328 lines
7.9 KiB
Ruby
328 lines
7.9 KiB
Ruby
module RKelly
|
|
module Visitors
|
|
class ECMAVisitor < Visitor
|
|
def initialize
|
|
@indent = 0
|
|
end
|
|
|
|
def visit_ParentheticalNode(o)
|
|
"(#{o.value.accept(self)})"
|
|
end
|
|
|
|
def visit_SourceElementsNode(o)
|
|
o.value.map { |x| "#{indent}#{x.accept(self)}" }.join("\n")
|
|
end
|
|
|
|
def visit_VarStatementNode(o)
|
|
"var #{o.value.map { |x| x.accept(self) }.join(', ')};"
|
|
end
|
|
|
|
def visit_ConstStatementNode(o)
|
|
"const #{o.value.map { |x| x.accept(self) }.join(', ')};"
|
|
end
|
|
|
|
def visit_VarDeclNode(o)
|
|
"#{o.name}#{o.value ? o.value.accept(self) : nil}"
|
|
end
|
|
|
|
def visit_AssignExprNode(o)
|
|
" = #{o.value.accept(self)}"
|
|
end
|
|
|
|
def visit_NumberNode(o)
|
|
o.value.to_s
|
|
end
|
|
|
|
def visit_ForNode(o)
|
|
init = o.init ? o.init.accept(self) : ';'
|
|
test = o.test ? o.test.accept(self) : ''
|
|
counter = o.counter ? o.counter.accept(self) : ''
|
|
# VarStatementNodes will have a ; appended automatically, but other
|
|
# expressions won't, so make sure it's there
|
|
if init[-1,1] != ';'
|
|
init += ';'
|
|
end
|
|
"for(#{init} #{test}; #{counter}) #{o.value.accept(self)}"
|
|
end
|
|
|
|
def visit_LessNode(o)
|
|
"#{o.left.accept(self)} < #{o.value.accept(self)}"
|
|
end
|
|
|
|
def visit_ResolveNode(o)
|
|
o.value
|
|
end
|
|
|
|
def visit_PostfixNode(o)
|
|
"#{o.operand.accept(self)}#{o.value}"
|
|
end
|
|
|
|
def visit_PrefixNode(o)
|
|
"#{o.value}#{o.operand.accept(self)}"
|
|
end
|
|
|
|
def visit_BlockNode(o)
|
|
@indent += 1
|
|
"{\n#{o.value.accept(self)}\n#{@indent -=1; indent}}"
|
|
end
|
|
|
|
def visit_ExpressionStatementNode(o)
|
|
"#{o.value.accept(self)};"
|
|
end
|
|
|
|
def visit_OpEqualNode(o)
|
|
"#{o.left.accept(self)} = #{o.value.accept(self)}"
|
|
end
|
|
|
|
def visit_FunctionCallNode(o)
|
|
"#{o.value.accept(self)}(#{o.arguments.accept(self)})"
|
|
end
|
|
|
|
def visit_ArgumentsNode(o)
|
|
o.value.map { |x| x.accept(self) }.join(', ')
|
|
end
|
|
|
|
def visit_StringNode(o)
|
|
o.value
|
|
end
|
|
|
|
def visit_NullNode(o)
|
|
"null"
|
|
end
|
|
|
|
def visit_FunctionDeclNode(o)
|
|
"#{indent}function #{o.value}(" +
|
|
"#{o.arguments.map { |x| x.accept(self) }.join(', ')})" +
|
|
"#{o.function_body.accept(self)}"
|
|
end
|
|
|
|
def visit_ParameterNode(o)
|
|
o.value
|
|
end
|
|
|
|
def visit_FunctionBodyNode(o)
|
|
@indent += 1
|
|
"{\n#{o.value.accept(self)}\n#{@indent -=1; indent}}"
|
|
end
|
|
|
|
def visit_BreakNode(o)
|
|
"break" + (o.value ? " #{o.value}" : '') + ';'
|
|
end
|
|
|
|
def visit_ContinueNode(o)
|
|
"continue" + (o.value ? " #{o.value}" : '') + ';'
|
|
end
|
|
|
|
def visit_TrueNode(o)
|
|
"true"
|
|
end
|
|
|
|
def visit_FalseNode(o)
|
|
"false"
|
|
end
|
|
|
|
def visit_EmptyStatementNode(o)
|
|
';'
|
|
end
|
|
|
|
def visit_RegexpNode(o)
|
|
o.value
|
|
end
|
|
|
|
def visit_DotAccessorNode(o)
|
|
"#{o.value.accept(self)}.#{o.accessor}"
|
|
end
|
|
|
|
def visit_ThisNode(o)
|
|
"this"
|
|
end
|
|
|
|
def visit_BitwiseNotNode(o)
|
|
"~#{o.value.accept(self)}"
|
|
end
|
|
|
|
def visit_DeleteNode(o)
|
|
"delete #{o.value.accept(self)}"
|
|
end
|
|
|
|
def visit_ArrayNode(o)
|
|
"[#{o.value.map { |x| x ? x.accept(self) : '' }.join(', ')}]"
|
|
end
|
|
|
|
def visit_ElementNode(o)
|
|
o.value.accept(self)
|
|
end
|
|
|
|
def visit_LogicalNotNode(o)
|
|
"!#{o.value.accept(self)}"
|
|
end
|
|
|
|
def visit_UnaryMinusNode(o)
|
|
"-#{o.value.accept(self)}"
|
|
end
|
|
|
|
def visit_UnaryPlusNode(o)
|
|
"+#{o.value.accept(self)}"
|
|
end
|
|
|
|
def visit_ReturnNode(o)
|
|
"return" + (o.value ? " #{o.value.accept(self)}" : '') + ';'
|
|
end
|
|
|
|
def visit_ThrowNode(o)
|
|
"throw #{o.value.accept(self)};"
|
|
end
|
|
|
|
def visit_TypeOfNode(o)
|
|
"typeof #{o.value.accept(self)}"
|
|
end
|
|
|
|
def visit_VoidNode(o)
|
|
"void(#{o.value.accept(self)})"
|
|
end
|
|
|
|
[
|
|
[:Add, '+'],
|
|
[:BitAnd, '&'],
|
|
[:BitOr, '|'],
|
|
[:BitXOr, '^'],
|
|
[:Divide, '/'],
|
|
[:Equal, '=='],
|
|
[:Greater, '>'],
|
|
[:Greater, '>'],
|
|
[:GreaterOrEqual, '>='],
|
|
[:GreaterOrEqual, '>='],
|
|
[:In, 'in'],
|
|
[:InstanceOf, 'instanceof'],
|
|
[:LeftShift, '<<'],
|
|
[:LessOrEqual, '<='],
|
|
[:LogicalAnd, '&&'],
|
|
[:LogicalOr, '||'],
|
|
[:Modulus, '%'],
|
|
[:Multiply, '*'],
|
|
[:NotEqual, '!='],
|
|
[:NotStrictEqual, '!=='],
|
|
[:OpAndEqual, '&='],
|
|
[:OpDivideEqual, '/='],
|
|
[:OpLShiftEqual, '<<='],
|
|
[:OpMinusEqual, '-='],
|
|
[:OpModEqual, '%='],
|
|
[:OpMultiplyEqual, '*='],
|
|
[:OpOrEqual, '|='],
|
|
[:OpPlusEqual, '+='],
|
|
[:OpRShiftEqual, '>>='],
|
|
[:OpURShiftEqual, '>>>='],
|
|
[:OpXOrEqual, '^='],
|
|
[:RightShift, '>>'],
|
|
[:StrictEqual, '==='],
|
|
[:Subtract, '-'],
|
|
[:UnsignedRightShift, '>>>'],
|
|
].each do |name,op|
|
|
define_method(:"visit_#{name}Node") do |o|
|
|
"#{o.left.accept(self)} #{op} #{o.value.accept(self)}"
|
|
end
|
|
end
|
|
|
|
def visit_WhileNode(o)
|
|
"while(#{o.left.accept(self)}) #{o.value.accept(self)}"
|
|
end
|
|
|
|
def visit_SwitchNode(o)
|
|
"switch(#{o.left.accept(self)}) #{o.value.accept(self)}"
|
|
end
|
|
|
|
def visit_CaseBlockNode(o)
|
|
@indent += 1
|
|
"{\n" + (o.value ? o.value.map { |x| x.accept(self) }.join('') : '') +
|
|
"#{@indent -=1; indent}}"
|
|
end
|
|
|
|
def visit_CaseClauseNode(o)
|
|
if o.left
|
|
case_code = "#{indent}case #{o.left.accept(self)}:\n"
|
|
else
|
|
case_code = "#{indent}default:\n"
|
|
end
|
|
@indent += 1
|
|
case_code += "#{o.value.accept(self)}\n"
|
|
@indent -= 1
|
|
case_code
|
|
end
|
|
|
|
def visit_DoWhileNode(o)
|
|
"do #{o.left.accept(self)} while(#{o.value.accept(self)});"
|
|
end
|
|
|
|
def visit_WithNode(o)
|
|
"with(#{o.left.accept(self)}) #{o.value.accept(self)}"
|
|
end
|
|
|
|
def visit_LabelNode(o)
|
|
"#{o.name}: #{o.value.accept(self)}"
|
|
end
|
|
|
|
def visit_ObjectLiteralNode(o)
|
|
@indent += 1
|
|
lit = "{" + (o.value.length > 0 ? "\n" : ' ') +
|
|
o.value.map { |x| "#{indent}#{x.accept(self)}" }.join(",\n") +
|
|
(o.value.length > 0 ? "\n" : '') + '}'
|
|
@indent -= 1
|
|
lit
|
|
end
|
|
|
|
def visit_PropertyNode(o)
|
|
"#{o.name}: #{o.value.accept(self)}"
|
|
end
|
|
|
|
def visit_GetterPropertyNode(o)
|
|
"get #{o.name}#{o.value.accept(self)}"
|
|
end
|
|
|
|
def visit_SetterPropertyNode(o)
|
|
"set #{o.name}#{o.value.accept(self)}"
|
|
end
|
|
|
|
def visit_FunctionExprNode(o)
|
|
"#{o.value}(#{o.arguments.map { |x| x.accept(self) }.join(', ')}) " +
|
|
"#{o.function_body.accept(self)}"
|
|
end
|
|
|
|
def visit_CommaNode(o)
|
|
"#{o.left.accept(self)}, #{o.value.accept(self)}"
|
|
end
|
|
|
|
def visit_IfNode(o)
|
|
"if(#{o.conditions.accept(self)}) #{o.value.accept(self)}" +
|
|
(o.else ? " else #{o.else.accept(self)}" : '')
|
|
end
|
|
|
|
def visit_ConditionalNode(o)
|
|
"#{o.conditions.accept(self)} ? #{o.value.accept(self)} : " +
|
|
"#{o.else.accept(self)}"
|
|
end
|
|
|
|
def visit_ForInNode(o)
|
|
"for(#{o.left.accept(self)} in #{o.right.accept(self)}) " +
|
|
"#{o.value.accept(self)}"
|
|
end
|
|
|
|
def visit_TryNode(o)
|
|
"try #{o.value.accept(self)}" +
|
|
(o.catch_block ? " catch(#{o.catch_var}) #{o.catch_block.accept(self)}" : '') +
|
|
(o.finally_block ? " finally #{o.finally_block.accept(self)}" : '')
|
|
end
|
|
|
|
def visit_BracketAccessorNode(o)
|
|
"#{o.value.accept(self)}[#{o.accessor.accept(self)}]"
|
|
end
|
|
|
|
def visit_NewExprNode(o)
|
|
"new #{o.value.accept(self)}(#{o.arguments.accept(self)})"
|
|
end
|
|
|
|
private
|
|
def indent; ' ' * @indent * 2; end
|
|
end
|
|
end
|
|
end
|