rkelly-fixed 1.0.7

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