Skip to content

Commit

Permalink
Add IfNode for compiled nodes
Browse files Browse the repository at this point in the history
  • Loading branch information
adambeynon committed Oct 22, 2013
1 parent 05c1a26 commit 87b0524
Show file tree
Hide file tree
Showing 4 changed files with 106 additions and 46 deletions.
1 change: 1 addition & 0 deletions lib/opal/nodes.rb
Expand Up @@ -5,6 +5,7 @@
require 'opal/nodes/call'
require 'opal/nodes/call_special'
require 'opal/nodes/class'
require 'opal/nodes/if'
require 'opal/nodes/logic'
require 'opal/nodes/definitions'
require 'opal/nodes/yield'
Expand Down
44 changes: 44 additions & 0 deletions lib/opal/nodes/helpers.rb
Expand Up @@ -30,6 +30,50 @@ def line(*strs)
def empty_line
push "\n"
end

def js_truthy(sexp)
if js_truthy_optimize(sexp)
return
end

with_temp do |tmp|
push "(#{tmp} = ", expr(sexp), ") !== false && #{tmp} !== nil"
end
end

def js_falsy(sexp)
if sexp.type == :call
mid = sexp[2]
if mid == :block_given?
push(*@parser.handle_block_given(sexp, true))
return
end
end

with_temp do |tmp|
push "(#{tmp} = ", expr(sexp), ") === false || #{tmp} === nil"
end
end

def js_truthy_optimize(sexp)
if sexp.type == :call
mid = sexp[2]

if mid == :block_given?
push expr(sexp)
true
elsif Parser::COMPARE.include? mid.to_s
push expr(sexp)
true
elsif mid == :"=="
push expr(sexp)
true
end
elsif [:lvar, :self].include? sexp.type
push expr(sexp.dup), " !== false && ", expr(sexp.dup), " !== nil"
true
end
end
end
end
end
58 changes: 58 additions & 0 deletions lib/opal/nodes/if.rb
@@ -0,0 +1,58 @@
require 'opal/nodes/base'

module Opal
class Parser
class IfNode < Node
children :test, :true_body, :false_body

def compile
truthy, falsy = self.truthy, self.falsy

push "if ("

# optimize unless (we don't want a else() unless we need to)
if falsy and !truthy
truthy = falsy
falsy = nil
js_falsy test
else
js_truthy test
end

push ") {"

# skip if-body if no truthy sexp
indent { line stmt(truthy) } if truthy

if falsy
if falsy.type == :if
line "} else ", stmt(falsy)
else
indent do
line "} else {"
line stmt(falsy)
end

line "}"
end
else
push "}"
end

wrap "(function() {", "; return nil; })()" if needs_wrapper?
end

def truthy
needs_wrapper? ? @parser.returns(true_body || s(:nil)) : true_body
end

def falsy
needs_wrapper? ? @parser.returns(false_body || s(:nil)) : false_body
end

def needs_wrapper?
expr? or recv?
end
end
end
end
49 changes: 3 additions & 46 deletions lib/opal/parser.rb
Expand Up @@ -115,6 +115,9 @@ def add_handler(klass, *types)
add_handler WhileNode, :while
add_handler UntilNode, :until

# if
add_handler IfNode, :if

# rescue/ensure
add_handler EnsureNode, :ensure
add_handler RescueNode, :rescue
Expand Down Expand Up @@ -1035,52 +1038,6 @@ def process_masgn(sexp, level)
code
end

# s(:if, test, truthy, falsy)
def process_if(sexp, level)
test, truthy, falsy = sexp
returnable = (level == :expr or level == :recv)

if returnable
truthy = returns(truthy || s(:nil))
falsy = returns(falsy || s(:nil))
end

# optimize unless (we don't want else unless we need to)
if falsy and !truthy
truthy = falsy
falsy = nil
check = js_falsy test
else
check = js_truthy test
end

result = [f("if (", sexp), check, f(") {\n", sexp)]

indent { result.push(f(@indent, sexp), process(truthy, :stmt)) } if truthy

outdent = @indent

if falsy
if falsy[0] == :if
result.push(f("\n#{outdent}} else "), process(falsy, :stmt))
else
indent {
result.push(f("\n#{outdent}} else {\n#@indent", sexp), process(falsy, :stmt))
}
result << f("\n#@indent}", sexp)
end
else
result << f("\n#@indent}", sexp)
end

if returnable
result.unshift f("(function() { ", sexp)
result.push f("; return nil; }).call(self)", sexp)
end

result
end

def js_truthy_optimize(sexp)
if sexp.first == :call
mid = sexp[2]
Expand Down

0 comments on commit 87b0524

Please sign in to comment.