lib/opal/nodes/definitions.rb
require 'opal/nodes/base' module Opal module Nodes class SvalueNode < Base handle :svalue children :value def compile push process(value, @level) end end class UndefNode < Base handle :undef def compile children.each do |child| value = child[1] statements = [] if child[0] == :js_return value = value[1] statements << expr(s(:js_return)) end statements << "Opal.udef(self, '$#{value.to_s}');" if children.length > 1 && child != children.first line *statements else push *statements end end end end class AliasNode < Base handle :alias children :new_name, :old_name def new_mid mid_to_jsid new_name[1].to_s end def old_mid mid_to_jsid old_name[1].to_s end def compile if scope.class? or scope.module? scope.methods << "$#{new_name[1]}" end push "Opal.alias(self, '#{new_name[1]}', '#{old_name[1]}')" end end class BeginNode < Base handle :begin children :body def compile if !stmt? and body.type == :block push stmt(compiler.returns(body)) wrap '(function() {', '})()' else push process(body, @level) end end end class ParenNode < Base handle :paren children :body def compile if body.type == :block body.children.each_with_index do |child, idx| push ', ' unless idx == 0 push expr(child) end wrap '(', ')' else push process(body, @level) wrap '(', ')' unless stmt? end end end class BlockNode < Base handle :block def compile return push "nil" if children.empty? children.each_with_index do |child, idx| push stmt_join unless idx == 0 if yasgn = find_inline_yield(child) push compiler.process(yasgn, @level) push ";" end push compiler.process(child, @level) push ";" if child_is_expr?(child) end end def stmt_join scope.class_scope? ? "\n\n#{current_indent}" : "\n#{current_indent}" end def child_is_expr?(child) raw_expression?(child) and [:stmt, :stmt_closure].include?(@level) end def raw_expression?(child) ![:xstr, :dxstr].include?(child.type) end # When a block sexp gets generated, any inline yields (i.e. yield # statements that are not direct members of the block) need to be # generated as a top level member. This is because if a yield # is returned by a break statement, then the method must return. # # As inline expressions in javascript cannot return, the block # must be rewritten. # # For example, a yield inside an array: # # [1, 2, 3, yield(4)] # # Must be rewitten into: # # tmp = yield 4 # [1, 2, 3, tmp] # # This rewriting happens on sexps directly. # # @param [Sexp] stmt sexps to (maybe) rewrite # @return [Sexp] def find_inline_yield(stmt) found = nil case stmt.first when :js_return if found = find_inline_yield(stmt[1]) found = found[2] end when :array stmt[1..-1].each_with_index do |el, idx| if el.first == :yield found = el stmt[idx+1] = s(:js_tmp, '$yielded') end end when :call arglist = stmt[3] arglist[1..-1].each_with_index do |el, idx| if el.first == :yield found = el arglist[idx+1] = s(:js_tmp, '$yielded') end end end if found scope.add_temp '$yielded' unless scope.has_temp? '$yielded' s(:yasgn, '$yielded', found) end end end end end