Skip to content

Commit

Permalink
Add a few more compiler nodes
Browse files Browse the repository at this point in the history
  • Loading branch information
adambeynon committed Oct 22, 2013
1 parent 6b05c8d commit 5c6d5d4
Show file tree
Hide file tree
Showing 3 changed files with 64 additions and 52 deletions.
40 changes: 40 additions & 0 deletions lib/opal/nodes/literal.rb
Expand Up @@ -38,6 +38,19 @@ def compile
end
end

class XStringNode < LiteralNode
def needs_semicolon?
stmt? and !value.to_s.include?(';')
end

def compile
push value.to_s
push ';' if needs_semicolon?

wrap '(', ')' if recv?
end
end

class DynamicStringNode < Node
def compile
children.each_with_index do |part, idx|
Expand Down Expand Up @@ -80,6 +93,33 @@ def compile
end
end

class DynamicXStringNode < Node
def requires_semicolon(code)
stmt? and !code.include?(';')
end

def compile
needs_semicolon = false

children.each do |part|
if String === part
push part.to_s
needs_semicolon = true if requires_semicolon(part.to_s)
elsif part.type == :evstr
push expr(part[1])
elsif part.type == :str
push part.last.to_s
needs_semicolon = true if requires_semicolon(part.last.to_s)
else
raise "Bad dxstr part"
end
end

push ';' if needs_semicolon
wrap '(', ')' if recv?
end
end

class DynamicRegexpNode < Node
def compile
children.each_with_index do |part, idx|
Expand Down
21 changes: 21 additions & 0 deletions lib/opal/nodes/logic.rb
Expand Up @@ -41,6 +41,27 @@ def compile_iter
end
end

class RedoNode < Node
def compile
if in_while?
compile_while
elsif scope.iter?
compile_iter
else
push "REDO()"
end
end

def compile_while
while_loop[:use_redo] = true
push "#{while_loop[:redo_var]} = true"
end

def compile_iter
push "return #{scope.identity}.apply(null, $slice.call(arguments))"
end
end

class NotNode < Node
children :value

Expand Down
55 changes: 3 additions & 52 deletions lib/opal/parser.rb
Expand Up @@ -47,8 +47,10 @@ def self.add_handler(klass, *types)
add_handler StringNode, :str
add_handler SymbolNode, :sym
add_handler RegexpNode, :regexp
add_handler XStringNode, :xstr
add_handler DynamicStringNode, :dstr
add_handler DynamicSymbolNode, :dsym
add_handler DynamicXStringNode, :dxstr
add_handler DynamicRegexpNode, :dregx
add_handler ExclusiveRangeNode, :dot2
add_handler InclusiveRangeNode, :dot3
Expand Down Expand Up @@ -77,6 +79,7 @@ def self.add_handler(klass, *types)
# control flow
add_handler NextNode, :next
add_handler BreakNode, :break
add_handler RedoNode, :redo
add_handler NotNode, :not
add_handler SplatNode, :splat
add_handler OrNode, :or
Expand Down Expand Up @@ -1402,44 +1405,6 @@ def process_return(sexp, level)
end
end

# s(:xstr, content)
def process_xstr(sexp, level)
code = sexp.first.to_s
code += ";" if level == :stmt and !code.include?(';')

result = f(code, sexp)

level == :recv ? [f("(", sexp), result, f(")", sexp)] : result
end

# s(:dxstr, parts...)
def process_dxstr(sexp, level)
result = []
needs_sc = false

sexp.each do |p|
if String === p
result << f(p.to_s, sexp)
needs_sc = true if level == :stmt and !p.to_s.include?(';')
elsif p.first == :evstr
result.push(*process(p.last, :stmt))
elsif p.first == :str
result << f(p.last.to_s, p)
needs_sc = true if level == :stmt and !p.last.to_s.include?(';')
else
raise "Bad dxstr part"
end
end

result << f(";", sexp) if needs_sc

if level == :recv
[f("(", sexp), result, f(")", sexp)]
else
result
end
end

# s(:if, test, truthy, falsy)
def process_if(sexp, level)
test, truthy, falsy = sexp
Expand Down Expand Up @@ -1957,19 +1922,5 @@ def process_paren(sexp, level)
result
end
end

# s(:redo) # => $redo_var = true
# Only currently supported inside while loops. Simply sets the redo variable
# for the loop to true.
def process_redo(exp, level)
if in_while?
@while_loop[:use_redo] = true
f("#{@while_loop[:redo_var]} = true", exp)
elsif @scope.iter?
f("return #{@scope.identity}.apply(null, $slice.call(arguments))")
else
f("REDO()", exp)
end
end
end
end

0 comments on commit 5c6d5d4

Please sign in to comment.