rkelly_for_reef 1.0.8

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 (202) hide show
  1. checksums.yaml +7 -0
  2. data/.gemtest +0 -0
  3. data/CHANGELOG.rdoc +26 -0
  4. data/Manifest.txt +199 -0
  5. data/README.rdoc +58 -0
  6. data/Rakefile +39 -0
  7. data/lib/parser.y +871 -0
  8. data/lib/rkelly.rb +14 -0
  9. data/lib/rkelly/constants.rb +3 -0
  10. data/lib/rkelly/generated_parser.rb +3274 -0
  11. data/lib/rkelly/js.rb +14 -0
  12. data/lib/rkelly/js/array.rb +15 -0
  13. data/lib/rkelly/js/base.rb +91 -0
  14. data/lib/rkelly/js/boolean.rb +21 -0
  15. data/lib/rkelly/js/function.rb +39 -0
  16. data/lib/rkelly/js/function_prototype.rb +15 -0
  17. data/lib/rkelly/js/global_object.rb +52 -0
  18. data/lib/rkelly/js/math.rb +10 -0
  19. data/lib/rkelly/js/nan.rb +18 -0
  20. data/lib/rkelly/js/number.rb +22 -0
  21. data/lib/rkelly/js/object.rb +30 -0
  22. data/lib/rkelly/js/object_prototype.rb +14 -0
  23. data/lib/rkelly/js/property.rb +20 -0
  24. data/lib/rkelly/js/scope.rb +6 -0
  25. data/lib/rkelly/js/string.rb +21 -0
  26. data/lib/rkelly/lexeme.rb +18 -0
  27. data/lib/rkelly/nodes.rb +25 -0
  28. data/lib/rkelly/nodes/binary_node.rb +18 -0
  29. data/lib/rkelly/nodes/bracket_accessor_node.rb +11 -0
  30. data/lib/rkelly/nodes/case_clause_node.rb +11 -0
  31. data/lib/rkelly/nodes/comma_node.rb +11 -0
  32. data/lib/rkelly/nodes/conditional_node.rb +11 -0
  33. data/lib/rkelly/nodes/dot_accessor_node.rb +11 -0
  34. data/lib/rkelly/nodes/for_in_node.rb +12 -0
  35. data/lib/rkelly/nodes/for_node.rb +13 -0
  36. data/lib/rkelly/nodes/function_call_node.rb +16 -0
  37. data/lib/rkelly/nodes/function_decl_node.rb +6 -0
  38. data/lib/rkelly/nodes/function_expr_node.rb +12 -0
  39. data/lib/rkelly/nodes/if_node.rb +12 -0
  40. data/lib/rkelly/nodes/label_node.rb +11 -0
  41. data/lib/rkelly/nodes/new_expr_node.rb +11 -0
  42. data/lib/rkelly/nodes/node.rb +88 -0
  43. data/lib/rkelly/nodes/not_strict_equal_node.rb +6 -0
  44. data/lib/rkelly/nodes/op_equal_node.rb +16 -0
  45. data/lib/rkelly/nodes/postfix_node.rb +11 -0
  46. data/lib/rkelly/nodes/prefix_node.rb +6 -0
  47. data/lib/rkelly/nodes/property_node.rb +13 -0
  48. data/lib/rkelly/nodes/resolve_node.rb +19 -0
  49. data/lib/rkelly/nodes/strict_equal_node.rb +6 -0
  50. data/lib/rkelly/nodes/try_node.rb +13 -0
  51. data/lib/rkelly/nodes/var_decl_node.rb +15 -0
  52. data/lib/rkelly/parser.rb +104 -0
  53. data/lib/rkelly/runtime.rb +36 -0
  54. data/lib/rkelly/runtime/ruby_function.rb +13 -0
  55. data/lib/rkelly/runtime/scope_chain.rb +57 -0
  56. data/lib/rkelly/syntax_error.rb +4 -0
  57. data/lib/rkelly/token.rb +19 -0
  58. data/lib/rkelly/tokenizer.rb +161 -0
  59. data/lib/rkelly/visitable.rb +16 -0
  60. data/lib/rkelly/visitors.rb +4 -0
  61. data/lib/rkelly/visitors/dot_visitor.rb +228 -0
  62. data/lib/rkelly/visitors/ecma_visitor.rb +322 -0
  63. data/lib/rkelly/visitors/enumerable_visitor.rb +18 -0
  64. data/lib/rkelly/visitors/evaluation_visitor.rb +419 -0
  65. data/lib/rkelly/visitors/function_visitor.rb +46 -0
  66. data/lib/rkelly/visitors/pointcut_visitor.rb +31 -0
  67. data/lib/rkelly/visitors/real_sexp_visitor.rb +16 -0
  68. data/lib/rkelly/visitors/sexp_visitor.rb +373 -0
  69. data/lib/rkelly/visitors/visitor.rb +136 -0
  70. data/test/ecma_script_test_case.rb +21 -0
  71. data/test/execute_test_case.rb +16 -0
  72. data/test/execution_contexts/test_10_1_3-1.rb +32 -0
  73. data/test/expressions/test_11_3_1.rb +64 -0
  74. data/test/expressions/test_11_3_2.rb +64 -0
  75. data/test/expressions/test_11_4_2.rb +13 -0
  76. data/test/expressions/test_11_4_3.rb +52 -0
  77. data/test/expressions/test_11_4_4.rb +68 -0
  78. data/test/expressions/test_11_4_5.rb +69 -0
  79. data/test/expressions/test_11_4_6.rb +88 -0
  80. data/test/expressions/test_11_4_8.rb +28 -0
  81. data/test/expressions/test_11_4_9.rb +103 -0
  82. data/test/expressions/test_11_5_1.rb +51 -0
  83. data/test/expressions/test_11_5_2.rb +80 -0
  84. data/test/expressions/test_11_5_3.rb +88 -0
  85. data/test/expressions/test_11_6_1-1.rb +19 -0
  86. data/test/expressions/test_11_9_1.rb +19 -0
  87. data/test/function/test_15_3_1_1-1.rb +34 -0
  88. data/test/global_object/test_15_1_1_1.rb +29 -0
  89. data/test/global_object/test_15_1_1_2.rb +17 -0
  90. data/test/global_object/test_15_1_1_3.rb +9 -0
  91. data/test/helper.rb +5 -0
  92. data/test/node_test_case.rb +11 -0
  93. data/test/object/test_15_2_1_1.rb +257 -0
  94. data/test/object/test_15_2_1_2.rb +21 -0
  95. data/test/object/test_15_2_2_1.rb +52 -0
  96. data/test/statements/test_12_5-1.rb +27 -0
  97. data/test/test_add_node.rb +8 -0
  98. data/test/test_arguments_node.rb +8 -0
  99. data/test/test_array_node.rb +9 -0
  100. data/test/test_assign_expr_node.rb +8 -0
  101. data/test/test_automatic_semicolon_insertion.rb +137 -0
  102. data/test/test_bit_and_node.rb +8 -0
  103. data/test/test_bit_or_node.rb +8 -0
  104. data/test/test_bit_x_or_node.rb +8 -0
  105. data/test/test_bitwise_not_node.rb +8 -0
  106. data/test/test_block_node.rb +14 -0
  107. data/test/test_bracket_accessor_node.rb +16 -0
  108. data/test/test_break_node.rb +11 -0
  109. data/test/test_case_block_node.rb +11 -0
  110. data/test/test_case_clause_node.rb +15 -0
  111. data/test/test_comma_node.rb +13 -0
  112. data/test/test_comments.rb +44 -0
  113. data/test/test_conditional_node.rb +17 -0
  114. data/test/test_const_statement_node.rb +14 -0
  115. data/test/test_continue_node.rb +11 -0
  116. data/test/test_delete_node.rb +8 -0
  117. data/test/test_divide_node.rb +8 -0
  118. data/test/test_do_while_node.rb +13 -0
  119. data/test/test_dot_accessor_node.rb +9 -0
  120. data/test/test_ecma_visitor.rb +210 -0
  121. data/test/test_element_node.rb +8 -0
  122. data/test/test_empty_statement_node.rb +8 -0
  123. data/test/test_equal_node.rb +8 -0
  124. data/test/test_evaluation_visitor.rb +66 -0
  125. data/test/test_expression_statement_node.rb +10 -0
  126. data/test/test_false_node.rb +8 -0
  127. data/test/test_for_in_node.rb +17 -0
  128. data/test/test_for_node.rb +24 -0
  129. data/test/test_function_body_node.rb +8 -0
  130. data/test/test_function_call_node.rb +10 -0
  131. data/test/test_function_decl_node.rb +16 -0
  132. data/test/test_function_expr_node.rb +16 -0
  133. data/test/test_function_visitor.rb +26 -0
  134. data/test/test_getter_property_node.rb +10 -0
  135. data/test/test_global_object.rb +49 -0
  136. data/test/test_greater_node.rb +8 -0
  137. data/test/test_greater_or_equal_node.rb +8 -0
  138. data/test/test_if_node.rb +17 -0
  139. data/test/test_in_node.rb +8 -0
  140. data/test/test_instance_of_node.rb +8 -0
  141. data/test/test_label_node.rb +13 -0
  142. data/test/test_left_shift_node.rb +8 -0
  143. data/test/test_less_node.rb +8 -0
  144. data/test/test_less_or_equal_node.rb +8 -0
  145. data/test/test_line_number.rb +23 -0
  146. data/test/test_logical_and_node.rb +8 -0
  147. data/test/test_logical_not_node.rb +8 -0
  148. data/test/test_logical_or_node.rb +8 -0
  149. data/test/test_modulus_node.rb +8 -0
  150. data/test/test_multiply_node.rb +8 -0
  151. data/test/test_new_expr_node.rb +9 -0
  152. data/test/test_not_equal_node.rb +8 -0
  153. data/test/test_not_strict_equal_node.rb +8 -0
  154. data/test/test_null_node.rb +8 -0
  155. data/test/test_number_node.rb +8 -0
  156. data/test/test_object_literal_node.rb +9 -0
  157. data/test/test_op_and_equal_node.rb +10 -0
  158. data/test/test_op_divide_equal_node.rb +10 -0
  159. data/test/test_op_equal_node.rb +10 -0
  160. data/test/test_op_l_shift_equal_node.rb +10 -0
  161. data/test/test_op_minus_equal_node.rb +10 -0
  162. data/test/test_op_mod_equal_node.rb +10 -0
  163. data/test/test_op_multiply_equal_node.rb +10 -0
  164. data/test/test_op_or_equal_node.rb +10 -0
  165. data/test/test_op_plus_equal_node.rb +10 -0
  166. data/test/test_op_r_shift_equal_node.rb +10 -0
  167. data/test/test_op_u_r_shift_equal_node.rb +10 -0
  168. data/test/test_op_x_or_equal_node.rb +10 -0
  169. data/test/test_parameter_node.rb +8 -0
  170. data/test/test_parser.rb +1361 -0
  171. data/test/test_pointcut_visitor.rb +34 -0
  172. data/test/test_postfix_node.rb +8 -0
  173. data/test/test_prefix_node.rb +8 -0
  174. data/test/test_property_node.rb +8 -0
  175. data/test/test_regexp_node.rb +8 -0
  176. data/test/test_resolve_node.rb +22 -0
  177. data/test/test_return_node.rb +11 -0
  178. data/test/test_right_shift_node.rb +8 -0
  179. data/test/test_rkelly.rb +19 -0
  180. data/test/test_runtime.rb +12 -0
  181. data/test/test_scope_chain.rb +50 -0
  182. data/test/test_setter_property_node.rb +10 -0
  183. data/test/test_source_elements.rb +9 -0
  184. data/test/test_strict_equal_node.rb +8 -0
  185. data/test/test_string_node.rb +8 -0
  186. data/test/test_subtract_node.rb +8 -0
  187. data/test/test_switch_node.rb +12 -0
  188. data/test/test_this_node.rb +8 -0
  189. data/test/test_throw_node.rb +7 -0
  190. data/test/test_tokenizer.rb +199 -0
  191. data/test/test_true_node.rb +8 -0
  192. data/test/test_try_node.rb +59 -0
  193. data/test/test_type_of_node.rb +8 -0
  194. data/test/test_unary_minus_node.rb +8 -0
  195. data/test/test_unary_plus_node.rb +8 -0
  196. data/test/test_unsigned_right_shift_node.rb +8 -0
  197. data/test/test_var_decl_node.rb +21 -0
  198. data/test/test_var_statement_node.rb +14 -0
  199. data/test/test_void_node.rb +8 -0
  200. data/test/test_while_node.rb +15 -0
  201. data/test/test_with_node.rb +8 -0
  202. metadata +406 -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,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\xA0]*|[\s\xA0]*\Z)/n, '')
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