rkelly-turbo 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 (205) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.rdoc +38 -0
  3. data/Manifest.txt +203 -0
  4. data/README.rdoc +135 -0
  5. data/Rakefile +41 -0
  6. data/lib/parser.y +883 -0
  7. data/lib/rkelly.rb +14 -0
  8. data/lib/rkelly/char_pos.rb +39 -0
  9. data/lib/rkelly/char_range.rb +33 -0
  10. data/lib/rkelly/constants.rb +3 -0
  11. data/lib/rkelly/generated_parser.rb +3380 -0
  12. data/lib/rkelly/js.rb +14 -0
  13. data/lib/rkelly/js/array.rb +15 -0
  14. data/lib/rkelly/js/base.rb +91 -0
  15. data/lib/rkelly/js/boolean.rb +21 -0
  16. data/lib/rkelly/js/function.rb +39 -0
  17. data/lib/rkelly/js/function_prototype.rb +15 -0
  18. data/lib/rkelly/js/global_object.rb +52 -0
  19. data/lib/rkelly/js/math.rb +10 -0
  20. data/lib/rkelly/js/nan.rb +18 -0
  21. data/lib/rkelly/js/number.rb +22 -0
  22. data/lib/rkelly/js/object.rb +30 -0
  23. data/lib/rkelly/js/object_prototype.rb +14 -0
  24. data/lib/rkelly/js/property.rb +20 -0
  25. data/lib/rkelly/js/scope.rb +6 -0
  26. data/lib/rkelly/js/string.rb +21 -0
  27. data/lib/rkelly/lexeme.rb +18 -0
  28. data/lib/rkelly/nodes.rb +25 -0
  29. data/lib/rkelly/nodes/binary_node.rb +18 -0
  30. data/lib/rkelly/nodes/bracket_accessor_node.rb +11 -0
  31. data/lib/rkelly/nodes/case_clause_node.rb +11 -0
  32. data/lib/rkelly/nodes/comma_node.rb +11 -0
  33. data/lib/rkelly/nodes/conditional_node.rb +11 -0
  34. data/lib/rkelly/nodes/dot_accessor_node.rb +11 -0
  35. data/lib/rkelly/nodes/for_in_node.rb +12 -0
  36. data/lib/rkelly/nodes/for_node.rb +13 -0
  37. data/lib/rkelly/nodes/function_call_node.rb +16 -0
  38. data/lib/rkelly/nodes/function_decl_node.rb +6 -0
  39. data/lib/rkelly/nodes/function_expr_node.rb +12 -0
  40. data/lib/rkelly/nodes/if_node.rb +12 -0
  41. data/lib/rkelly/nodes/label_node.rb +11 -0
  42. data/lib/rkelly/nodes/new_expr_node.rb +11 -0
  43. data/lib/rkelly/nodes/node.rb +116 -0
  44. data/lib/rkelly/nodes/not_strict_equal_node.rb +6 -0
  45. data/lib/rkelly/nodes/op_equal_node.rb +16 -0
  46. data/lib/rkelly/nodes/postfix_node.rb +11 -0
  47. data/lib/rkelly/nodes/prefix_node.rb +6 -0
  48. data/lib/rkelly/nodes/property_node.rb +13 -0
  49. data/lib/rkelly/nodes/resolve_node.rb +19 -0
  50. data/lib/rkelly/nodes/strict_equal_node.rb +6 -0
  51. data/lib/rkelly/nodes/try_node.rb +13 -0
  52. data/lib/rkelly/nodes/var_decl_node.rb +15 -0
  53. data/lib/rkelly/parser.rb +106 -0
  54. data/lib/rkelly/runtime.rb +36 -0
  55. data/lib/rkelly/runtime/ruby_function.rb +13 -0
  56. data/lib/rkelly/runtime/scope_chain.rb +57 -0
  57. data/lib/rkelly/syntax_error.rb +4 -0
  58. data/lib/rkelly/token.rb +27 -0
  59. data/lib/rkelly/tokenizer.rb +255 -0
  60. data/lib/rkelly/visitable.rb +31 -0
  61. data/lib/rkelly/visitors.rb +4 -0
  62. data/lib/rkelly/visitors/dot_visitor.rb +228 -0
  63. data/lib/rkelly/visitors/ecma_visitor.rb +328 -0
  64. data/lib/rkelly/visitors/enumerable_visitor.rb +18 -0
  65. data/lib/rkelly/visitors/evaluation_visitor.rb +419 -0
  66. data/lib/rkelly/visitors/function_visitor.rb +46 -0
  67. data/lib/rkelly/visitors/pointcut_visitor.rb +31 -0
  68. data/lib/rkelly/visitors/real_sexp_visitor.rb +16 -0
  69. data/lib/rkelly/visitors/sexp_visitor.rb +373 -0
  70. data/lib/rkelly/visitors/visitor.rb +149 -0
  71. data/test/ecma_script_test_case.rb +21 -0
  72. data/test/execute_test_case.rb +16 -0
  73. data/test/execution_contexts/test_10_1_3-1.rb +32 -0
  74. data/test/expressions/test_11_3_1.rb +64 -0
  75. data/test/expressions/test_11_3_2.rb +64 -0
  76. data/test/expressions/test_11_4_2.rb +13 -0
  77. data/test/expressions/test_11_4_3.rb +52 -0
  78. data/test/expressions/test_11_4_4.rb +68 -0
  79. data/test/expressions/test_11_4_5.rb +69 -0
  80. data/test/expressions/test_11_4_6.rb +94 -0
  81. data/test/expressions/test_11_4_8.rb +28 -0
  82. data/test/expressions/test_11_4_9.rb +103 -0
  83. data/test/expressions/test_11_5_1.rb +51 -0
  84. data/test/expressions/test_11_5_2.rb +80 -0
  85. data/test/expressions/test_11_5_3.rb +88 -0
  86. data/test/expressions/test_11_6_1-1.rb +19 -0
  87. data/test/expressions/test_11_9_1.rb +19 -0
  88. data/test/function/test_15_3_1_1-1.rb +34 -0
  89. data/test/global_object/test_15_1_1_1.rb +29 -0
  90. data/test/global_object/test_15_1_1_2.rb +17 -0
  91. data/test/global_object/test_15_1_1_3.rb +9 -0
  92. data/test/helper.rb +5 -0
  93. data/test/node_test_case.rb +11 -0
  94. data/test/object/test_15_2_1_1.rb +257 -0
  95. data/test/object/test_15_2_1_2.rb +21 -0
  96. data/test/object/test_15_2_2_1.rb +52 -0
  97. data/test/statements/test_12_5-1.rb +27 -0
  98. data/test/test_add_node.rb +8 -0
  99. data/test/test_arguments_node.rb +8 -0
  100. data/test/test_array_node.rb +9 -0
  101. data/test/test_assign_expr_node.rb +8 -0
  102. data/test/test_automatic_semicolon_insertion.rb +137 -0
  103. data/test/test_bit_and_node.rb +8 -0
  104. data/test/test_bit_or_node.rb +8 -0
  105. data/test/test_bit_x_or_node.rb +8 -0
  106. data/test/test_bitwise_not_node.rb +8 -0
  107. data/test/test_block_node.rb +14 -0
  108. data/test/test_bracket_accessor_node.rb +16 -0
  109. data/test/test_break_node.rb +11 -0
  110. data/test/test_case_block_node.rb +11 -0
  111. data/test/test_case_clause_node.rb +15 -0
  112. data/test/test_char_pos.rb +39 -0
  113. data/test/test_char_range.rb +29 -0
  114. data/test/test_comma_node.rb +13 -0
  115. data/test/test_comments.rb +45 -0
  116. data/test/test_conditional_node.rb +17 -0
  117. data/test/test_const_statement_node.rb +14 -0
  118. data/test/test_continue_node.rb +11 -0
  119. data/test/test_delete_node.rb +8 -0
  120. data/test/test_divide_node.rb +8 -0
  121. data/test/test_do_while_node.rb +13 -0
  122. data/test/test_dot_accessor_node.rb +9 -0
  123. data/test/test_ecma_visitor.rb +213 -0
  124. data/test/test_element_node.rb +8 -0
  125. data/test/test_empty_statement_node.rb +8 -0
  126. data/test/test_equal_node.rb +8 -0
  127. data/test/test_evaluation_visitor.rb +66 -0
  128. data/test/test_expression_statement_node.rb +10 -0
  129. data/test/test_false_node.rb +8 -0
  130. data/test/test_for_in_node.rb +17 -0
  131. data/test/test_for_node.rb +24 -0
  132. data/test/test_function_body_node.rb +8 -0
  133. data/test/test_function_call_node.rb +10 -0
  134. data/test/test_function_decl_node.rb +16 -0
  135. data/test/test_function_expr_node.rb +16 -0
  136. data/test/test_function_visitor.rb +26 -0
  137. data/test/test_getter_property_node.rb +10 -0
  138. data/test/test_global_object.rb +49 -0
  139. data/test/test_greater_node.rb +8 -0
  140. data/test/test_greater_or_equal_node.rb +8 -0
  141. data/test/test_if_node.rb +17 -0
  142. data/test/test_in_node.rb +8 -0
  143. data/test/test_instance_of_node.rb +8 -0
  144. data/test/test_label_node.rb +13 -0
  145. data/test/test_left_shift_node.rb +8 -0
  146. data/test/test_less_node.rb +8 -0
  147. data/test/test_less_or_equal_node.rb +8 -0
  148. data/test/test_line_number.rb +81 -0
  149. data/test/test_logical_and_node.rb +8 -0
  150. data/test/test_logical_not_node.rb +8 -0
  151. data/test/test_logical_or_node.rb +8 -0
  152. data/test/test_modulus_node.rb +8 -0
  153. data/test/test_multiply_node.rb +8 -0
  154. data/test/test_new_expr_node.rb +9 -0
  155. data/test/test_not_equal_node.rb +8 -0
  156. data/test/test_not_strict_equal_node.rb +8 -0
  157. data/test/test_null_node.rb +8 -0
  158. data/test/test_number_node.rb +8 -0
  159. data/test/test_object_literal_node.rb +9 -0
  160. data/test/test_op_and_equal_node.rb +10 -0
  161. data/test/test_op_divide_equal_node.rb +10 -0
  162. data/test/test_op_equal_node.rb +10 -0
  163. data/test/test_op_l_shift_equal_node.rb +10 -0
  164. data/test/test_op_minus_equal_node.rb +10 -0
  165. data/test/test_op_mod_equal_node.rb +10 -0
  166. data/test/test_op_multiply_equal_node.rb +10 -0
  167. data/test/test_op_or_equal_node.rb +10 -0
  168. data/test/test_op_plus_equal_node.rb +10 -0
  169. data/test/test_op_r_shift_equal_node.rb +10 -0
  170. data/test/test_op_u_r_shift_equal_node.rb +10 -0
  171. data/test/test_op_x_or_equal_node.rb +10 -0
  172. data/test/test_parameter_node.rb +8 -0
  173. data/test/test_parser.rb +1434 -0
  174. data/test/test_pointcut_visitor.rb +34 -0
  175. data/test/test_postfix_node.rb +8 -0
  176. data/test/test_prefix_node.rb +8 -0
  177. data/test/test_property_node.rb +8 -0
  178. data/test/test_regexp_node.rb +8 -0
  179. data/test/test_resolve_node.rb +22 -0
  180. data/test/test_return_node.rb +11 -0
  181. data/test/test_right_shift_node.rb +8 -0
  182. data/test/test_rkelly.rb +19 -0
  183. data/test/test_runtime.rb +12 -0
  184. data/test/test_scope_chain.rb +50 -0
  185. data/test/test_setter_property_node.rb +10 -0
  186. data/test/test_source_elements.rb +9 -0
  187. data/test/test_strict_equal_node.rb +8 -0
  188. data/test/test_string_node.rb +8 -0
  189. data/test/test_subtract_node.rb +8 -0
  190. data/test/test_switch_node.rb +12 -0
  191. data/test/test_this_node.rb +8 -0
  192. data/test/test_throw_node.rb +7 -0
  193. data/test/test_tokenizer.rb +285 -0
  194. data/test/test_true_node.rb +8 -0
  195. data/test/test_try_node.rb +59 -0
  196. data/test/test_type_of_node.rb +8 -0
  197. data/test/test_unary_minus_node.rb +8 -0
  198. data/test/test_unary_plus_node.rb +8 -0
  199. data/test/test_unsigned_right_shift_node.rb +8 -0
  200. data/test/test_var_decl_node.rb +21 -0
  201. data/test/test_var_statement_node.rb +14 -0
  202. data/test/test_void_node.rb +8 -0
  203. data/test/test_while_node.rb +15 -0
  204. data/test/test_with_node.rb +8 -0
  205. metadata +293 -0
@@ -0,0 +1,18 @@
1
+ module RKelly
2
+ module Nodes
3
+ class BinaryNode < Node
4
+ attr_reader :left
5
+ def initialize(left, right)
6
+ super(right)
7
+ @left = left
8
+ end
9
+ end
10
+
11
+ %w[Subtract LessOrEqual GreaterOrEqual Add Multiply NotEqual
12
+ DoWhile Switch LogicalAnd UnsignedRightShift Modulus While
13
+ NotStrictEqual Less With In Greater BitOr StrictEqual LogicalOr
14
+ BitXOr LeftShift Equal BitAnd InstanceOf Divide RightShift].each do |node|
15
+ const_set "#{node}Node", Class.new(BinaryNode)
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,11 @@
1
+ module RKelly
2
+ module Nodes
3
+ class BracketAccessorNode < Node
4
+ attr_reader :accessor
5
+ def initialize(resolve, accessor)
6
+ super(resolve)
7
+ @accessor = accessor
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ require 'rkelly/nodes/binary_node'
2
+
3
+ module RKelly
4
+ module Nodes
5
+ class CaseClauseNode < BinaryNode
6
+ def initialize(left, src = SourceElementsNode.new([]))
7
+ super
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ module RKelly
2
+ module Nodes
3
+ class CommaNode < Node
4
+ attr_reader :left
5
+ def initialize(left, right)
6
+ super(right)
7
+ @left = left
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ require 'rkelly/nodes/if_node'
2
+
3
+ module RKelly
4
+ module Nodes
5
+ class ConditionalNode < IfNode
6
+ def initialize(test, true_block, else_block)
7
+ super
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ module RKelly
2
+ module Nodes
3
+ class DotAccessorNode < Node
4
+ attr_reader :accessor
5
+ def initialize(resolve, accessor)
6
+ super(resolve)
7
+ @accessor = accessor
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,12 @@
1
+ module RKelly
2
+ module Nodes
3
+ class ForInNode < Node
4
+ attr_reader :left, :right
5
+ def initialize(left, right, block)
6
+ super(block)
7
+ @left = left
8
+ @right = right
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,13 @@
1
+ module RKelly
2
+ module Nodes
3
+ class ForNode < Node
4
+ attr_reader :init, :test, :counter
5
+ def initialize(init, test, counter, body)
6
+ super(body)
7
+ @init = init
8
+ @test = test
9
+ @counter = counter
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,16 @@
1
+ module RKelly
2
+ module Nodes
3
+ class FunctionCallNode < Node
4
+ attr_reader :arguments
5
+ def initialize(value, arguments)
6
+ super(value)
7
+ @arguments = arguments
8
+ end
9
+
10
+ def ==(other)
11
+ super && @arguments == other.arguments
12
+ end
13
+ alias :=~ :==
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,6 @@
1
+ module RKelly
2
+ module Nodes
3
+ class FunctionDeclNode < FunctionExprNode
4
+ end
5
+ end
6
+ end
@@ -0,0 +1,12 @@
1
+ module RKelly
2
+ module Nodes
3
+ class FunctionExprNode < Node
4
+ attr_reader :function_body, :arguments
5
+ def initialize(name, body, args = [])
6
+ super(name)
7
+ @function_body = body
8
+ @arguments = args
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,12 @@
1
+ module RKelly
2
+ module Nodes
3
+ class IfNode < Node
4
+ attr_reader :conditions, :else
5
+ def initialize(conditions, value, else_stmt = nil)
6
+ super(value)
7
+ @conditions = conditions
8
+ @else = else_stmt
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,11 @@
1
+ module RKelly
2
+ module Nodes
3
+ class LabelNode < Node
4
+ attr_reader :name
5
+ def initialize(name, value)
6
+ super(value)
7
+ @name = name
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ module RKelly
2
+ module Nodes
3
+ class NewExprNode < Node
4
+ attr_reader :arguments
5
+ def initialize(value, args)
6
+ super(value)
7
+ @arguments = args
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,116 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RKelly
4
+ module Nodes
5
+ class Node
6
+ include RKelly::Visitable
7
+ include RKelly::Visitors
8
+ include Enumerable
9
+
10
+ attr_accessor :value, :comments, :range, :filename
11
+ def initialize(value)
12
+ @value = value
13
+ @range = CharRange::EMPTY
14
+ end
15
+
16
+ def comments; @comments || []; end
17
+
18
+ # For backwards compatibility
19
+ def line
20
+ @range.from.line
21
+ end
22
+
23
+ def ==(other)
24
+ other.is_a?(self.class) && @value == other.value
25
+ end
26
+ alias :=~ :==
27
+
28
+ def ===(other)
29
+ other.is_a?(self.class) && @value === other.value
30
+ end
31
+
32
+ # Matches nodes with the given pattern (usually a class name of
33
+ # the node) and returns an instance of PointcutVisitor on which
34
+ # #matches can be invoked to get the list of AST nodes that
35
+ # matched.
36
+ #
37
+ # ast.pointcut(RKelly::Nodes::IfNode).matches --> array of nodes
38
+ #
39
+ def pointcut(pattern)
40
+ case pattern
41
+ when String
42
+ ast = RKelly::Parser.new.parse(pattern)
43
+ # Only take the first statement
44
+ finder = ast.value.first.class.name.end_with?("StatementNode") ?
45
+ ast.value.first.value : ast.value.first
46
+ visitor = PointcutVisitor.new(finder)
47
+ else
48
+ visitor = PointcutVisitor.new(pattern)
49
+ end
50
+
51
+ visitor.accept(self)
52
+ visitor
53
+ end
54
+ alias :/ :pointcut
55
+
56
+ # Generates an s-expression data structure like so:
57
+ #
58
+ # "var x = 10;" --> [:var, [[:var_decl, :x, [:assign, [:lit, 10]]]]]]
59
+ #
60
+ def to_sexp
61
+ SexpVisitor.new.accept(self)
62
+ end
63
+
64
+ # Generates formatted and intented JavaScript source code.
65
+ def to_ecma
66
+ ECMAVisitor.new.accept(self)
67
+ end
68
+
69
+ # Generates a graph description in DOT language. This can be
70
+ # fed into the dot program to generate a graph of the AST:
71
+ #
72
+ # $ dot -Tpng generated-graph.dot -o graph.png
73
+ #
74
+ def to_dots
75
+ visitor = DotVisitor.new
76
+ visitor.accept(self)
77
+ header = <<-END
78
+ digraph g {
79
+ graph [ rankdir = "TB" ];
80
+ node [
81
+ fontsize = "16"
82
+ shape = "ellipse"
83
+ ];
84
+ edge [ ];
85
+ END
86
+ nodes = visitor.nodes.map { |x| x.to_s }.join("\n")
87
+ counter = 0
88
+ arrows = visitor.arrows.map { |x|
89
+ s = "#{x} [\nid = #{counter}\n];"
90
+ counter += 1
91
+ s
92
+ }.join("\n")
93
+ "#{header}\n#{nodes}\n#{arrows}\n}"
94
+ end
95
+
96
+ # Loops through all the syntax nodes.
97
+ def each(&block)
98
+ EnumerableVisitor.new(block).accept(self)
99
+ end
100
+
101
+ # This CRASHES!
102
+ # It calls method #s which is nowhere to be found.
103
+ def to_real_sexp
104
+ RealSexpVisitor.new.accept(self)
105
+ end
106
+ end
107
+
108
+ %w[EmptyStatement Parenthetical ExpressionStatement True Delete Return TypeOf
109
+ SourceElements Number LogicalNot AssignExpr FunctionBody
110
+ ObjectLiteral UnaryMinus Throw This BitwiseNot Element String
111
+ Array CaseBlock Null Break Parameter Block False Void Regexp
112
+ Arguments Attr Continue ConstStatement UnaryPlus VarStatement].each do |node|
113
+ eval "class #{node}Node < Node; end"
114
+ end
115
+ end
116
+ 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 ('A'..'Z').include? @value[0]
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,106 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rkelly/tokenizer'
4
+ require 'rkelly/generated_parser'
5
+
6
+
7
+ module RKelly
8
+ class Parser < RKelly::GeneratedParser
9
+ TOKENIZER = Tokenizer.new
10
+
11
+ RKelly::GeneratedParser.instance_methods.each do |im|
12
+ next unless im.to_s =~ /^_reduce_\d+$/
13
+ define_method im do |val, _values, result|
14
+ r = super(val.map { |v|
15
+ v.is_a?(Token) ? v.to_racc_token[1] : v
16
+ }, _values, result)
17
+
18
+ if r.respond_to? :range
19
+ suitable_values = val.flatten.find_all {|v| v.is_a? Token or v.is_a? Node }
20
+ first = suitable_values.first
21
+ if first
22
+ r.range = CharRange.new(first.range.from, suitable_values.last.range.to)
23
+ r.filename = @filename if @filename
24
+ end
25
+ end
26
+ r
27
+ end
28
+ end
29
+
30
+ attr_accessor :logger
31
+ def initialize
32
+ @tokens = []
33
+ @logger = nil
34
+ @terminator = false
35
+ @prev_token = nil
36
+ @comments = []
37
+ end
38
+
39
+ # Parse +javascript+ and return an AST
40
+ def parse(javascript, filename = nil)
41
+ @tokens = TOKENIZER.raw_tokens(javascript)
42
+ @position = 0
43
+ @filename = filename
44
+ ast = do_parse
45
+ ast.comments = @comments if ast
46
+ ast
47
+ end
48
+
49
+ def yyabort
50
+ raise "something bad happened, please report a bug with sample JavaScript"
51
+ end
52
+
53
+ # When parsing finishes without all tokens being parsed, returns
54
+ # the token at which the parsing stopped. Returns nil when parser
55
+ # reached to the very last token (but possibly still failed as it
56
+ # expeced more tokens).
57
+ #
58
+ # Useful for pin-pointing the position of a syntax error.
59
+ def stopped_at
60
+ if @position < @tokens.length
61
+ @tokens[@position-1]
62
+ else
63
+ nil
64
+ end
65
+ end
66
+
67
+ private
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
+ SEMICOLON_TOKEN = RKelly::Token.new(';', ';').freeze
77
+
78
+ def next_token
79
+ @terminator = false
80
+ begin
81
+ return [false, false] if @position >= @tokens.length
82
+ n_token = @tokens[@position]
83
+ @position += 1
84
+ case @tokens[@position - 1].name
85
+ when :COMMENT
86
+ @comments << n_token
87
+ @terminator = true if n_token.value.start_with? "//"
88
+ when :S
89
+ @terminator = true if n_token.value =~ /[\r\n]/
90
+ end
91
+ end while([:COMMENT, :S].include?(n_token.name))
92
+
93
+ if @terminator &&
94
+ ((@prev_token && %w[continue break return throw].include?(@prev_token.value)) ||
95
+ (n_token && %w[++ --].include?(n_token.value)))
96
+ @position -= 1
97
+ return (@prev_token = SEMICOLON_TOKEN.dup).to_racc_token
98
+ end
99
+
100
+ @prev_token = n_token
101
+ v = n_token.to_racc_token
102
+ v[1] = n_token
103
+ v
104
+ end
105
+ end
106
+ end