tenderlove-rkelly 0.0.0.20080909095845
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/CHANGELOG.txt +7 -0
- data/Manifest.txt +197 -0
- data/README.txt +49 -0
- data/Rakefile +85 -0
- data/lib/parser.y +870 -0
- data/lib/rkelly.rb +8 -0
- data/lib/rkelly/constants.rb +3 -0
- data/lib/rkelly/js.rb +14 -0
- data/lib/rkelly/js/array.rb +15 -0
- data/lib/rkelly/js/base.rb +91 -0
- data/lib/rkelly/js/boolean.rb +21 -0
- data/lib/rkelly/js/function.rb +39 -0
- data/lib/rkelly/js/function_prototype.rb +15 -0
- data/lib/rkelly/js/global_object.rb +52 -0
- data/lib/rkelly/js/math.rb +10 -0
- data/lib/rkelly/js/nan.rb +18 -0
- data/lib/rkelly/js/number.rb +22 -0
- data/lib/rkelly/js/object.rb +30 -0
- data/lib/rkelly/js/object_prototype.rb +14 -0
- data/lib/rkelly/js/property.rb +20 -0
- data/lib/rkelly/js/scope.rb +6 -0
- data/lib/rkelly/js/string.rb +21 -0
- data/lib/rkelly/lexeme.rb +18 -0
- data/lib/rkelly/nodes.rb +5 -0
- data/lib/rkelly/nodes/binary_node.rb +18 -0
- data/lib/rkelly/nodes/bracket_accessor_node.rb +11 -0
- data/lib/rkelly/nodes/case_clause_node.rb +11 -0
- data/lib/rkelly/nodes/comma_node.rb +11 -0
- data/lib/rkelly/nodes/conditional_node.rb +11 -0
- data/lib/rkelly/nodes/dot_accessor_node.rb +11 -0
- data/lib/rkelly/nodes/for_in_node.rb +12 -0
- data/lib/rkelly/nodes/for_node.rb +13 -0
- data/lib/rkelly/nodes/function_call_node.rb +16 -0
- data/lib/rkelly/nodes/function_decl_node.rb +6 -0
- data/lib/rkelly/nodes/function_expr_node.rb +12 -0
- data/lib/rkelly/nodes/if_node.rb +12 -0
- data/lib/rkelly/nodes/label_node.rb +11 -0
- data/lib/rkelly/nodes/new_expr_node.rb +11 -0
- data/lib/rkelly/nodes/node.rb +80 -0
- data/lib/rkelly/nodes/not_strict_equal_node.rb +6 -0
- data/lib/rkelly/nodes/op_equal_node.rb +16 -0
- data/lib/rkelly/nodes/postfix_node.rb +11 -0
- data/lib/rkelly/nodes/prefix_node.rb +6 -0
- data/lib/rkelly/nodes/property_node.rb +13 -0
- data/lib/rkelly/nodes/resolve_node.rb +19 -0
- data/lib/rkelly/nodes/strict_equal_node.rb +6 -0
- data/lib/rkelly/nodes/try_node.rb +13 -0
- data/lib/rkelly/nodes/var_decl_node.rb +15 -0
- data/lib/rkelly/parser.rb +98 -0
- data/lib/rkelly/runtime.rb +36 -0
- data/lib/rkelly/runtime/ruby_function.rb +13 -0
- data/lib/rkelly/runtime/scope_chain.rb +57 -0
- data/lib/rkelly/token.rb +15 -0
- data/lib/rkelly/tokenizer.rb +122 -0
- data/lib/rkelly/visitable.rb +16 -0
- data/lib/rkelly/visitors.rb +4 -0
- data/lib/rkelly/visitors/dot_visitor.rb +228 -0
- data/lib/rkelly/visitors/ecma_visitor.rb +314 -0
- data/lib/rkelly/visitors/enumerable_visitor.rb +18 -0
- data/lib/rkelly/visitors/evaluation_visitor.rb +419 -0
- data/lib/rkelly/visitors/function_visitor.rb +46 -0
- data/lib/rkelly/visitors/pointcut_visitor.rb +18 -0
- data/lib/rkelly/visitors/sexp_visitor.rb +374 -0
- data/lib/rkelly/visitors/visitor.rb +136 -0
- data/test/ecma_script_test_case.rb +21 -0
- data/test/execute_test_case.rb +16 -0
- data/test/execution_contexts/test_10_1_3-1.rb +32 -0
- data/test/expressions/test_11_3_1.rb +64 -0
- data/test/expressions/test_11_3_2.rb +64 -0
- data/test/expressions/test_11_4_2.rb +13 -0
- data/test/expressions/test_11_4_3.rb +52 -0
- data/test/expressions/test_11_4_4.rb +68 -0
- data/test/expressions/test_11_4_5.rb +69 -0
- data/test/expressions/test_11_4_6.rb +88 -0
- data/test/expressions/test_11_4_8.rb +28 -0
- data/test/expressions/test_11_4_9.rb +103 -0
- data/test/expressions/test_11_5_1.rb +51 -0
- data/test/expressions/test_11_5_2.rb +80 -0
- data/test/expressions/test_11_5_3.rb +88 -0
- data/test/expressions/test_11_6_1-1.rb +19 -0
- data/test/expressions/test_11_9_1.rb +19 -0
- data/test/function/test_15_3_1_1-1.rb +34 -0
- data/test/global_object/test_15_1_1_1.rb +29 -0
- data/test/global_object/test_15_1_1_2.rb +17 -0
- data/test/global_object/test_15_1_1_3.rb +9 -0
- data/test/helper.rb +5 -0
- data/test/node_test_case.rb +11 -0
- data/test/object/test_15_2_1_1.rb +257 -0
- data/test/object/test_15_2_1_2.rb +21 -0
- data/test/object/test_15_2_2_1.rb +52 -0
- data/test/statements/test_12_5-1.rb +27 -0
- data/test/test_add_node.rb +8 -0
- data/test/test_arguments_node.rb +8 -0
- data/test/test_array_node.rb +9 -0
- data/test/test_assign_expr_node.rb +8 -0
- data/test/test_automatic_semicolon_insertion.rb +137 -0
- data/test/test_bit_and_node.rb +8 -0
- data/test/test_bit_or_node.rb +8 -0
- data/test/test_bit_x_or_node.rb +8 -0
- data/test/test_bitwise_not_node.rb +8 -0
- data/test/test_block_node.rb +14 -0
- data/test/test_bracket_accessor_node.rb +16 -0
- data/test/test_break_node.rb +11 -0
- data/test/test_case_block_node.rb +11 -0
- data/test/test_case_clause_node.rb +15 -0
- data/test/test_comma_node.rb +13 -0
- data/test/test_comments.rb +44 -0
- data/test/test_conditional_node.rb +17 -0
- data/test/test_const_statement_node.rb +14 -0
- data/test/test_continue_node.rb +11 -0
- data/test/test_delete_node.rb +8 -0
- data/test/test_divide_node.rb +8 -0
- data/test/test_do_while_node.rb +13 -0
- data/test/test_dot_accessor_node.rb +9 -0
- data/test/test_ecma_visitor.rb +192 -0
- data/test/test_element_node.rb +8 -0
- data/test/test_empty_statement_node.rb +8 -0
- data/test/test_equal_node.rb +8 -0
- data/test/test_evaluation_visitor.rb +66 -0
- data/test/test_expression_statement_node.rb +10 -0
- data/test/test_false_node.rb +8 -0
- data/test/test_for_in_node.rb +17 -0
- data/test/test_for_node.rb +24 -0
- data/test/test_function_body_node.rb +8 -0
- data/test/test_function_call_node.rb +10 -0
- data/test/test_function_decl_node.rb +16 -0
- data/test/test_function_expr_node.rb +16 -0
- data/test/test_function_visitor.rb +26 -0
- data/test/test_getter_property_node.rb +10 -0
- data/test/test_global_object.rb +49 -0
- data/test/test_greater_node.rb +8 -0
- data/test/test_greater_or_equal_node.rb +8 -0
- data/test/test_if_node.rb +17 -0
- data/test/test_in_node.rb +8 -0
- data/test/test_instance_of_node.rb +8 -0
- data/test/test_label_node.rb +13 -0
- data/test/test_left_shift_node.rb +8 -0
- data/test/test_less_node.rb +8 -0
- data/test/test_less_or_equal_node.rb +8 -0
- data/test/test_line_number.rb +23 -0
- data/test/test_logical_and_node.rb +8 -0
- data/test/test_logical_not_node.rb +8 -0
- data/test/test_logical_or_node.rb +8 -0
- data/test/test_modulus_node.rb +8 -0
- data/test/test_multiply_node.rb +8 -0
- data/test/test_new_expr_node.rb +9 -0
- data/test/test_not_equal_node.rb +8 -0
- data/test/test_not_strict_equal_node.rb +8 -0
- data/test/test_null_node.rb +8 -0
- data/test/test_number_node.rb +8 -0
- data/test/test_object_literal_node.rb +9 -0
- data/test/test_op_and_equal_node.rb +10 -0
- data/test/test_op_divide_equal_node.rb +10 -0
- data/test/test_op_equal_node.rb +10 -0
- data/test/test_op_l_shift_equal_node.rb +10 -0
- data/test/test_op_minus_equal_node.rb +10 -0
- data/test/test_op_mod_equal_node.rb +10 -0
- data/test/test_op_multiply_equal_node.rb +10 -0
- data/test/test_op_or_equal_node.rb +10 -0
- data/test/test_op_plus_equal_node.rb +10 -0
- data/test/test_op_r_shift_equal_node.rb +10 -0
- data/test/test_op_u_r_shift_equal_node.rb +10 -0
- data/test/test_op_x_or_equal_node.rb +10 -0
- data/test/test_parameter_node.rb +8 -0
- data/test/test_parser.rb +1355 -0
- data/test/test_pointcut_visitor.rb +34 -0
- data/test/test_postfix_node.rb +8 -0
- data/test/test_prefix_node.rb +8 -0
- data/test/test_property_node.rb +8 -0
- data/test/test_regexp_node.rb +8 -0
- data/test/test_resolve_node.rb +22 -0
- data/test/test_return_node.rb +11 -0
- data/test/test_right_shift_node.rb +8 -0
- data/test/test_runtime.rb +12 -0
- data/test/test_scope_chain.rb +50 -0
- data/test/test_setter_property_node.rb +10 -0
- data/test/test_source_elements.rb +9 -0
- data/test/test_strict_equal_node.rb +8 -0
- data/test/test_string_node.rb +8 -0
- data/test/test_subtract_node.rb +8 -0
- data/test/test_switch_node.rb +12 -0
- data/test/test_this_node.rb +8 -0
- data/test/test_throw_node.rb +7 -0
- data/test/test_tokenizer.rb +143 -0
- data/test/test_true_node.rb +8 -0
- data/test/test_try_node.rb +59 -0
- data/test/test_type_of_node.rb +8 -0
- data/test/test_unary_minus_node.rb +8 -0
- data/test/test_unary_plus_node.rb +8 -0
- data/test/test_unsigned_right_shift_node.rb +8 -0
- data/test/test_var_decl_node.rb +21 -0
- data/test/test_var_statement_node.rb +14 -0
- data/test/test_void_node.rb +8 -0
- data/test/test_while_node.rb +15 -0
- data/test/test_with_node.rb +8 -0
- metadata +385 -0
@@ -0,0 +1,314 @@
|
|
1
|
+
module RKelly
|
2
|
+
module Visitors
|
3
|
+
class ECMAVisitor < Visitor
|
4
|
+
def initialize
|
5
|
+
@indent = 0
|
6
|
+
end
|
7
|
+
|
8
|
+
def visit_SourceElementsNode(o)
|
9
|
+
o.value.map { |x| "#{indent}#{x.accept(self)}" }.join("\n")
|
10
|
+
end
|
11
|
+
|
12
|
+
def visit_VarStatementNode(o)
|
13
|
+
"var #{o.value.map { |x| x.accept(self) }.join(', ')};"
|
14
|
+
end
|
15
|
+
|
16
|
+
def visit_ConstStatementNode(o)
|
17
|
+
"const #{o.value.map { |x| x.accept(self) }.join(', ')};"
|
18
|
+
end
|
19
|
+
|
20
|
+
def visit_VarDeclNode(o)
|
21
|
+
"#{o.name}#{o.value ? o.value.accept(self) : nil}"
|
22
|
+
end
|
23
|
+
|
24
|
+
def visit_AssignExprNode(o)
|
25
|
+
" = #{o.value.accept(self)}"
|
26
|
+
end
|
27
|
+
|
28
|
+
def visit_NumberNode(o)
|
29
|
+
o.value.to_s
|
30
|
+
end
|
31
|
+
|
32
|
+
def visit_ForNode(o)
|
33
|
+
init = o.init ? o.init.accept(self) : ';'
|
34
|
+
test = o.test ? o.test.accept(self) : ''
|
35
|
+
counter = o.counter ? o.counter.accept(self) : ''
|
36
|
+
"for(#{init} #{test}; #{counter}) #{o.value.accept(self)}"
|
37
|
+
end
|
38
|
+
|
39
|
+
def visit_LessNode(o)
|
40
|
+
"#{o.left.accept(self)} < #{o.value.accept(self)}"
|
41
|
+
end
|
42
|
+
|
43
|
+
def visit_ResolveNode(o)
|
44
|
+
o.value
|
45
|
+
end
|
46
|
+
|
47
|
+
def visit_PostfixNode(o)
|
48
|
+
"#{o.operand.accept(self)}#{o.value}"
|
49
|
+
end
|
50
|
+
|
51
|
+
def visit_PrefixNode(o)
|
52
|
+
"#{o.value}#{o.operand.accept(self)}"
|
53
|
+
end
|
54
|
+
|
55
|
+
def visit_BlockNode(o)
|
56
|
+
@indent += 1
|
57
|
+
"{\n#{o.value.accept(self)}\n#{@indent -=1; indent}}"
|
58
|
+
end
|
59
|
+
|
60
|
+
def visit_ExpressionStatementNode(o)
|
61
|
+
"#{o.value.accept(self)};"
|
62
|
+
end
|
63
|
+
|
64
|
+
def visit_OpEqualNode(o)
|
65
|
+
"#{o.left.accept(self)} = #{o.value.accept(self)}"
|
66
|
+
end
|
67
|
+
|
68
|
+
def visit_FunctionCallNode(o)
|
69
|
+
"#{o.value.accept(self)}(#{o.arguments.accept(self)})"
|
70
|
+
end
|
71
|
+
|
72
|
+
def visit_ArgumentsNode(o)
|
73
|
+
o.value.map { |x| x.accept(self) }.join(', ')
|
74
|
+
end
|
75
|
+
|
76
|
+
def visit_StringNode(o)
|
77
|
+
o.value
|
78
|
+
end
|
79
|
+
|
80
|
+
def visit_NullNode(o)
|
81
|
+
"null"
|
82
|
+
end
|
83
|
+
|
84
|
+
def visit_FunctionDeclNode(o)
|
85
|
+
"#{indent}function #{o.value}(" +
|
86
|
+
"#{o.arguments.map { |x| x.accept(self) }.join(', ')})" +
|
87
|
+
"#{o.function_body.accept(self)}"
|
88
|
+
end
|
89
|
+
|
90
|
+
def visit_ParameterNode(o)
|
91
|
+
o.value
|
92
|
+
end
|
93
|
+
|
94
|
+
def visit_FunctionBodyNode(o)
|
95
|
+
@indent += 1
|
96
|
+
"{\n#{o.value.accept(self)}\n#{@indent -=1; indent}}"
|
97
|
+
end
|
98
|
+
|
99
|
+
def visit_BreakNode(o)
|
100
|
+
"break" + (o.value ? " #{o.value}" : '') + ';'
|
101
|
+
end
|
102
|
+
|
103
|
+
def visit_ContinueNode(o)
|
104
|
+
"continue" + (o.value ? " #{o.value}" : '') + ';'
|
105
|
+
end
|
106
|
+
|
107
|
+
def visit_TrueNode(o)
|
108
|
+
"true"
|
109
|
+
end
|
110
|
+
|
111
|
+
def visit_FalseNode(o)
|
112
|
+
"false"
|
113
|
+
end
|
114
|
+
|
115
|
+
def visit_EmptyStatementNode(o)
|
116
|
+
';'
|
117
|
+
end
|
118
|
+
|
119
|
+
def visit_RegexpNode(o)
|
120
|
+
o.value
|
121
|
+
end
|
122
|
+
|
123
|
+
def visit_DotAccessorNode(o)
|
124
|
+
"#{o.value.accept(self)}.#{o.accessor}"
|
125
|
+
end
|
126
|
+
|
127
|
+
def visit_ThisNode(o)
|
128
|
+
"this"
|
129
|
+
end
|
130
|
+
|
131
|
+
def visit_BitwiseNotNode(o)
|
132
|
+
"~#{o.value.accept(self)}"
|
133
|
+
end
|
134
|
+
|
135
|
+
def visit_DeleteNode(o)
|
136
|
+
"delete #{o.value.accept(self)}"
|
137
|
+
end
|
138
|
+
|
139
|
+
def visit_ArrayNode(o)
|
140
|
+
"[#{o.value.map { |x| x ? x.accept(self) : '' }.join(', ')}]"
|
141
|
+
end
|
142
|
+
|
143
|
+
def visit_ElementNode(o)
|
144
|
+
o.value.accept(self)
|
145
|
+
end
|
146
|
+
|
147
|
+
def visit_LogicalNotNode(o)
|
148
|
+
"!#{o.value.accept(self)}"
|
149
|
+
end
|
150
|
+
|
151
|
+
def visit_UnaryMinusNode(o)
|
152
|
+
"-#{o.value.accept(self)}"
|
153
|
+
end
|
154
|
+
|
155
|
+
def visit_UnaryPlusNode(o)
|
156
|
+
"+#{o.value.accept(self)}"
|
157
|
+
end
|
158
|
+
|
159
|
+
def visit_ReturnNode(o)
|
160
|
+
"return" + (o.value ? " #{o.value.accept(self)}" : '') + ';'
|
161
|
+
end
|
162
|
+
|
163
|
+
def visit_ThrowNode(o)
|
164
|
+
"throw #{o.value.accept(self)};"
|
165
|
+
end
|
166
|
+
|
167
|
+
def visit_TypeOfNode(o)
|
168
|
+
"typeof #{o.value.accept(self)}"
|
169
|
+
end
|
170
|
+
|
171
|
+
def visit_VoidNode(o)
|
172
|
+
"void(#{o.value.accept(self)})"
|
173
|
+
end
|
174
|
+
|
175
|
+
[
|
176
|
+
[:Add, '+'],
|
177
|
+
[:BitAnd, '&'],
|
178
|
+
[:BitOr, '|'],
|
179
|
+
[:BitXOr, '^'],
|
180
|
+
[:Divide, '/'],
|
181
|
+
[:Equal, '=='],
|
182
|
+
[:Greater, '>'],
|
183
|
+
[:Greater, '>'],
|
184
|
+
[:GreaterOrEqual, '>='],
|
185
|
+
[:GreaterOrEqual, '>='],
|
186
|
+
[:In, 'in'],
|
187
|
+
[:InstanceOf, 'instanceof'],
|
188
|
+
[:LeftShift, '<<'],
|
189
|
+
[:LessOrEqual, '<='],
|
190
|
+
[:LogicalAnd, '&&'],
|
191
|
+
[:LogicalOr, '||'],
|
192
|
+
[:Modulus, '%'],
|
193
|
+
[:Multiply, '*'],
|
194
|
+
[:NotEqual, '!='],
|
195
|
+
[:NotStrictEqual, '!=='],
|
196
|
+
[:OpAndEqual, '&='],
|
197
|
+
[:OpDivideEqual, '/='],
|
198
|
+
[:OpLShiftEqual, '<<='],
|
199
|
+
[:OpMinusEqual, '-='],
|
200
|
+
[:OpModEqual, '%='],
|
201
|
+
[:OpMultiplyEqual, '*='],
|
202
|
+
[:OpOrEqual, '|='],
|
203
|
+
[:OpPlusEqual, '+='],
|
204
|
+
[:OpRShiftEqual, '>>='],
|
205
|
+
[:OpURShiftEqual, '>>>='],
|
206
|
+
[:OpXOrEqual, '^='],
|
207
|
+
[:RightShift, '>>'],
|
208
|
+
[:StrictEqual, '==='],
|
209
|
+
[:Subtract, '-'],
|
210
|
+
[:UnsignedRightShift, '>>>'],
|
211
|
+
].each do |name,op|
|
212
|
+
define_method(:"visit_#{name}Node") do |o|
|
213
|
+
"#{o.left.accept(self)} #{op} #{o.value.accept(self)}"
|
214
|
+
end
|
215
|
+
end
|
216
|
+
|
217
|
+
def visit_WhileNode(o)
|
218
|
+
"while(#{o.left.accept(self)}) #{o.value.accept(self)}"
|
219
|
+
end
|
220
|
+
|
221
|
+
def visit_SwitchNode(o)
|
222
|
+
"switch(#{o.left.accept(self)}) #{o.value.accept(self)}"
|
223
|
+
end
|
224
|
+
|
225
|
+
def visit_CaseBlockNode(o)
|
226
|
+
@indent += 1
|
227
|
+
"{\n" + (o.value ? o.value.map { |x| x.accept(self) }.join('') : '') +
|
228
|
+
"#{@indent -=1; indent}}"
|
229
|
+
end
|
230
|
+
|
231
|
+
def visit_CaseClauseNode(o)
|
232
|
+
case_code = "#{indent}case #{o.left ? o.left.accept(self) : nil}:\n"
|
233
|
+
@indent += 1
|
234
|
+
case_code += "#{o.value.accept(self)}\n"
|
235
|
+
@indent -= 1
|
236
|
+
case_code
|
237
|
+
end
|
238
|
+
|
239
|
+
def visit_DoWhileNode(o)
|
240
|
+
"do #{o.left.accept(self)} while(#{o.value.accept(self)});"
|
241
|
+
end
|
242
|
+
|
243
|
+
def visit_WithNode(o)
|
244
|
+
"with(#{o.left.accept(self)}) #{o.value.accept(self)}"
|
245
|
+
end
|
246
|
+
|
247
|
+
def visit_LabelNode(o)
|
248
|
+
"#{o.name}: #{o.value.accept(self)}"
|
249
|
+
end
|
250
|
+
|
251
|
+
def visit_ObjectLiteralNode(o)
|
252
|
+
@indent += 1
|
253
|
+
lit = "{" + (o.value.length > 0 ? "\n" : ' ') +
|
254
|
+
o.value.map { |x| "#{indent}#{x.accept(self)}" }.join(",\n") +
|
255
|
+
(o.value.length > 0 ? "\n" : '') + '}'
|
256
|
+
@indent -= 1
|
257
|
+
lit
|
258
|
+
end
|
259
|
+
|
260
|
+
def visit_PropertyNode(o)
|
261
|
+
"#{o.name}: #{o.value.accept(self)}"
|
262
|
+
end
|
263
|
+
|
264
|
+
def visit_GetterPropertyNode(o)
|
265
|
+
"get #{o.name}#{o.value.accept(self)}"
|
266
|
+
end
|
267
|
+
|
268
|
+
def visit_SetterPropertyNode(o)
|
269
|
+
"set #{o.name}#{o.value.accept(self)}"
|
270
|
+
end
|
271
|
+
|
272
|
+
def visit_FunctionExprNode(o)
|
273
|
+
"#{o.value}(#{o.arguments.map { |x| x.accept(self) }.join(', ')}) " +
|
274
|
+
"#{o.function_body.accept(self)}"
|
275
|
+
end
|
276
|
+
|
277
|
+
def visit_CommaNode(o)
|
278
|
+
"#{o.left.accept(self)}, #{o.value.accept(self)}"
|
279
|
+
end
|
280
|
+
|
281
|
+
def visit_IfNode(o)
|
282
|
+
"if(#{o.conditions.accept(self)}) #{o.value.accept(self)}" +
|
283
|
+
(o.else ? " else #{o.else.accept(self)}" : '')
|
284
|
+
end
|
285
|
+
|
286
|
+
def visit_ConditionalNode(o)
|
287
|
+
"#{o.conditions.accept(self)} ? #{o.value.accept(self)} : " +
|
288
|
+
"#{o.else.accept(self)}"
|
289
|
+
end
|
290
|
+
|
291
|
+
def visit_ForInNode(o)
|
292
|
+
"for(#{o.left.accept(self)} in #{o.right.accept(self)}) " +
|
293
|
+
"#{o.value.accept(self)}"
|
294
|
+
end
|
295
|
+
|
296
|
+
def visit_TryNode(o)
|
297
|
+
"try #{o.value.accept(self)}" +
|
298
|
+
(o.catch_block ? " catch(#{o.catch_var}) #{o.catch_block.accept(self)}" : '') +
|
299
|
+
(o.finally_block ? " finally #{o.finally_block.accept(self)}" : '')
|
300
|
+
end
|
301
|
+
|
302
|
+
def visit_BracketAccessorNode(o)
|
303
|
+
"#{o.value.accept(self)}[#{o.accessor.accept(self)}]"
|
304
|
+
end
|
305
|
+
|
306
|
+
def visit_NewExprNode(o)
|
307
|
+
"new #{o.value.accept(self)}(#{o.arguments.accept(self)})"
|
308
|
+
end
|
309
|
+
|
310
|
+
private
|
311
|
+
def indent; ' ' * @indent * 2; end
|
312
|
+
end
|
313
|
+
end
|
314
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module RKelly
|
2
|
+
module Visitors
|
3
|
+
class EnumerableVisitor < Visitor
|
4
|
+
def initialize(block)
|
5
|
+
@block = block
|
6
|
+
end
|
7
|
+
|
8
|
+
ALL_NODES.each do |type|
|
9
|
+
eval <<-RUBY
|
10
|
+
def visit_#{type}Node(o)
|
11
|
+
@block[o]
|
12
|
+
super
|
13
|
+
end
|
14
|
+
RUBY
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,419 @@
|
|
1
|
+
module RKelly
|
2
|
+
module Visitors
|
3
|
+
class EvaluationVisitor < Visitor
|
4
|
+
attr_reader :scope_chain
|
5
|
+
def initialize(scope)
|
6
|
+
super()
|
7
|
+
@scope_chain = scope
|
8
|
+
@operand = []
|
9
|
+
end
|
10
|
+
|
11
|
+
def visit_SourceElementsNode(o)
|
12
|
+
o.value.each { |x|
|
13
|
+
next if scope_chain.returned?
|
14
|
+
x.accept(self)
|
15
|
+
}
|
16
|
+
end
|
17
|
+
|
18
|
+
def visit_FunctionDeclNode(o)
|
19
|
+
end
|
20
|
+
|
21
|
+
def visit_VarStatementNode(o)
|
22
|
+
o.value.each { |x| x.accept(self) }
|
23
|
+
end
|
24
|
+
|
25
|
+
def visit_VarDeclNode(o)
|
26
|
+
@operand << o.name
|
27
|
+
o.value.accept(self) if o.value
|
28
|
+
@operand.pop
|
29
|
+
end
|
30
|
+
|
31
|
+
def visit_IfNode(o)
|
32
|
+
truthiness = o.conditions.accept(self)
|
33
|
+
if truthiness.value && truthiness.value != 0
|
34
|
+
o.value.accept(self)
|
35
|
+
else
|
36
|
+
o.else && o.else.accept(self)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def visit_ResolveNode(o)
|
41
|
+
scope_chain[o.value]
|
42
|
+
end
|
43
|
+
|
44
|
+
def visit_ThisNode(o)
|
45
|
+
scope_chain.this
|
46
|
+
end
|
47
|
+
|
48
|
+
def visit_ExpressionStatementNode(o)
|
49
|
+
o.value.accept(self)
|
50
|
+
end
|
51
|
+
|
52
|
+
def visit_AddNode(o)
|
53
|
+
left = to_primitive(o.left.accept(self), 'Number')
|
54
|
+
right = to_primitive(o.value.accept(self), 'Number')
|
55
|
+
|
56
|
+
if left.value.is_a?(::String) || right.value.is_a?(::String)
|
57
|
+
RKelly::JS::Property.new(:add,
|
58
|
+
"#{left.value}#{right.value}"
|
59
|
+
)
|
60
|
+
else
|
61
|
+
additive_operator(:+, left, right)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def visit_SubtractNode(o)
|
66
|
+
RKelly::JS::Property.new(:subtract,
|
67
|
+
o.left.accept(self).value - o.value.accept(self).value
|
68
|
+
)
|
69
|
+
end
|
70
|
+
|
71
|
+
def visit_MultiplyNode(o)
|
72
|
+
left = to_number(o.left.accept(self)).value
|
73
|
+
right = to_number(o.value.accept(self)).value
|
74
|
+
return_val =
|
75
|
+
if [left, right].any? { |x| x.respond_to?(:nan?) && x.nan? }
|
76
|
+
RKelly::JS::NaN.new
|
77
|
+
else
|
78
|
+
[left, right].any? { |x|
|
79
|
+
x.respond_to?(:intinite?) && x.infinite?
|
80
|
+
} && [left, right].any? { |x| x == 0
|
81
|
+
} ? RKelly::JS::NaN.new : left * right
|
82
|
+
end
|
83
|
+
RKelly::JS::Property.new(:multiple, return_val)
|
84
|
+
end
|
85
|
+
|
86
|
+
def visit_DivideNode(o)
|
87
|
+
left = to_number(o.left.accept(self)).value
|
88
|
+
right = to_number(o.value.accept(self)).value
|
89
|
+
return_val =
|
90
|
+
if [left, right].any? { |x|
|
91
|
+
x.respond_to?(:nan?) && x.nan? ||
|
92
|
+
x.respond_to?(:intinite?) && x.infinite?
|
93
|
+
}
|
94
|
+
RKelly::JS::NaN.new
|
95
|
+
elsif [left, right].all? { |x| x == 0 }
|
96
|
+
RKelly::JS::NaN.new
|
97
|
+
elsif right == 0
|
98
|
+
left * (right.eql?(0) ? (1.0/0.0) : (-1.0/0.0))
|
99
|
+
else
|
100
|
+
left / right
|
101
|
+
end
|
102
|
+
RKelly::JS::Property.new(:divide, return_val)
|
103
|
+
end
|
104
|
+
|
105
|
+
def visit_ModulusNode(o)
|
106
|
+
left = to_number(o.left.accept(self)).value
|
107
|
+
right = to_number(o.value.accept(self)).value
|
108
|
+
return_val =
|
109
|
+
if [left, right].any? { |x| x.respond_to?(:nan?) && x.nan? }
|
110
|
+
RKelly::JS::NaN.new
|
111
|
+
elsif [left, right].all? { |x| x.respond_to?(:infinite?) && x.infinite? }
|
112
|
+
RKelly::JS::NaN.new
|
113
|
+
elsif right == 0
|
114
|
+
RKelly::JS::NaN.new
|
115
|
+
elsif left.respond_to?(:infinite?) && left.infinite?
|
116
|
+
RKelly::JS::NaN.new
|
117
|
+
elsif right.respond_to?(:infinite?) && right.infinite?
|
118
|
+
left
|
119
|
+
else
|
120
|
+
left % right
|
121
|
+
end
|
122
|
+
RKelly::JS::Property.new(:divide, return_val)
|
123
|
+
end
|
124
|
+
|
125
|
+
def visit_OpEqualNode(o)
|
126
|
+
left = o.left.accept(self)
|
127
|
+
right = o.value.accept(self)
|
128
|
+
left.value = right.value
|
129
|
+
left.function = right.function
|
130
|
+
left
|
131
|
+
end
|
132
|
+
|
133
|
+
def visit_OpPlusEqualNode(o)
|
134
|
+
o.left.accept(self).value += o.value.accept(self).value
|
135
|
+
end
|
136
|
+
|
137
|
+
def visit_AssignExprNode(o)
|
138
|
+
scope_chain[@operand.last] = o.value.accept(self)
|
139
|
+
end
|
140
|
+
|
141
|
+
def visit_NumberNode(o)
|
142
|
+
RKelly::JS::Property.new(o.value, o.value)
|
143
|
+
end
|
144
|
+
|
145
|
+
def visit_VoidNode(o)
|
146
|
+
o.value.accept(self)
|
147
|
+
RKelly::JS::Property.new(:undefined, :undefined)
|
148
|
+
end
|
149
|
+
|
150
|
+
def visit_NullNode(o)
|
151
|
+
RKelly::JS::Property.new(nil, nil)
|
152
|
+
end
|
153
|
+
|
154
|
+
def visit_TrueNode(o)
|
155
|
+
RKelly::JS::Property.new(true, true)
|
156
|
+
end
|
157
|
+
|
158
|
+
def visit_FalseNode(o)
|
159
|
+
RKelly::JS::Property.new(false, false)
|
160
|
+
end
|
161
|
+
|
162
|
+
def visit_StringNode(o)
|
163
|
+
RKelly::JS::Property.new(:string,
|
164
|
+
o.value.gsub(/\A['"]/, '').gsub(/['"]$/, '')
|
165
|
+
)
|
166
|
+
end
|
167
|
+
|
168
|
+
def visit_FunctionCallNode(o)
|
169
|
+
left = o.value.accept(self)
|
170
|
+
arguments = o.arguments.accept(self)
|
171
|
+
call_function(left, arguments)
|
172
|
+
end
|
173
|
+
|
174
|
+
def visit_NewExprNode(o)
|
175
|
+
visit_FunctionCallNode(o)
|
176
|
+
end
|
177
|
+
|
178
|
+
def visit_DotAccessorNode(o)
|
179
|
+
left = o.value.accept(self)
|
180
|
+
right = left.value[o.accessor]
|
181
|
+
right.binder = left.value
|
182
|
+
right
|
183
|
+
end
|
184
|
+
|
185
|
+
def visit_EqualNode(o)
|
186
|
+
left = o.left.accept(self)
|
187
|
+
right = o.value.accept(self)
|
188
|
+
|
189
|
+
RKelly::JS::Property.new(:equal_node, left.value == right.value)
|
190
|
+
end
|
191
|
+
|
192
|
+
def visit_BlockNode(o)
|
193
|
+
o.value.accept(self)
|
194
|
+
end
|
195
|
+
|
196
|
+
def visit_FunctionBodyNode(o)
|
197
|
+
o.value.accept(self)
|
198
|
+
scope_chain.return
|
199
|
+
end
|
200
|
+
|
201
|
+
def visit_ReturnNode(o)
|
202
|
+
scope_chain.return = o.value.accept(self)
|
203
|
+
end
|
204
|
+
|
205
|
+
def visit_BitwiseNotNode(o)
|
206
|
+
orig = o.value.accept(self)
|
207
|
+
number = to_int_32(orig)
|
208
|
+
RKelly::JS::Property.new(nil, ~number.value)
|
209
|
+
end
|
210
|
+
|
211
|
+
def visit_PostfixNode(o)
|
212
|
+
orig = o.operand.accept(self)
|
213
|
+
number = to_number(orig)
|
214
|
+
case o.value
|
215
|
+
when '++'
|
216
|
+
orig.value = number.value + 1
|
217
|
+
when '--'
|
218
|
+
orig.value = number.value - 1
|
219
|
+
end
|
220
|
+
number
|
221
|
+
end
|
222
|
+
|
223
|
+
def visit_PrefixNode(o)
|
224
|
+
orig = o.operand.accept(self)
|
225
|
+
number = to_number(orig)
|
226
|
+
case o.value
|
227
|
+
when '++'
|
228
|
+
orig.value = number.value + 1
|
229
|
+
when '--'
|
230
|
+
orig.value = number.value - 1
|
231
|
+
end
|
232
|
+
orig
|
233
|
+
end
|
234
|
+
|
235
|
+
def visit_LogicalNotNode(o)
|
236
|
+
bool = to_boolean(o.value.accept(self))
|
237
|
+
bool.value = !bool.value
|
238
|
+
bool
|
239
|
+
end
|
240
|
+
|
241
|
+
def visit_ArgumentsNode(o)
|
242
|
+
o.value.map { |x| x.accept(self) }
|
243
|
+
end
|
244
|
+
|
245
|
+
def visit_TypeOfNode(o)
|
246
|
+
val = o.value.accept(self)
|
247
|
+
return RKelly::JS::Property.new(:string, 'object') if val.value.nil?
|
248
|
+
|
249
|
+
case val.value
|
250
|
+
when String
|
251
|
+
RKelly::JS::Property.new(:string, 'string')
|
252
|
+
when Numeric
|
253
|
+
RKelly::JS::Property.new(:string, 'number')
|
254
|
+
when true
|
255
|
+
RKelly::JS::Property.new(:string, 'boolean')
|
256
|
+
when false
|
257
|
+
RKelly::JS::Property.new(:string, 'boolean')
|
258
|
+
when :undefined
|
259
|
+
RKelly::JS::Property.new(:string, 'undefined')
|
260
|
+
else
|
261
|
+
RKelly::JS::Property.new(:object, 'object')
|
262
|
+
end
|
263
|
+
end
|
264
|
+
|
265
|
+
def visit_UnaryPlusNode(o)
|
266
|
+
orig = o.value.accept(self)
|
267
|
+
to_number(orig)
|
268
|
+
end
|
269
|
+
|
270
|
+
def visit_UnaryMinusNode(o)
|
271
|
+
orig = o.value.accept(self)
|
272
|
+
v = to_number(orig)
|
273
|
+
v.value = v.value == 0 ? -0.0 : 0 - v.value
|
274
|
+
v
|
275
|
+
end
|
276
|
+
|
277
|
+
%w{
|
278
|
+
ArrayNode BitAndNode BitOrNode
|
279
|
+
BitXOrNode BracketAccessorNode BreakNode
|
280
|
+
CaseBlockNode CaseClauseNode CommaNode ConditionalNode
|
281
|
+
ConstStatementNode ContinueNode DeleteNode
|
282
|
+
DoWhileNode ElementNode EmptyStatementNode
|
283
|
+
ForInNode ForNode
|
284
|
+
FunctionExprNode GetterPropertyNode GreaterNode GreaterOrEqualNode
|
285
|
+
InNode InstanceOfNode LabelNode LeftShiftNode LessNode
|
286
|
+
LessOrEqualNode LogicalAndNode LogicalOrNode
|
287
|
+
NotEqualNode NotStrictEqualNode
|
288
|
+
ObjectLiteralNode OpAndEqualNode OpDivideEqualNode
|
289
|
+
OpLShiftEqualNode OpMinusEqualNode OpModEqualNode
|
290
|
+
OpMultiplyEqualNode OpOrEqualNode OpRShiftEqualNode
|
291
|
+
OpURShiftEqualNode OpXOrEqualNode ParameterNode
|
292
|
+
PropertyNode RegexpNode RightShiftNode
|
293
|
+
SetterPropertyNode StrictEqualNode
|
294
|
+
SwitchNode ThrowNode TryNode
|
295
|
+
UnsignedRightShiftNode
|
296
|
+
WhileNode WithNode
|
297
|
+
}.each do |type|
|
298
|
+
define_method(:"visit_#{type}") do |o|
|
299
|
+
raise "#{type} not defined"
|
300
|
+
end
|
301
|
+
end
|
302
|
+
|
303
|
+
private
|
304
|
+
def to_number(object)
|
305
|
+
return RKelly::JS::Property.new('0', 0) unless object.value
|
306
|
+
|
307
|
+
return_val =
|
308
|
+
case object.value
|
309
|
+
when :undefined
|
310
|
+
RKelly::JS::NaN.new
|
311
|
+
when false
|
312
|
+
0
|
313
|
+
when true
|
314
|
+
1
|
315
|
+
when Numeric
|
316
|
+
object.value
|
317
|
+
when ::String
|
318
|
+
s = object.value.gsub(/(\A[\s\xB\xA0]*|[\s\xB\xA0]*\Z)/, '')
|
319
|
+
if s.length == 0
|
320
|
+
0
|
321
|
+
else
|
322
|
+
case s
|
323
|
+
when /^([+-])?Infinity/
|
324
|
+
$1 == '-' ? -1.0/0.0 : 1.0/0.0
|
325
|
+
when /\A[-+]?\d+\.\d*(?:[eE][-+]?\d+)?$|\A[-+]?\d+(?:\.\d*)?[eE][-+]?\d+$|\A[-+]?\.\d+(?:[eE][-+]?\d+)?$/, /\A[-+]?0[xX][\da-fA-F]+$|\A[+-]?0[0-7]*$|\A[+-]?\d+$/
|
326
|
+
s.gsub!(/\.(\D)/, '.0\1') if s =~ /\.\w/
|
327
|
+
s.gsub!(/\.$/, '.0') if s =~ /\.$/
|
328
|
+
s.gsub!(/^\./, '0.') if s =~ /^\./
|
329
|
+
s.gsub!(/^([+-])\./, '\10.') if s =~ /^[+-]\./
|
330
|
+
s = s.gsub(/^[0]*/, '') if /^0[1-9]+$/.match(s)
|
331
|
+
eval(s)
|
332
|
+
else
|
333
|
+
RKelly::JS::NaN.new
|
334
|
+
end
|
335
|
+
end
|
336
|
+
when RKelly::JS::Base
|
337
|
+
return to_number(to_primitive(object, 'Number'))
|
338
|
+
end
|
339
|
+
RKelly::JS::Property.new(nil, return_val)
|
340
|
+
end
|
341
|
+
|
342
|
+
def to_boolean(object)
|
343
|
+
return RKelly::JS::Property.new(false, false) unless object.value
|
344
|
+
value = object.value
|
345
|
+
boolean =
|
346
|
+
case value
|
347
|
+
when :undefined
|
348
|
+
false
|
349
|
+
when true
|
350
|
+
true
|
351
|
+
when Numeric
|
352
|
+
value == 0 || value.respond_to?(:nan?) && value.nan? ? false : true
|
353
|
+
when ::String
|
354
|
+
value.length == 0 ? false : true
|
355
|
+
when RKelly::JS::Base
|
356
|
+
true
|
357
|
+
else
|
358
|
+
raise
|
359
|
+
end
|
360
|
+
RKelly::JS::Property.new(boolean, boolean)
|
361
|
+
end
|
362
|
+
|
363
|
+
def to_int_32(object)
|
364
|
+
number = to_number(object)
|
365
|
+
value = number.value
|
366
|
+
return number if value == 0
|
367
|
+
if value.respond_to?(:nan?) && (value.nan? || value.infinite?)
|
368
|
+
RKelly::JS::Property.new(nil, 0)
|
369
|
+
end
|
370
|
+
value = ((value < 0 ? -1 : 1) * value.abs.floor) % (2 ** 32)
|
371
|
+
if value >= 2 ** 31
|
372
|
+
RKelly::JS::Property.new(nil, value - (2 ** 32))
|
373
|
+
else
|
374
|
+
RKelly::JS::Property.new(nil, value)
|
375
|
+
end
|
376
|
+
end
|
377
|
+
|
378
|
+
def to_primitive(object, preferred_type = nil)
|
379
|
+
return object unless object.value
|
380
|
+
case object.value
|
381
|
+
when false, true, :undefined, ::String, Numeric
|
382
|
+
RKelly::JS::Property.new(nil, object.value)
|
383
|
+
when RKelly::JS::Base
|
384
|
+
call_function(object.value.default_value(preferred_type))
|
385
|
+
end
|
386
|
+
end
|
387
|
+
|
388
|
+
def additive_operator(operator, left, right)
|
389
|
+
left, right = to_number(left).value, to_number(right).value
|
390
|
+
|
391
|
+
left = left.respond_to?(:nan?) && left.nan? ? 0.0/0.0 : left
|
392
|
+
right = right.respond_to?(:nan?) && right.nan? ? 0.0/0.0 : right
|
393
|
+
|
394
|
+
result = left.send(operator, right)
|
395
|
+
result = result.respond_to?(:nan?) && result.nan? ? JS::NaN.new : result
|
396
|
+
|
397
|
+
RKelly::JS::Property.new(operator, result)
|
398
|
+
end
|
399
|
+
|
400
|
+
def call_function(property, arguments = [])
|
401
|
+
function = property.function || property.value
|
402
|
+
case function
|
403
|
+
when RKelly::JS::Function
|
404
|
+
scope_chain.new_scope { |chain|
|
405
|
+
function.js_call(chain, *arguments)
|
406
|
+
}
|
407
|
+
when UnboundMethod
|
408
|
+
RKelly::JS::Property.new(:ruby,
|
409
|
+
function.bind(property.binder).call(*(arguments.map { |x| x.value}))
|
410
|
+
)
|
411
|
+
else
|
412
|
+
RKelly::JS::Property.new(:ruby,
|
413
|
+
function.call(*(arguments.map { |x| x.value }))
|
414
|
+
)
|
415
|
+
end
|
416
|
+
end
|
417
|
+
end
|
418
|
+
end
|
419
|
+
end
|