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