module Johnson module SpiderMonkey class MutableTreeVisitor include Johnson::Nodes def visit_For(ro_node) For.new( ro_node.line, ro_node.index, ro_node.pn_left.pn_kid1 && ro_node.pn_left.pn_kid1.accept(self), ro_node.pn_left.pn_kid2 && ro_node.pn_left.pn_kid2.accept(self), ro_node.pn_left.pn_kid3 && ro_node.pn_left.pn_kid3.accept(self), ro_node.pn_right.accept(self) ) end def visit_Name(ro_node) Name.new(ro_node.line, ro_node.index, ro_node.name) end def visit_Number(ro_node) Number.new(ro_node.line, ro_node.index, ro_node.pn_dval) end def visit_String(ro_node) Nodes::String.new( ro_node.line, ro_node.index, ro_node.name ) end def visit_Regexp(ro_node) Regexp.new( ro_node.line, ro_node.index, ro_node.regexp ) end def visit_Function(ro_node) Function.new( ro_node.line, ro_node.index, ro_node.function_name, ro_node.function_args, ro_node.function_body.accept(self) ) end def visit_LexicalScope(ro_node) LexicalScope.new( ro_node.line, ro_node.index, Name.new(ro_node.line, ro_node.index, "unnamed"), # lexical scope nodes don't hold a name ro_node.pn_expr.accept(self)) end %w{ Label AssignExpr DotAccessor }.each do |type| define_method(:"visit_#{type}") do |ro_node| Nodes.const_get(type).new( ro_node.line, ro_node.index, Name.new(ro_node.line, ro_node.index, ro_node.name), ro_node.pn_expr.accept(self) ) end end %w{ SourceElements VarStatement LetStatement Comma ObjectLiteral ArrayLiteral New FunctionCall Import Export }.each do |list_op| define_method(:"visit_#{list_op}") do |ro_node| Nodes.const_get(list_op).new( ro_node.line, ro_node.index, ro_node.children.map { |c| c.accept(self) }.compact) end end { 'Null' => nil, 'True' => true, 'False' => false, 'This' => 'this', 'Continue' => 'continue', 'Break' => 'break', }.each do |type,val| define_method(:"visit_#{type}") do |ro_node| Nodes.const_get(type).new( ro_node.line, ro_node.index, val ) end end def visit_Try(ro_node) Try.new( ro_node.line, ro_node.index, ro_node.pn_kid1 && ro_node.pn_kid1.accept(self), if ro_node.pn_kid2 case ro_node.pn_kid2.pn_type when :tok_reserved ro_node.pn_kid2.children.map { |x| x.pn_expr.accept(self) } else raise "HALP some other catch #{ro_node.line}, #{ro_node.index}" end else nil end, ro_node.pn_kid3 && ro_node.pn_kid3.accept(self) ) end %w{ Ternary If Catch }.each do |node| define_method(:"visit_#{node}") do |ro_node| Nodes.const_get(node).new( ro_node.line, ro_node.index, ro_node.pn_kid1 && ro_node.pn_kid1.accept(self), ro_node.pn_kid2 && ro_node.pn_kid2.accept(self), ro_node.pn_kid3 && ro_node.pn_kid3.accept(self) ) end end %w{ BitwiseNot Delete Not Parenthesis PostfixDecrement PostfixIncrement PrefixDecrement PrefixIncrement Return Throw Typeof UnaryNegative UnaryPositive Void }.each do |node| define_method(:"visit_#{node}") do |ro_node| Nodes.const_get(node).new(ro_node.line, ro_node.index, ro_node.pn_kid && ro_node.pn_kid.accept(self)) end end %w{ And BracketAccess DoWhile Case Default While With Equal Switch In InstanceOf GetterProperty ForIn GreaterThan LessThan GreaterThanOrEqual LessThanOrEqual NotEqual OpAdd OpAddEqual OpBitAnd OpBitAndEqual OpBitOr OpBitOrEqual OpBitXor OpBitXorEqual OpDivide OpDivideEqual OpEqual OpLShift OpLShiftEqual OpMod OpModEqual OpMultiply OpMultiplyEqual OpRShift OpRShiftEqual OpSubtract OpSubtractEqual OpURShift OpURShiftEqual Or Property SetterProperty StrictEqual StrictNotEqual }.each do |bin_op| define_method(:"visit_#{bin_op}") do |ro_node| if ro_node.children.length > 1 kids = ro_node.children.reverse tree = self.class.const_get(bin_op).new( ro_node.line, ro_node.index, kids[1].accept(self), kids[0].accept(self) ) 2.times { kids.shift } kids.each do |kid| tree = self.class.const_get(bin_op).new( ro_node.line, ro_node.index, kid.accept(self), tree ) end tree else self.class.const_get(bin_op).new( ro_node.line, ro_node.index, ro_node.pn_left && ro_node.pn_left.accept(self), ro_node.pn_right && ro_node.pn_right.accept(self) ) end end end def accept(target) target.accept(self) end end end end