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
data/lib/rkelly.rb ADDED
@@ -0,0 +1,8 @@
1
+ require 'rkelly/constants'
2
+ require 'rkelly/visitable'
3
+ require 'rkelly/visitors'
4
+ require 'rkelly/parser'
5
+ require 'rkelly/runtime'
6
+
7
+ module RKelly
8
+ end
@@ -0,0 +1,3 @@
1
+ module RKelly
2
+ VERSION = '0.0.0'
3
+ end
data/lib/rkelly/js.rb ADDED
@@ -0,0 +1,14 @@
1
+ require 'rkelly/js/nan'
2
+ require 'rkelly/js/property'
3
+ require 'rkelly/js/base'
4
+ require 'rkelly/js/global_object'
5
+ require 'rkelly/js/object'
6
+ require 'rkelly/js/object_prototype'
7
+ require 'rkelly/js/function_prototype'
8
+ require 'rkelly/js/array'
9
+ require 'rkelly/js/boolean'
10
+ require 'rkelly/js/math'
11
+ require 'rkelly/js/number'
12
+ require 'rkelly/js/string'
13
+ require 'rkelly/js/scope'
14
+ require 'rkelly/js/function'
@@ -0,0 +1,15 @@
1
+ module RKelly
2
+ module JS
3
+ class Array < Base
4
+ class << self
5
+ def create(*args)
6
+ self.new(*args)
7
+ end
8
+ end
9
+
10
+ def initialize(*args)
11
+ super()
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,91 @@
1
+ module RKelly
2
+ module JS
3
+ class Base
4
+ attr_reader :properties, :return, :value
5
+ def initialize
6
+ @properties = Hash.new { |h,k|
7
+ h[k] = Property.new(k, :undefined, self)
8
+ }
9
+ @return = nil
10
+ @returned = false
11
+ @value = self
12
+ self['Class'] = self.class.to_s.split('::').last
13
+ end
14
+
15
+ def [](name)
16
+ return self.properties[name] if has_property?(name)
17
+ if self.properties['prototype'].value != :undefined
18
+ self.properties['prototype'].value[name]
19
+ else
20
+ RKelly::Runtime::UNDEFINED
21
+ end
22
+ end
23
+
24
+ def []=(name, value)
25
+ return unless can_put?(name)
26
+ if has_property?(name)
27
+ self.properties[name].value = value
28
+ else
29
+ self.properties[name] = Property.new(name, value, self)
30
+ end
31
+ end
32
+
33
+ def can_put?(name)
34
+ if !has_property?(name)
35
+ return true if self.properties['prototype'].nil?
36
+ return true if self.properties['prototype'].value.nil?
37
+ return true if self.properties['prototype'].value == :undefined
38
+ return self.properties['prototype'].value.can_put?(name)
39
+ end
40
+ !self.properties[name].read_only?
41
+ end
42
+
43
+ def has_property?(name)
44
+ return true if self.properties.has_key?(name)
45
+ return false if self.properties['prototype'].nil?
46
+ return false if self.properties['prototype'].value.nil?
47
+ return false if self.properties['prototype'].value == :undefined
48
+ self.properties['prototype'].value.has_property?(name)
49
+ end
50
+
51
+ def delete(name)
52
+ return true unless has_property?(name)
53
+ return false if self.properties[name].dont_delete?
54
+ self.properties.delete(name)
55
+ true
56
+ end
57
+
58
+ def default_value(hint)
59
+ case hint
60
+ when 'Number'
61
+ value_of = self['valueOf']
62
+ if value_of.function || value_of.value.is_a?(RKelly::JS::Function)
63
+ return value_of
64
+ end
65
+ to_string = self['toString']
66
+ if to_string.function || to_string.value.is_a?(RKelly::JS::Function)
67
+ return to_string
68
+ end
69
+ end
70
+ end
71
+
72
+ def return=(value)
73
+ @returned = true
74
+ @return = value
75
+ end
76
+
77
+ def returned?; @returned; end
78
+
79
+ private
80
+ def unbound_method(name, object_id = nil, &block)
81
+ name = "#{name}_#{self.class.to_s.split('::').last}_#{object_id}"
82
+ unless RKelly::JS::Base.instance_methods.include?(name.to_sym)
83
+ RKelly::JS::Base.class_eval do
84
+ define_method(name, &block)
85
+ end
86
+ end
87
+ RKelly::JS::Base.instance_method(name)
88
+ end
89
+ end
90
+ end
91
+ end
@@ -0,0 +1,21 @@
1
+ module RKelly
2
+ module JS
3
+ class Boolean < Base
4
+ class << self
5
+ def create(*args)
6
+ return false if args.length == 0
7
+ self.new(args.first)
8
+ end
9
+ end
10
+ def initialize(*args)
11
+ super()
12
+ value = args.first.nil? ? false : args.first
13
+ self['valueOf'] = value
14
+ self['valueOf'].function = lambda {
15
+ value
16
+ }
17
+ self['toString'] = args.first.to_s
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,39 @@
1
+ module RKelly
2
+ module JS
3
+ class Function < Base
4
+ class << self
5
+ def create(*args)
6
+ if args.length > 0
7
+ parser = RKelly::Parser.new
8
+ body = args.pop
9
+ tree = parser.parse("function x(#{args.join(',')}) { #{body} }")
10
+ func = tree.value.first
11
+ self.new(func.function_body, func.arguments)
12
+ else
13
+ self.new
14
+ end
15
+ end
16
+ end
17
+
18
+ attr_reader :body, :arguments
19
+ def initialize(body = nil, arguments = [])
20
+ super()
21
+ @body = body
22
+ @arguments = arguments
23
+ self['prototype'] = JS::FunctionPrototype.new(self)
24
+ self['toString'] = :undefined
25
+ self['length'] = arguments.length
26
+ end
27
+
28
+ def js_call(scope_chain, *params)
29
+ arguments.each_with_index { |name, i|
30
+ scope_chain[name.value] = params[i] || RKelly::Runtime::UNDEFINED
31
+ }
32
+ function_visitor = RKelly::Visitors::FunctionVisitor.new(scope_chain)
33
+ eval_visitor = RKelly::Visitors::EvaluationVisitor.new(scope_chain)
34
+ body.accept(function_visitor) if body
35
+ body.accept(eval_visitor) if body
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,15 @@
1
+ module RKelly
2
+ module JS
3
+ # This is the object protytpe
4
+ # ECMA-262 15.2.4
5
+ class FunctionPrototype < ObjectPrototype
6
+ def initialize(function)
7
+ super()
8
+ self['Class'] = 'Object'
9
+ self['constructor'] = function
10
+ self['arguments'].value = nil
11
+ end
12
+ end
13
+ end
14
+ end
15
+
@@ -0,0 +1,52 @@
1
+ module RKelly
2
+ module JS
3
+ class GlobalObject < Base
4
+ def initialize
5
+ super
6
+ self['class'] = 'GlobalObject'
7
+ self['NaN'] = JS::NaN.new
8
+ self['NaN'].attributes << :dont_enum
9
+ self['NaN'].attributes << :dont_delete
10
+
11
+ self['Infinity'] = 1.0/0.0
12
+ self['Infinity'].attributes << :dont_enum
13
+ self['Infinity'].attributes << :dont_delete
14
+
15
+ self['undefined'] = :undefined
16
+ self['undefined'].attributes << :dont_enum
17
+ self['undefined'].attributes << :dont_delete
18
+
19
+ self['Array'] = JS::Array.new
20
+ self['Array'].function = lambda { |*args|
21
+ JS::Array.create(*args)
22
+ }
23
+
24
+ self['Object'] = JS::Object.new
25
+ self['Object'].function = lambda { |*args|
26
+ JS::Object.create(*args)
27
+ }
28
+
29
+ self['Math'] = JS::Math.new
30
+
31
+ self['Function'] = :undefined
32
+ self['Function'].function = lambda { |*args|
33
+ JS::Function.create(*args)
34
+ }
35
+
36
+ self['Number'] = JS::Number.new
37
+ self['Number'].function = lambda { |*args|
38
+ JS::Number.create(*args)
39
+ }
40
+
41
+ self['Boolean'] = JS::Boolean.new
42
+ self['Boolean'].function = lambda { |*args|
43
+ JS::Boolean.create(*args)
44
+ }
45
+ self['String'] = JS::String.new('')
46
+ self['String'].function = lambda { |*args|
47
+ JS::String.create(*args)
48
+ }
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,10 @@
1
+ module RKelly
2
+ module JS
3
+ class Math < Base
4
+ def initialize
5
+ super
6
+ self['PI'] = ::Math::PI
7
+ end
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,18 @@
1
+ module RKelly
2
+ module JS
3
+ # Class to represent Not A Number
4
+ # In Ruby NaN != NaN, but in JS, NaN == NaN
5
+ class NaN < ::Numeric
6
+ def ==(other)
7
+ other.respond_to?(:nan?) && other.nan?
8
+ end
9
+
10
+ def nan?
11
+ true
12
+ end
13
+
14
+ def +(o); self; end
15
+ def -(o); self; end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,22 @@
1
+ module RKelly
2
+ module JS
3
+ class Number < Base
4
+ class << self
5
+ def create(*args)
6
+ self.new(args.first || 0)
7
+ end
8
+ end
9
+
10
+ def initialize(value = 0)
11
+ super()
12
+ self['MAX_VALUE'] = 1.797693134862315e+308
13
+ self['MIN_VALUE'] = 1.0e-306
14
+ self['NaN'] = JS::NaN.new
15
+ self['POSITIVE_INFINITY'] = 1.0/0.0
16
+ self['NEGATIVE_INFINITY'] = -1.0/0.0
17
+ self['valueOf'] = lambda { value }
18
+ self['toString'] = value.to_s
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,30 @@
1
+ module RKelly
2
+ module JS
3
+ class Object < Base
4
+ attr_reader :value
5
+ class << self
6
+ def create(*args)
7
+ arg = args.first
8
+ return self.new if arg.nil? || arg == :undefined
9
+ case arg
10
+ when true, false
11
+ JS::Boolean.new(arg)
12
+ when Numeric
13
+ JS::Number.new(arg)
14
+ when ::String
15
+ JS::String.new(arg)
16
+ else
17
+ self.new(arg)
18
+ end
19
+ end
20
+ end
21
+
22
+ def initialize(*args)
23
+ super()
24
+ self['prototype'] = JS::ObjectPrototype.new
25
+ self['valueOf'] = lambda { args.first || self }
26
+ self['valueOf'].function = lambda { args.first || self }
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,14 @@
1
+ module RKelly
2
+ module JS
3
+ # This is the object protytpe
4
+ # ECMA-262 15.2.4
5
+ class ObjectPrototype < Base
6
+ def initialize
7
+ super
8
+ self['toString'].function = unbound_method(:toString) do
9
+ "[object #{self['Class'].value}]"
10
+ end
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,20 @@
1
+ module RKelly
2
+ module JS
3
+ class Property
4
+ attr_accessor :name, :value, :attributes, :function, :binder
5
+ def initialize(name, value, binder = nil, function = nil, attributes = [])
6
+ @name = name
7
+ @value = value
8
+ @binder = binder
9
+ @function = function
10
+ @attributes = attributes
11
+ end
12
+
13
+ [:read_only, :dont_enum, :dont_delete, :internal].each do |property|
14
+ define_method(:"#{property}?") do
15
+ self.attributes.include?(property)
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,6 @@
1
+ module RKelly
2
+ module JS
3
+ class Scope < Base
4
+ end
5
+ end
6
+ end
@@ -0,0 +1,21 @@
1
+ module RKelly
2
+ module JS
3
+ class String < Base
4
+ class << self
5
+ def create(*args)
6
+ self.new(args.first || '')
7
+ end
8
+ end
9
+
10
+ def initialize(value)
11
+ super()
12
+ self['valueOf'] = value
13
+ self['valueOf'].function = lambda { value }
14
+ self['toString'] = value
15
+ self['fromCharCode'] = unbound_method(:fromCharCode) { |*args|
16
+ args.map { |x| x.chr }.join
17
+ }
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,18 @@
1
+ require 'rkelly/token'
2
+
3
+ module RKelly
4
+ class Lexeme
5
+ attr_reader :name, :pattern
6
+ def initialize(name, pattern, &block)
7
+ @name = name
8
+ @pattern = pattern
9
+ @block = block
10
+ end
11
+
12
+ def match(string)
13
+ match = pattern.match(string)
14
+ return Token.new(name, match.to_s, &@block) if match
15
+ match
16
+ end
17
+ end
18
+ end