modulr 0.1.0

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 (217) hide show
  1. data/LICENSE +22 -0
  2. data/README.markdown +62 -0
  3. data/Rakefile +55 -0
  4. data/VERSION +1 -0
  5. data/assets/modulr.js +58 -0
  6. data/bin/modulrize +39 -0
  7. data/example/foo/bar.js +1 -0
  8. data/example/foo/foo.js +3 -0
  9. data/example/increment.js +6 -0
  10. data/example/inspect.js +3 -0
  11. data/example/math.js +7 -0
  12. data/example/program.js +9 -0
  13. data/lib/modulr/collector.rb +60 -0
  14. data/lib/modulr/js_module.rb +88 -0
  15. data/lib/modulr/version.rb +6 -0
  16. data/lib/modulr.rb +21 -0
  17. data/vendor/rkelly/CHANGELOG.rdoc +13 -0
  18. data/vendor/rkelly/Manifest.txt +198 -0
  19. data/vendor/rkelly/README.rdoc +58 -0
  20. data/vendor/rkelly/Rakefile +39 -0
  21. data/vendor/rkelly/lib/parser.y +870 -0
  22. data/vendor/rkelly/lib/rkelly/constants.rb +3 -0
  23. data/vendor/rkelly/lib/rkelly/generated_parser.rb +3237 -0
  24. data/vendor/rkelly/lib/rkelly/js/array.rb +15 -0
  25. data/vendor/rkelly/lib/rkelly/js/base.rb +91 -0
  26. data/vendor/rkelly/lib/rkelly/js/boolean.rb +21 -0
  27. data/vendor/rkelly/lib/rkelly/js/function.rb +39 -0
  28. data/vendor/rkelly/lib/rkelly/js/function_prototype.rb +15 -0
  29. data/vendor/rkelly/lib/rkelly/js/global_object.rb +52 -0
  30. data/vendor/rkelly/lib/rkelly/js/math.rb +10 -0
  31. data/vendor/rkelly/lib/rkelly/js/nan.rb +18 -0
  32. data/vendor/rkelly/lib/rkelly/js/number.rb +22 -0
  33. data/vendor/rkelly/lib/rkelly/js/object.rb +30 -0
  34. data/vendor/rkelly/lib/rkelly/js/object_prototype.rb +14 -0
  35. data/vendor/rkelly/lib/rkelly/js/property.rb +20 -0
  36. data/vendor/rkelly/lib/rkelly/js/scope.rb +6 -0
  37. data/vendor/rkelly/lib/rkelly/js/string.rb +21 -0
  38. data/vendor/rkelly/lib/rkelly/js.rb +14 -0
  39. data/vendor/rkelly/lib/rkelly/lexeme.rb +18 -0
  40. data/vendor/rkelly/lib/rkelly/nodes/binary_node.rb +18 -0
  41. data/vendor/rkelly/lib/rkelly/nodes/bracket_accessor_node.rb +11 -0
  42. data/vendor/rkelly/lib/rkelly/nodes/case_clause_node.rb +11 -0
  43. data/vendor/rkelly/lib/rkelly/nodes/comma_node.rb +11 -0
  44. data/vendor/rkelly/lib/rkelly/nodes/conditional_node.rb +11 -0
  45. data/vendor/rkelly/lib/rkelly/nodes/dot_accessor_node.rb +11 -0
  46. data/vendor/rkelly/lib/rkelly/nodes/for_in_node.rb +12 -0
  47. data/vendor/rkelly/lib/rkelly/nodes/for_node.rb +13 -0
  48. data/vendor/rkelly/lib/rkelly/nodes/function_call_node.rb +16 -0
  49. data/vendor/rkelly/lib/rkelly/nodes/function_decl_node.rb +6 -0
  50. data/vendor/rkelly/lib/rkelly/nodes/function_expr_node.rb +12 -0
  51. data/vendor/rkelly/lib/rkelly/nodes/if_node.rb +12 -0
  52. data/vendor/rkelly/lib/rkelly/nodes/label_node.rb +11 -0
  53. data/vendor/rkelly/lib/rkelly/nodes/new_expr_node.rb +11 -0
  54. data/vendor/rkelly/lib/rkelly/nodes/node.rb +88 -0
  55. data/vendor/rkelly/lib/rkelly/nodes/not_strict_equal_node.rb +6 -0
  56. data/vendor/rkelly/lib/rkelly/nodes/op_equal_node.rb +16 -0
  57. data/vendor/rkelly/lib/rkelly/nodes/postfix_node.rb +11 -0
  58. data/vendor/rkelly/lib/rkelly/nodes/prefix_node.rb +6 -0
  59. data/vendor/rkelly/lib/rkelly/nodes/property_node.rb +13 -0
  60. data/vendor/rkelly/lib/rkelly/nodes/resolve_node.rb +19 -0
  61. data/vendor/rkelly/lib/rkelly/nodes/strict_equal_node.rb +6 -0
  62. data/vendor/rkelly/lib/rkelly/nodes/try_node.rb +13 -0
  63. data/vendor/rkelly/lib/rkelly/nodes/var_decl_node.rb +15 -0
  64. data/vendor/rkelly/lib/rkelly/nodes.rb +25 -0
  65. data/vendor/rkelly/lib/rkelly/parser.rb +104 -0
  66. data/vendor/rkelly/lib/rkelly/runtime/ruby_function.rb +13 -0
  67. data/vendor/rkelly/lib/rkelly/runtime/scope_chain.rb +57 -0
  68. data/vendor/rkelly/lib/rkelly/runtime.rb +36 -0
  69. data/vendor/rkelly/lib/rkelly/syntax_error.rb +4 -0
  70. data/vendor/rkelly/lib/rkelly/token.rb +15 -0
  71. data/vendor/rkelly/lib/rkelly/tokenizer.rb +122 -0
  72. data/vendor/rkelly/lib/rkelly/visitable.rb +16 -0
  73. data/vendor/rkelly/lib/rkelly/visitors/dot_visitor.rb +228 -0
  74. data/vendor/rkelly/lib/rkelly/visitors/ecma_visitor.rb +314 -0
  75. data/vendor/rkelly/lib/rkelly/visitors/enumerable_visitor.rb +18 -0
  76. data/vendor/rkelly/lib/rkelly/visitors/evaluation_visitor.rb +419 -0
  77. data/vendor/rkelly/lib/rkelly/visitors/function_visitor.rb +46 -0
  78. data/vendor/rkelly/lib/rkelly/visitors/pointcut_visitor.rb +31 -0
  79. data/vendor/rkelly/lib/rkelly/visitors/real_sexp_visitor.rb +16 -0
  80. data/vendor/rkelly/lib/rkelly/visitors/sexp_visitor.rb +373 -0
  81. data/vendor/rkelly/lib/rkelly/visitors/visitor.rb +136 -0
  82. data/vendor/rkelly/lib/rkelly/visitors.rb +4 -0
  83. data/vendor/rkelly/lib/rkelly.rb +14 -0
  84. data/vendor/rkelly/rkelly.gemspec +34 -0
  85. data/vendor/rkelly/test/ecma_script_test_case.rb +21 -0
  86. data/vendor/rkelly/test/execute_test_case.rb +16 -0
  87. data/vendor/rkelly/test/execution_contexts/test_10_1_3-1.rb +32 -0
  88. data/vendor/rkelly/test/expressions/test_11_3_1.rb +64 -0
  89. data/vendor/rkelly/test/expressions/test_11_3_2.rb +64 -0
  90. data/vendor/rkelly/test/expressions/test_11_4_2.rb +13 -0
  91. data/vendor/rkelly/test/expressions/test_11_4_3.rb +52 -0
  92. data/vendor/rkelly/test/expressions/test_11_4_4.rb +68 -0
  93. data/vendor/rkelly/test/expressions/test_11_4_5.rb +69 -0
  94. data/vendor/rkelly/test/expressions/test_11_4_6.rb +88 -0
  95. data/vendor/rkelly/test/expressions/test_11_4_8.rb +28 -0
  96. data/vendor/rkelly/test/expressions/test_11_4_9.rb +103 -0
  97. data/vendor/rkelly/test/expressions/test_11_5_1.rb +51 -0
  98. data/vendor/rkelly/test/expressions/test_11_5_2.rb +80 -0
  99. data/vendor/rkelly/test/expressions/test_11_5_3.rb +88 -0
  100. data/vendor/rkelly/test/expressions/test_11_6_1-1.rb +19 -0
  101. data/vendor/rkelly/test/expressions/test_11_9_1.rb +19 -0
  102. data/vendor/rkelly/test/function/test_15_3_1_1-1.rb +34 -0
  103. data/vendor/rkelly/test/global_object/test_15_1_1_1.rb +29 -0
  104. data/vendor/rkelly/test/global_object/test_15_1_1_2.rb +17 -0
  105. data/vendor/rkelly/test/global_object/test_15_1_1_3.rb +9 -0
  106. data/vendor/rkelly/test/helper.rb +5 -0
  107. data/vendor/rkelly/test/node_test_case.rb +11 -0
  108. data/vendor/rkelly/test/object/test_15_2_1_1.rb +257 -0
  109. data/vendor/rkelly/test/object/test_15_2_1_2.rb +21 -0
  110. data/vendor/rkelly/test/object/test_15_2_2_1.rb +52 -0
  111. data/vendor/rkelly/test/statements/test_12_5-1.rb +27 -0
  112. data/vendor/rkelly/test/test_add_node.rb +8 -0
  113. data/vendor/rkelly/test/test_arguments_node.rb +8 -0
  114. data/vendor/rkelly/test/test_array_node.rb +9 -0
  115. data/vendor/rkelly/test/test_assign_expr_node.rb +8 -0
  116. data/vendor/rkelly/test/test_automatic_semicolon_insertion.rb +137 -0
  117. data/vendor/rkelly/test/test_bit_and_node.rb +8 -0
  118. data/vendor/rkelly/test/test_bit_or_node.rb +8 -0
  119. data/vendor/rkelly/test/test_bit_x_or_node.rb +8 -0
  120. data/vendor/rkelly/test/test_bitwise_not_node.rb +8 -0
  121. data/vendor/rkelly/test/test_block_node.rb +14 -0
  122. data/vendor/rkelly/test/test_bracket_accessor_node.rb +16 -0
  123. data/vendor/rkelly/test/test_break_node.rb +11 -0
  124. data/vendor/rkelly/test/test_case_block_node.rb +11 -0
  125. data/vendor/rkelly/test/test_case_clause_node.rb +15 -0
  126. data/vendor/rkelly/test/test_comma_node.rb +13 -0
  127. data/vendor/rkelly/test/test_comments.rb +44 -0
  128. data/vendor/rkelly/test/test_conditional_node.rb +17 -0
  129. data/vendor/rkelly/test/test_const_statement_node.rb +14 -0
  130. data/vendor/rkelly/test/test_continue_node.rb +11 -0
  131. data/vendor/rkelly/test/test_delete_node.rb +8 -0
  132. data/vendor/rkelly/test/test_divide_node.rb +8 -0
  133. data/vendor/rkelly/test/test_do_while_node.rb +13 -0
  134. data/vendor/rkelly/test/test_dot_accessor_node.rb +9 -0
  135. data/vendor/rkelly/test/test_ecma_visitor.rb +192 -0
  136. data/vendor/rkelly/test/test_element_node.rb +8 -0
  137. data/vendor/rkelly/test/test_empty_statement_node.rb +8 -0
  138. data/vendor/rkelly/test/test_equal_node.rb +8 -0
  139. data/vendor/rkelly/test/test_evaluation_visitor.rb +66 -0
  140. data/vendor/rkelly/test/test_expression_statement_node.rb +10 -0
  141. data/vendor/rkelly/test/test_false_node.rb +8 -0
  142. data/vendor/rkelly/test/test_for_in_node.rb +17 -0
  143. data/vendor/rkelly/test/test_for_node.rb +24 -0
  144. data/vendor/rkelly/test/test_function_body_node.rb +8 -0
  145. data/vendor/rkelly/test/test_function_call_node.rb +10 -0
  146. data/vendor/rkelly/test/test_function_decl_node.rb +16 -0
  147. data/vendor/rkelly/test/test_function_expr_node.rb +16 -0
  148. data/vendor/rkelly/test/test_function_visitor.rb +26 -0
  149. data/vendor/rkelly/test/test_getter_property_node.rb +10 -0
  150. data/vendor/rkelly/test/test_global_object.rb +49 -0
  151. data/vendor/rkelly/test/test_greater_node.rb +8 -0
  152. data/vendor/rkelly/test/test_greater_or_equal_node.rb +8 -0
  153. data/vendor/rkelly/test/test_if_node.rb +17 -0
  154. data/vendor/rkelly/test/test_in_node.rb +8 -0
  155. data/vendor/rkelly/test/test_instance_of_node.rb +8 -0
  156. data/vendor/rkelly/test/test_label_node.rb +13 -0
  157. data/vendor/rkelly/test/test_left_shift_node.rb +8 -0
  158. data/vendor/rkelly/test/test_less_node.rb +8 -0
  159. data/vendor/rkelly/test/test_less_or_equal_node.rb +8 -0
  160. data/vendor/rkelly/test/test_line_number.rb +23 -0
  161. data/vendor/rkelly/test/test_logical_and_node.rb +8 -0
  162. data/vendor/rkelly/test/test_logical_not_node.rb +8 -0
  163. data/vendor/rkelly/test/test_logical_or_node.rb +8 -0
  164. data/vendor/rkelly/test/test_modulus_node.rb +8 -0
  165. data/vendor/rkelly/test/test_multiply_node.rb +8 -0
  166. data/vendor/rkelly/test/test_new_expr_node.rb +9 -0
  167. data/vendor/rkelly/test/test_not_equal_node.rb +8 -0
  168. data/vendor/rkelly/test/test_not_strict_equal_node.rb +8 -0
  169. data/vendor/rkelly/test/test_null_node.rb +8 -0
  170. data/vendor/rkelly/test/test_number_node.rb +8 -0
  171. data/vendor/rkelly/test/test_object_literal_node.rb +9 -0
  172. data/vendor/rkelly/test/test_op_and_equal_node.rb +10 -0
  173. data/vendor/rkelly/test/test_op_divide_equal_node.rb +10 -0
  174. data/vendor/rkelly/test/test_op_equal_node.rb +10 -0
  175. data/vendor/rkelly/test/test_op_l_shift_equal_node.rb +10 -0
  176. data/vendor/rkelly/test/test_op_minus_equal_node.rb +10 -0
  177. data/vendor/rkelly/test/test_op_mod_equal_node.rb +10 -0
  178. data/vendor/rkelly/test/test_op_multiply_equal_node.rb +10 -0
  179. data/vendor/rkelly/test/test_op_or_equal_node.rb +10 -0
  180. data/vendor/rkelly/test/test_op_plus_equal_node.rb +10 -0
  181. data/vendor/rkelly/test/test_op_r_shift_equal_node.rb +10 -0
  182. data/vendor/rkelly/test/test_op_u_r_shift_equal_node.rb +10 -0
  183. data/vendor/rkelly/test/test_op_x_or_equal_node.rb +10 -0
  184. data/vendor/rkelly/test/test_parameter_node.rb +8 -0
  185. data/vendor/rkelly/test/test_parser.rb +1361 -0
  186. data/vendor/rkelly/test/test_pointcut_visitor.rb +34 -0
  187. data/vendor/rkelly/test/test_postfix_node.rb +8 -0
  188. data/vendor/rkelly/test/test_prefix_node.rb +8 -0
  189. data/vendor/rkelly/test/test_property_node.rb +8 -0
  190. data/vendor/rkelly/test/test_regexp_node.rb +8 -0
  191. data/vendor/rkelly/test/test_resolve_node.rb +22 -0
  192. data/vendor/rkelly/test/test_return_node.rb +11 -0
  193. data/vendor/rkelly/test/test_right_shift_node.rb +8 -0
  194. data/vendor/rkelly/test/test_rkelly.rb +19 -0
  195. data/vendor/rkelly/test/test_runtime.rb +12 -0
  196. data/vendor/rkelly/test/test_scope_chain.rb +50 -0
  197. data/vendor/rkelly/test/test_setter_property_node.rb +10 -0
  198. data/vendor/rkelly/test/test_source_elements.rb +9 -0
  199. data/vendor/rkelly/test/test_strict_equal_node.rb +8 -0
  200. data/vendor/rkelly/test/test_string_node.rb +8 -0
  201. data/vendor/rkelly/test/test_subtract_node.rb +8 -0
  202. data/vendor/rkelly/test/test_switch_node.rb +12 -0
  203. data/vendor/rkelly/test/test_this_node.rb +8 -0
  204. data/vendor/rkelly/test/test_throw_node.rb +7 -0
  205. data/vendor/rkelly/test/test_tokenizer.rb +148 -0
  206. data/vendor/rkelly/test/test_true_node.rb +8 -0
  207. data/vendor/rkelly/test/test_try_node.rb +59 -0
  208. data/vendor/rkelly/test/test_type_of_node.rb +8 -0
  209. data/vendor/rkelly/test/test_unary_minus_node.rb +8 -0
  210. data/vendor/rkelly/test/test_unary_plus_node.rb +8 -0
  211. data/vendor/rkelly/test/test_unsigned_right_shift_node.rb +8 -0
  212. data/vendor/rkelly/test/test_var_decl_node.rb +21 -0
  213. data/vendor/rkelly/test/test_var_statement_node.rb +14 -0
  214. data/vendor/rkelly/test/test_void_node.rb +8 -0
  215. data/vendor/rkelly/test/test_while_node.rb +15 -0
  216. data/vendor/rkelly/test/test_with_node.rb +8 -0
  217. metadata +271 -0
@@ -0,0 +1,88 @@
1
+ module RKelly
2
+ module Nodes
3
+ class Node
4
+ include RKelly::Visitable
5
+ include RKelly::Visitors
6
+ include Enumerable
7
+
8
+ attr_accessor :value, :comments, :line, :filename
9
+ def initialize(value)
10
+ @value = value
11
+ @comments = []
12
+ @filename = @line = nil
13
+ end
14
+
15
+ def ==(other)
16
+ other.is_a?(self.class) && @value == other.value
17
+ end
18
+ alias :=~ :==
19
+
20
+ def ===(other)
21
+ other.is_a?(self.class) && @value === other.value
22
+ end
23
+
24
+ def pointcut(pattern)
25
+ case pattern
26
+ when String
27
+ ast = RKelly::Parser.new.parse(pattern)
28
+ # Only take the first statement
29
+ finder = ast.value.first.class.to_s =~ /StatementNode$/ ?
30
+ ast.value.first.value : ast.value.first
31
+ visitor = PointcutVisitor.new(finder)
32
+ else
33
+ visitor = PointcutVisitor.new(pattern)
34
+ end
35
+
36
+ visitor.accept(self)
37
+ visitor
38
+ end
39
+ alias :/ :pointcut
40
+
41
+ def to_sexp
42
+ SexpVisitor.new.accept(self)
43
+ end
44
+
45
+ def to_ecma
46
+ ECMAVisitor.new.accept(self)
47
+ end
48
+
49
+ def to_dots
50
+ visitor = DotVisitor.new
51
+ visitor.accept(self)
52
+ header = <<-END
53
+ digraph g {
54
+ graph [ rankdir = "TB" ];
55
+ node [
56
+ fontsize = "16"
57
+ shape = "ellipse"
58
+ ];
59
+ edge [ ];
60
+ END
61
+ nodes = visitor.nodes.map { |x| x.to_s }.join("\n")
62
+ counter = 0
63
+ arrows = visitor.arrows.map { |x|
64
+ s = "#{x} [\nid = #{counter}\n];"
65
+ counter += 1
66
+ s
67
+ }.join("\n")
68
+ "#{header}\n#{nodes}\n#{arrows}\n}"
69
+ end
70
+
71
+ def each(&block)
72
+ EnumerableVisitor.new(block).accept(self)
73
+ end
74
+
75
+ def to_real_sexp
76
+ RealSexpVisitor.new.accept(self)
77
+ end
78
+ end
79
+
80
+ %w[EmptyStatement ExpressionStatement True Delete Return TypeOf
81
+ SourceElements Number LogicalNot AssignExpr FunctionBody
82
+ ObjectLiteral UnaryMinus Throw This BitwiseNot Element String
83
+ Array CaseBlock Null Break Parameter Block False Void Regexp
84
+ Arguments Attr Continue ConstStatement UnaryPlus VarStatement].each do |node|
85
+ eval "class #{node}Node < Node; end"
86
+ end
87
+ end
88
+ end
@@ -0,0 +1,6 @@
1
+ module RKelly
2
+ module Nodes
3
+ class NotStrictEqualNode < BinaryNode
4
+ end
5
+ end
6
+ end
@@ -0,0 +1,16 @@
1
+ module RKelly
2
+ module Nodes
3
+ class OpEqualNode < Node
4
+ attr_reader :left
5
+ def initialize(left, right)
6
+ super(right)
7
+ @left = left
8
+ end
9
+ end
10
+
11
+ %w[Multiply Divide LShift Minus Plus Mod XOr RShift And URShift Or].each do |node|
12
+ eval "class Op#{node}EqualNode < OpEqualNode; end"
13
+ end
14
+
15
+ end
16
+ end
@@ -0,0 +1,11 @@
1
+ module RKelly
2
+ module Nodes
3
+ class PostfixNode < Node
4
+ attr_reader :operand
5
+ def initialize(operand, operator)
6
+ super(operator)
7
+ @operand = operand
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,6 @@
1
+ module RKelly
2
+ module Nodes
3
+ class PrefixNode < PostfixNode
4
+ end
5
+ end
6
+ end
@@ -0,0 +1,13 @@
1
+ module RKelly
2
+ module Nodes
3
+ class PropertyNode < Node
4
+ attr_reader :name
5
+ def initialize(name, value)
6
+ super(value)
7
+ @name = name
8
+ end
9
+ end
10
+
11
+ %w[Getter Setter].each {|node| eval "class #{node}PropertyNode < PropertyNode; end"}
12
+ end
13
+ end
@@ -0,0 +1,19 @@
1
+ module RKelly
2
+ module Nodes
3
+ class ResolveNode < Node
4
+ def ==(other)
5
+ return true if super
6
+ if @value =~ /^[A-Z]/
7
+ place = [Object, Module, RKelly::Nodes].find { |x|
8
+ x.const_defined?(@value.to_sym)
9
+ }
10
+ return false unless place
11
+ klass = place.const_get(@value.to_sym)
12
+ return true if klass && other.is_a?(klass) || other.value.is_a?(klass)
13
+ end
14
+ false
15
+ end
16
+ alias :=~ :==
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,6 @@
1
+ module RKelly
2
+ module Nodes
3
+ class StrictEqualNode < BinaryNode
4
+ end
5
+ end
6
+ end
@@ -0,0 +1,13 @@
1
+ module RKelly
2
+ module Nodes
3
+ class TryNode < Node
4
+ attr_reader :catch_var, :catch_block, :finally_block
5
+ def initialize(value, catch_var, catch_block, finally_block = nil)
6
+ super(value)
7
+ @catch_var = catch_var
8
+ @catch_block = catch_block
9
+ @finally_block = finally_block
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,15 @@
1
+ module RKelly
2
+ module Nodes
3
+ class VarDeclNode < Node
4
+ attr_accessor :name, :type
5
+ def initialize(name, value, constant = false)
6
+ super(value)
7
+ @name = name
8
+ @constant = constant
9
+ end
10
+
11
+ def constant?; @constant; end
12
+ def variable?; !@constant; end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,25 @@
1
+ require 'rkelly/nodes/node'
2
+ require 'rkelly/nodes/function_expr_node'
3
+ require 'rkelly/nodes/binary_node'
4
+ require 'rkelly/nodes/bracket_accessor_node'
5
+ require 'rkelly/nodes/case_clause_node'
6
+ require 'rkelly/nodes/comma_node'
7
+ require 'rkelly/nodes/conditional_node'
8
+ require 'rkelly/nodes/dot_accessor_node'
9
+ require 'rkelly/nodes/for_in_node'
10
+ require 'rkelly/nodes/for_node'
11
+ require 'rkelly/nodes/function_call_node'
12
+ require 'rkelly/nodes/function_decl_node'
13
+ require 'rkelly/nodes/function_expr_node'
14
+ require 'rkelly/nodes/if_node'
15
+ require 'rkelly/nodes/label_node'
16
+ require 'rkelly/nodes/new_expr_node'
17
+ require 'rkelly/nodes/not_strict_equal_node'
18
+ require 'rkelly/nodes/op_equal_node'
19
+ require 'rkelly/nodes/postfix_node'
20
+ require 'rkelly/nodes/prefix_node'
21
+ require 'rkelly/nodes/property_node'
22
+ require 'rkelly/nodes/resolve_node'
23
+ require 'rkelly/nodes/strict_equal_node'
24
+ require 'rkelly/nodes/try_node'
25
+ require 'rkelly/nodes/var_decl_node'
@@ -0,0 +1,104 @@
1
+ require 'rkelly/tokenizer'
2
+ require 'rkelly/generated_parser'
3
+
4
+
5
+ module RKelly
6
+ class Parser < RKelly::GeneratedParser
7
+ TOKENIZER = Tokenizer.new
8
+
9
+ RKelly::GeneratedParser.instance_methods.each do |im|
10
+ next unless im.to_s =~ /^_reduce_\d+$/
11
+ eval(<<-eoawesomehack)
12
+ def #{im}(val, _values, result)
13
+ r = super(val.map { |v|
14
+ v.is_a?(Token) ? v.to_racc_token[1] : v
15
+ }, _values, result)
16
+ if token = val.find { |v| v.is_a?(Token) }
17
+ r.line = token.line if r.respond_to?(:line)
18
+ r.filename = @filename if r.respond_to?(:filename)
19
+ end
20
+ r
21
+ end
22
+ eoawesomehack
23
+ end
24
+
25
+ attr_accessor :logger
26
+ def initialize
27
+ @tokens = []
28
+ @logger = nil
29
+ @terminator = false
30
+ @prev_token = nil
31
+ @comments = []
32
+ end
33
+
34
+ # Parse +javascript+ and return an AST
35
+ def parse(javascript, filename = nil)
36
+ @tokens = TOKENIZER.raw_tokens(javascript)
37
+ @position = 0
38
+ @filename = filename
39
+ ast = do_parse
40
+ apply_comments(ast)
41
+ end
42
+
43
+ def yyabort
44
+ raise "something bad happened, please report a bug with sample JavaScript"
45
+ end
46
+
47
+ private
48
+ def apply_comments(ast)
49
+ ast_hash = Hash.new { |h,k| h[k] = [] }
50
+ (ast || []).each { |n|
51
+ next unless n.line
52
+ ast_hash[n.line] << n
53
+ }
54
+ max = ast_hash.keys.sort.last
55
+ @comments.each do |comment|
56
+ node = nil
57
+ comment.line.upto(max) do |line|
58
+ if ast_hash.key?(line)
59
+ node = ast_hash[line].first
60
+ break
61
+ end
62
+ end
63
+ node.comments << comment if node
64
+ end if max
65
+ ast
66
+ end
67
+
68
+ def on_error(error_token_id, error_value, value_stack)
69
+ if logger
70
+ logger.error(token_to_str(error_token_id))
71
+ logger.error("error value: #{error_value}")
72
+ logger.error("error stack: #{value_stack}")
73
+ end
74
+ end
75
+
76
+ def next_token
77
+ @terminator = false
78
+ begin
79
+ return [false, false] if @position >= @tokens.length
80
+ n_token = @tokens[@position]
81
+ @position += 1
82
+ case @tokens[@position - 1].name
83
+ when :COMMENT
84
+ @comments << n_token
85
+ @terminator = true if n_token.value =~ /^\/\//
86
+ when :S
87
+ @terminator = true if n_token.value =~ /[\r\n]/
88
+ end
89
+ end while([:COMMENT, :S].include?(n_token.name))
90
+
91
+ if @terminator &&
92
+ ((@prev_token && %w[continue break return throw].include?(@prev_token.value)) ||
93
+ (n_token && %w[++ --].include?(n_token.value)))
94
+ @position -= 1
95
+ return (@prev_token = RKelly::Token.new(';', ';')).to_racc_token
96
+ end
97
+
98
+ @prev_token = n_token
99
+ v = n_token.to_racc_token
100
+ v[1] = n_token
101
+ v
102
+ end
103
+ end
104
+ end
@@ -0,0 +1,13 @@
1
+ module RKelly
2
+ class Runtime
3
+ class RubyFunction
4
+ def initialize(&block)
5
+ @code = block
6
+ end
7
+
8
+ def call(chain, *args)
9
+ @code.call(*args)
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,57 @@
1
+ module RKelly
2
+ class Runtime
3
+ class ScopeChain
4
+ include RKelly::JS
5
+
6
+ def initialize(scope = Scope.new)
7
+ @chain = [GlobalObject.new]
8
+ end
9
+
10
+ def <<(scope)
11
+ @chain << scope
12
+ end
13
+
14
+ def has_property?(name)
15
+ scope = @chain.reverse.find { |x|
16
+ x.has_property?(name)
17
+ }
18
+ scope ? scope[name] : nil
19
+ end
20
+
21
+ def [](name)
22
+ property = has_property?(name)
23
+ return property if property
24
+ @chain.last.properties[name]
25
+ end
26
+
27
+ def []=(name, value)
28
+ @chain.last.properties[name] = value
29
+ end
30
+
31
+ def pop
32
+ @chain.pop
33
+ end
34
+
35
+ def this
36
+ @chain.last
37
+ end
38
+
39
+ def new_scope(&block)
40
+ @chain << Scope.new
41
+ result = yield(self)
42
+ @chain.pop
43
+ result
44
+ end
45
+
46
+ def return=(value)
47
+ @chain.last.return = value
48
+ end
49
+
50
+ def return; @chain.last.return; end
51
+
52
+ def returned?
53
+ @chain.last.returned?
54
+ end
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,36 @@
1
+ require 'rkelly/js'
2
+ require 'rkelly/runtime/scope_chain'
3
+
4
+ module RKelly
5
+ class Runtime
6
+ UNDEFINED = RKelly::JS::Property.new(:undefined, :undefined)
7
+
8
+ def initialize
9
+ @parser = Parser.new
10
+ @scope = ScopeChain.new
11
+ end
12
+
13
+ # Execute +js+
14
+ def execute(js)
15
+ function_visitor = Visitors::FunctionVisitor.new(@scope)
16
+ eval_visitor = Visitors::EvaluationVisitor.new(@scope)
17
+ tree = @parser.parse(js)
18
+ function_visitor.accept(tree)
19
+ eval_visitor.accept(tree)
20
+ @scope
21
+ end
22
+
23
+ def call_function(function_name, *args)
24
+ function = @scope[function_name].value
25
+ @scope.new_scope { |chain|
26
+ function.js_call(chain, *(args.map { |x|
27
+ RKelly::JS::Property.new(:param, x)
28
+ }))
29
+ }.value
30
+ end
31
+
32
+ def define_function(function, &block)
33
+ @scope[function.to_s].function = block
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,4 @@
1
+ module RKelly
2
+ class SyntaxError < StandardError
3
+ end
4
+ end
@@ -0,0 +1,15 @@
1
+ module RKelly
2
+ class Token
3
+ attr_accessor :name, :value, :transformer, :line
4
+ def initialize(name, value, &transformer)
5
+ @name = name
6
+ @value = value
7
+ @transformer = transformer
8
+ end
9
+
10
+ def to_racc_token
11
+ return transformer.call(name, value) if transformer
12
+ [name, value]
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,122 @@
1
+ require 'rkelly/lexeme'
2
+
3
+ module RKelly
4
+ class Tokenizer
5
+ KEYWORDS = %w{
6
+ break case catch continue default delete do else finally for function
7
+ if in instanceof new return switch this throw try typeof var void while
8
+ with
9
+
10
+ const true false null debugger
11
+ }
12
+
13
+ RESERVED = %w{
14
+ abstract boolean byte char class double enum export extends
15
+ final float goto implements import int interface long native package
16
+ private protected public short static super synchronized throws
17
+ transient volatile
18
+ }
19
+
20
+ LITERALS = {
21
+ # Punctuators
22
+ '==' => :EQEQ,
23
+ '!=' => :NE,
24
+ '===' => :STREQ,
25
+ '!==' => :STRNEQ,
26
+ '<=' => :LE,
27
+ '>=' => :GE,
28
+ '||' => :OR,
29
+ '&&' => :AND,
30
+ '++' => :PLUSPLUS,
31
+ '--' => :MINUSMINUS,
32
+ '<<' => :LSHIFT,
33
+ '<<=' => :LSHIFTEQUAL,
34
+ '>>' => :RSHIFT,
35
+ '>>=' => :RSHIFTEQUAL,
36
+ '>>>' => :URSHIFT,
37
+ '>>>='=> :URSHIFTEQUAL,
38
+ '&=' => :ANDEQUAL,
39
+ '%=' => :MODEQUAL,
40
+ '^=' => :XOREQUAL,
41
+ '|=' => :OREQUAL,
42
+ '+=' => :PLUSEQUAL,
43
+ '-=' => :MINUSEQUAL,
44
+ '*=' => :MULTEQUAL,
45
+ '/=' => :DIVEQUAL,
46
+ }
47
+
48
+ def initialize(&block)
49
+ @lexemes = []
50
+
51
+ token(:COMMENT, /\A\/(?:\*(?:.)*?\*\/|\/[^\n]*)/m)
52
+ token(:STRING, /\A"(?:[^"\\]*(?:\\.[^"\\]*)*)"|\A'(?:[^'\\]*(?:\\.[^'\\]*)*)'/m)
53
+
54
+ # A regexp to match floating point literals (but not integer literals).
55
+ token(:NUMBER, /\A\d+\.\d*(?:[eE][-+]?\d+)?|\A\d+(?:\.\d*)?[eE][-+]?\d+|\A\.\d+(?:[eE][-+]?\d+)?/m) do |type, value|
56
+ value.gsub!(/\.(\D)/, '.0\1') if value =~ /\.\w/
57
+ value.gsub!(/\.$/, '.0') if value =~ /\.$/
58
+ value.gsub!(/^\./, '0.') if value =~ /^\./
59
+ [type, eval(value)]
60
+ end
61
+ token(:NUMBER, /\A0[xX][\da-fA-F]+|\A0[0-7]*|\A\d+/) do |type, value|
62
+ [type, eval(value)]
63
+ end
64
+
65
+ token(:LITERALS,
66
+ Regexp.new(LITERALS.keys.sort_by { |x|
67
+ x.length
68
+ }.reverse.map { |x| "\\A#{x.gsub(/([|+*^])/, '\\\\\1')}" }.join('|')
69
+ )) do |type, value|
70
+ [LITERALS[value], value]
71
+ end
72
+
73
+ token(:IDENT, /\A([_\$A-Za-z][_\$0-9A-Za-z]*)/) do |type,value|
74
+ if KEYWORDS.include?(value)
75
+ [value.upcase.to_sym, value]
76
+ elsif RESERVED.include?(value)
77
+ [:RESERVED, value]
78
+ else
79
+ [type, value]
80
+ end
81
+ end
82
+
83
+ token(:REGEXP, /\A\/(?:[^\/\r\n\\]*(?:\\[^\r\n][^\/\r\n\\]*)*)\/[gi]*/)
84
+ token(:S, /\A[\s\r\n]*/m)
85
+
86
+ token(:SINGLE_CHAR, /\A./) do |type, value|
87
+ [value, value]
88
+ end
89
+ end
90
+
91
+ def tokenize(string)
92
+ raw_tokens(string).map { |x| x.to_racc_token }
93
+ end
94
+
95
+ def raw_tokens(string)
96
+ tokens = []
97
+ line_number = 1
98
+ while string.length > 0
99
+ longest_token = nil
100
+
101
+ @lexemes.each { |lexeme|
102
+ match = lexeme.match(string)
103
+ next if match.nil?
104
+ longest_token = match if longest_token.nil?
105
+ next if longest_token.value.length >= match.value.length
106
+ longest_token = match
107
+ }
108
+
109
+ longest_token.line = line_number
110
+ line_number += longest_token.value.scan(/\n/).length
111
+ string = string.slice(Range.new(longest_token.value.length, -1))
112
+ tokens << longest_token
113
+ end
114
+ tokens
115
+ end
116
+
117
+ private
118
+ def token(name, pattern = nil, &block)
119
+ @lexemes << Lexeme.new(name, pattern, &block)
120
+ end
121
+ end
122
+ end
@@ -0,0 +1,16 @@
1
+ module RKelly
2
+ module Visitable
3
+ # Based off the visitor pattern from RubyGarden
4
+ def accept(visitor, &block)
5
+ klass = self.class.ancestors.find { |ancestor|
6
+ visitor.respond_to?("visit_#{ancestor.name.split(/::/)[-1]}")
7
+ }
8
+
9
+ if klass
10
+ visitor.send(:"visit_#{klass.name.split(/::/)[-1]}", self, &block)
11
+ else
12
+ raise "No visitor for '#{self.class}'"
13
+ end
14
+ end
15
+ end
16
+ end