myco 0.1.4 → 0.1.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (51) hide show
  1. checksums.yaml +4 -4
  2. data/lib/myco/bootstrap/find_constant.rb +4 -11
  3. data/lib/myco/code_loader.rb +2 -1
  4. data/lib/myco/code_tools/AST/ConstantAccess.my +47 -3
  5. data/lib/myco/code_tools/AST/ConstantAccess.my.rb +13 -9
  6. data/lib/myco/code_tools/AST/ConstantAssignment.my +1 -5
  7. data/lib/myco/code_tools/AST/ConstantAssignment.my.rb +3 -9
  8. data/lib/myco/code_tools/AST/ToRuby.my +5 -2
  9. data/lib/myco/code_tools/AST/ToRuby.my.rb +7 -3
  10. data/lib/myco/code_tools/AST.my +1 -0
  11. data/lib/myco/code_tools/AST.my.rb +9 -1
  12. data/lib/myco/code_tools/Parser.my +24 -0
  13. data/lib/myco/code_tools/Parser.my.rb +25 -0
  14. data/lib/myco/code_tools/parser/MycoBuilder.my +67 -0
  15. data/lib/myco/code_tools/parser/MycoBuilder.my.rb +99 -0
  16. data/lib/myco/code_tools/parser/MycoCharacterClasses.my +20 -0
  17. data/lib/myco/code_tools/parser/MycoCharacterClasses.my.rb +56 -0
  18. data/lib/myco/code_tools/parser/MycoGrammar.my +564 -0
  19. data/lib/myco/code_tools/parser/MycoGrammar.my.rb +1851 -0
  20. data/lib/myco/code_tools/parser/MycoTokens.my +78 -0
  21. data/lib/myco/code_tools/parser/MycoTokens.my.rb +170 -0
  22. data/lib/myco/code_tools/parser/pegleromyces/lib/pegleromyces/Builder.my +4 -0
  23. data/lib/myco/code_tools/parser/pegleromyces/lib/pegleromyces/Builder.my.rb +5 -0
  24. data/lib/myco/code_tools/parser/pegleromyces/lib/pegleromyces/BytecodeHelpers.my +142 -0
  25. data/lib/myco/code_tools/parser/pegleromyces/lib/pegleromyces/BytecodeHelpers.my.rb +181 -0
  26. data/lib/myco/code_tools/parser/pegleromyces/lib/pegleromyces/BytecodeInstructions.my +420 -0
  27. data/lib/myco/code_tools/parser/pegleromyces/lib/pegleromyces/BytecodeInstructions.my.rb +415 -0
  28. data/lib/myco/code_tools/parser/pegleromyces/lib/pegleromyces/BytecodeParser.my +137 -0
  29. data/lib/myco/code_tools/parser/pegleromyces/lib/pegleromyces/BytecodeParser.my.rb +237 -0
  30. data/lib/myco/code_tools/parser/pegleromyces/lib/pegleromyces/Constructions.my +183 -0
  31. data/lib/myco/code_tools/parser/pegleromyces/lib/pegleromyces/Constructions.my.rb +370 -0
  32. data/lib/myco/code_tools/parser/pegleromyces/lib/pegleromyces/Grammar.my +65 -0
  33. data/lib/myco/code_tools/parser/pegleromyces/lib/pegleromyces/Grammar.my.rb +83 -0
  34. data/lib/myco/code_tools/parser/pegleromyces/lib/pegleromyces/Instructions.my +139 -0
  35. data/lib/myco/code_tools/parser/pegleromyces/lib/pegleromyces/Instructions.my.rb +284 -0
  36. data/lib/myco/code_tools/parser/pegleromyces/lib/pegleromyces/Machine.my +37 -0
  37. data/lib/myco/code_tools/parser/pegleromyces/lib/pegleromyces/Machine.my.rb +24 -0
  38. data/lib/myco/code_tools/parser/pegleromyces/lib/pegleromyces/Parser.my +42 -0
  39. data/lib/myco/code_tools/parser/pegleromyces/lib/pegleromyces/Parser.my.rb +52 -0
  40. data/lib/myco/code_tools/parser/pegleromyces/lib/pegleromyces/Patterns.my +123 -0
  41. data/lib/myco/code_tools/parser/pegleromyces/lib/pegleromyces/Patterns.my.rb +164 -0
  42. data/lib/myco/code_tools/parser/pegleromyces/lib/pegleromyces/Processor.my +236 -0
  43. data/lib/myco/code_tools/parser/pegleromyces/lib/pegleromyces/Processor.my.rb +339 -0
  44. data/lib/myco/code_tools/parser/pegleromyces/lib/pegleromyces.my +15 -0
  45. data/lib/myco/code_tools/parser/pegleromyces/lib/pegleromyces.my.rb +14 -0
  46. data/lib/myco/code_tools.rb +1 -1
  47. data/lib/myco/version.rb +1 -1
  48. data/lib/myco.rb +2 -0
  49. metadata +44 -25
  50. data/lib/myco/code_tools/parser/peg_parser.rb +0 -7182
  51. data/lib/myco/code_tools/parser.rb +0 -39
@@ -0,0 +1,164 @@
1
+
2
+ ::Myco::Component.new([::Myco::FileToplevel], ::Myco.cscope.for_method_definition, __FILE__, __LINE__)
3
+ .tap { |__c__| __c__.__last__ = __c__.component_eval {(::Myco.cscope.for_method_definition.const_set(:Patterns, ::Myco::Component.new([::Myco.find_constant(:EmptyObject)], ::Myco.cscope.for_method_definition, __FILE__, __LINE__)
4
+ .tap { |__c__| __c__.__last__ = __c__.component_eval {(
5
+ ::Myco.cscope.for_method_definition.const_set(:Base, ::Myco::Component.new([::Myco.find_constant(:BasicObject)], ::Myco.cscope.for_method_definition, __FILE__, __LINE__)
6
+ .tap { |__c__| __c__.__last__ = __c__.component_eval {(declare_meme(:name, [[:var, []]], nil, ::Myco.cscope.dup) { |*| (self.parent_meme.name)})}})
7
+ .tap { |__c__| __c__.__name__ = :Base }
8
+ ::Myco.cscope.for_method_definition.const_set(:UnaryBase, ::Myco::Component.new([::Myco.find_constant(:Base)], ::Myco.cscope.for_method_definition, __FILE__, __LINE__)
9
+ .tap { |__c__| __c__.__last__ = __c__.component_eval {(declare_meme(:inner, [[:var, []]], nil, ::Myco.cscope.dup) { |*| nil})}})
10
+ .tap { |__c__| __c__.__name__ = :UnaryBase }
11
+ ::Myco.cscope.for_method_definition.const_set(:BinaryBase, ::Myco::Component.new([::Myco.find_constant(:Base)], ::Myco.cscope.for_method_definition, __FILE__, __LINE__)
12
+ .tap { |__c__| __c__.__last__ = __c__.component_eval {(
13
+ declare_meme(:first, [[:var, []]], nil, ::Myco.cscope.dup) { |*| nil}
14
+ declare_meme(:second, [[:var, []]], nil, ::Myco.cscope.dup) { |*| nil}
15
+ )}})
16
+ .tap { |__c__| __c__.__name__ = :BinaryBase }
17
+ ::Myco.cscope.for_method_definition.const_set(:AnyCharacter, ::Myco::Component.new([::Myco.find_constant(:Base)], ::Myco.cscope.for_method_definition, __FILE__, __LINE__)
18
+ .tap { |__c__| __c__.__last__ = __c__.component_eval {nil}})
19
+ .tap { |__c__| __c__.__name__ = :AnyCharacter }
20
+ ::Myco.cscope.for_method_definition.const_set(:Character, ::Myco::Component.new([::Myco.find_constant(:Base)], ::Myco.cscope.for_method_definition, __FILE__, __LINE__)
21
+ .tap { |__c__| __c__.__last__ = __c__.component_eval {(declare_meme(:code, [[:var, []]], nil, ::Myco.cscope.dup) { |*| nil})}})
22
+ .tap { |__c__| __c__.__name__ = :Character }
23
+ ::Myco.cscope.for_method_definition.const_set(:CharacterString, ::Myco::Component.new([::Myco.find_constant(:Base)], ::Myco.cscope.for_method_definition, __FILE__, __LINE__)
24
+ .tap { |__c__| __c__.__last__ = __c__.component_eval {(declare_meme(:codes, [[:var, []]], nil, ::Myco.cscope.dup) { |*| nil})}})
25
+ .tap { |__c__| __c__.__name__ = :CharacterString }
26
+ ::Myco.cscope.for_method_definition.const_set(:CharacterSet, ::Myco::Component.new([::Myco.find_constant(:Base)], ::Myco.cscope.for_method_definition, __FILE__, __LINE__)
27
+ .tap { |__c__| __c__.__last__ = __c__.component_eval {(declare_meme(:codes, [[:var, []]], nil, ::Myco.cscope.dup) { |*| nil})}})
28
+ .tap { |__c__| __c__.__name__ = :CharacterSet }
29
+ ::Myco.cscope.for_method_definition.const_set(:CharacterRange, ::Myco::Component.new([::Myco.find_constant(:Base)], ::Myco.cscope.for_method_definition, __FILE__, __LINE__)
30
+ .tap { |__c__| __c__.__last__ = __c__.component_eval {(
31
+ declare_meme(:start, [[:var, []]], nil, ::Myco.cscope.dup) { |*| nil}
32
+ declare_meme(:stop, [[:var, []]], nil, ::Myco.cscope.dup) { |*| nil}
33
+ )}})
34
+ .tap { |__c__| __c__.__name__ = :CharacterRange }
35
+ ::Myco.cscope.for_method_definition.const_set(:NegativePredicate, ::Myco::Component.new([::Myco.find_constant(:UnaryBase)], ::Myco.cscope.for_method_definition, __FILE__, __LINE__)
36
+ .tap { |__c__| __c__.__last__ = __c__.component_eval {nil}})
37
+ .tap { |__c__| __c__.__name__ = :NegativePredicate }
38
+ ::Myco.cscope.for_method_definition.const_set(:PositivePredicate, ::Myco::Component.new([::Myco.find_constant(:UnaryBase)], ::Myco.cscope.for_method_definition, __FILE__, __LINE__)
39
+ .tap { |__c__| __c__.__last__ = __c__.component_eval {nil}})
40
+ .tap { |__c__| __c__.__name__ = :PositivePredicate }
41
+ ::Myco.cscope.for_method_definition.const_set(:OneOrMore, ::Myco::Component.new([::Myco.find_constant(:UnaryBase)], ::Myco.cscope.for_method_definition, __FILE__, __LINE__)
42
+ .tap { |__c__| __c__.__last__ = __c__.component_eval {nil}})
43
+ .tap { |__c__| __c__.__name__ = :OneOrMore }
44
+ ::Myco.cscope.for_method_definition.const_set(:ZeroOrOne, ::Myco::Component.new([::Myco.find_constant(:UnaryBase)], ::Myco.cscope.for_method_definition, __FILE__, __LINE__)
45
+ .tap { |__c__| __c__.__last__ = __c__.component_eval {nil}})
46
+ .tap { |__c__| __c__.__name__ = :ZeroOrOne }
47
+ ::Myco.cscope.for_method_definition.const_set(:ZeroOrMore, ::Myco::Component.new([::Myco.find_constant(:UnaryBase)], ::Myco.cscope.for_method_definition, __FILE__, __LINE__)
48
+ .tap { |__c__| __c__.__last__ = __c__.component_eval {nil}})
49
+ .tap { |__c__| __c__.__name__ = :ZeroOrMore }
50
+ ::Myco.cscope.for_method_definition.const_set(:OrderedChoice, ::Myco::Component.new([::Myco.find_constant(:BinaryBase)], ::Myco.cscope.for_method_definition, __FILE__, __LINE__)
51
+ .tap { |__c__| __c__.__last__ = __c__.component_eval {nil}})
52
+ .tap { |__c__| __c__.__name__ = :OrderedChoice }
53
+ ::Myco.cscope.for_method_definition.const_set(:Concatenation, ::Myco::Component.new([::Myco.find_constant(:BinaryBase)], ::Myco.cscope.for_method_definition, __FILE__, __LINE__)
54
+ .tap { |__c__| __c__.__last__ = __c__.component_eval {nil}})
55
+ .tap { |__c__| __c__.__name__ = :Concatenation }
56
+ ::Myco.cscope.for_method_definition.const_set(:NamedCapture, ::Myco::Component.new([::Myco.find_constant(:UnaryBase)], ::Myco.cscope.for_method_definition, __FILE__, __LINE__)
57
+ .tap { |__c__| __c__.__last__ = __c__.component_eval {nil}})
58
+ .tap { |__c__| __c__.__name__ = :NamedCapture }
59
+ ::Myco.cscope.for_method_definition.const_set(:NamedTextCapture, ::Myco::Component.new([::Myco.find_constant(:UnaryBase)], ::Myco.cscope.for_method_definition, __FILE__, __LINE__)
60
+ .tap { |__c__| __c__.__last__ = __c__.component_eval {nil}})
61
+ .tap { |__c__| __c__.__name__ = :NamedTextCapture }
62
+ ::Myco.cscope.for_method_definition.const_set(:NamedTokenCapture, ::Myco::Component.new([::Myco.find_constant(:UnaryBase)], ::Myco.cscope.for_method_definition, __FILE__, __LINE__)
63
+ .tap { |__c__| __c__.__last__ = __c__.component_eval {nil}})
64
+ .tap { |__c__| __c__.__name__ = :NamedTokenCapture }
65
+ ::Myco.cscope.for_method_definition.const_set(:Reduction, ::Myco::Component.new([::Myco.find_constant(:UnaryBase)], ::Myco.cscope.for_method_definition, __FILE__, __LINE__)
66
+ .tap { |__c__| __c__.__last__ = __c__.component_eval {(
67
+ declare_meme(:block, [[:var, []]], nil, ::Myco.cscope.dup) { |*| nil}
68
+ declare_meme(:args, [[:var, []]], nil, ::Myco.cscope.dup) { |*| ([])}
69
+ )}})
70
+ .tap { |__c__| __c__.__name__ = :Reduction }
71
+ ::Myco.cscope.for_method_definition.const_set(:ShorthandMethods, ::Myco::Component.new([::Myco.find_constant(:EmptyObject)], ::Myco.cscope.for_method_definition, __FILE__, __LINE__)
72
+ .tap { |__c__| __c__.__last__ = __c__.component_eval {(
73
+ declare_meme(:any, [], nil, ::Myco.cscope.dup) { |*| (::Myco.find_constant(:AnyCharacter).new)}
74
+ declare_meme(:char, [], nil, ::Myco.cscope.dup) { |character| (::Myco.find_constant(:Character).new({:code => character.ord}))}
75
+ declare_meme(:str, [], nil, ::Myco.cscope.dup) { |string| (::Myco.find_constant(:CharacterString).new({:codes => string.each_char.map(&:ord)}))}
76
+ declare_meme(:set, [], nil, ::Myco.cscope.dup) { |string| (::Myco.find_constant(:CharacterSet).new({:codes => string.each_char.map(&:ord)}))}
77
+ declare_meme(:range, [], nil, ::Myco.cscope.dup) { |start, stop| (::Myco.find_constant(:CharacterRange).new({
78
+ :start => start.ord,
79
+ :stop => stop.ord
80
+ }))}
81
+ declare_meme(:r, [], nil, ::Myco.cscope.dup) { |pattern, &block| (::Myco.find_constant(:Reduction).new({
82
+ :inner => pattern,
83
+ :block => block
84
+ }))}
85
+ )}})
86
+ .tap { |__c__| __c__.__name__ = :ShorthandMethods }
87
+ ::Myco.find_constant(:Base).component_eval {(
88
+ declare_meme(:!, [], nil, ::Myco.cscope.dup) { |*| (::Myco.find_constant(:NegativePredicate).new({:inner => self}))}
89
+ declare_meme(:/, [], nil, ::Myco.cscope.dup) { |other| (::Myco.find_constant(:OrderedChoice).new({
90
+ :first => self,
91
+ :second => other
92
+ }))}
93
+ declare_meme(:+, [], nil, ::Myco.cscope.dup) { |other=false| (::Myco.branch_op(:"??", ::Myco.branch_op(:"&?", other) {::Myco.find_constant(:Concatenation).new({
94
+ :first => self,
95
+ :second => other
96
+ })}) {::Myco.find_constant(:OneOrMore).new({:inner => self})})}
97
+ declare_meme(:-, [], nil, ::Myco.cscope.dup) { |other=false| (::Myco.branch_op(:"??", ::Myco.branch_op(:"&?", other) {::Myco.find_constant(:ErrorCondition).new}) {::Myco.find_constant(:ZeroOrOne).new({:inner => self})})}
98
+ declare_meme(:*, [], nil, ::Myco.cscope.dup) { |other=false| (::Myco.branch_op(:"??", ::Myco.branch_op(:"&?", other) {::Myco.find_constant(:ErrorCondition).new}) {::Myco.find_constant(:ZeroOrMore).new({:inner => self})})}
99
+ declare_meme(:[], [], nil, ::Myco.cscope.dup) { |name| (::Myco.find_constant(:NamedCapture).new({
100
+ :inner => self,
101
+ :name => name
102
+ }))}
103
+ declare_meme(:text, [], nil, ::Myco.cscope.dup) { |name=:text| (::Myco.find_constant(:NamedTextCapture).new({
104
+ :inner => self,
105
+ :name => name
106
+ }))}
107
+ declare_meme(:token, [], nil, ::Myco.cscope.dup) { |name| (::Myco.find_constant(:NamedTokenCapture).new({
108
+ :inner => self,
109
+ :name => name
110
+ }))}
111
+ __category__(:private).component_eval {(declare_meme(:binary_right_assoc, [], nil, ::Myco.cscope.dup) { |orig, other, type| (
112
+ cursor = orig
113
+ self.loop { || (
114
+ self.__send__(
115
+ :unless,
116
+ cursor.second.__send__(
117
+ :is_a?,
118
+ type
119
+ )
120
+ ) { || (self.__send__(:break))}
121
+ cursor = cursor.second
122
+ )}
123
+ cursor.__send__(
124
+ :second=,
125
+ type.new({
126
+ :first => cursor.second,
127
+ :second => other
128
+ })
129
+ )
130
+ orig
131
+ )})}
132
+ )}
133
+ ::Myco.find_constant(:NegativePredicate).component_eval {(declare_meme(:!, [], nil, ::Myco.cscope.dup) { |*| (::Myco.find_constant(:PositivePredicate).new({:inner => self.inner}))})}
134
+ ::Myco.find_constant(:PositivePredicate).component_eval {(declare_meme(:!, [], nil, ::Myco.cscope.dup) { |*| (::Myco.find_constant(:NegativePredicate).new({:inner => self.inner}))})}
135
+ ::Myco.find_constant(:OrderedChoice).component_eval {(declare_meme(:/, [], nil, ::Myco.cscope.dup) { |other| (self.private.binary_right_assoc(
136
+ self,
137
+ other,
138
+ ::Myco.find_constant(:OrderedChoice)
139
+ ))})}
140
+ ::Myco.find_constant(:Concatenation).component_eval {(declare_meme(:+, [], nil, ::Myco.cscope.dup) { |other=false| (::Myco.branch_op(:"??", ::Myco.branch_op(:"&?", other) {self.private.binary_right_assoc(
141
+ self,
142
+ other,
143
+ ::Myco.find_constant(:Concatenation)
144
+ )}) {::Myco.find_constant(:OneOrMore).new({:inner => self})})})}
145
+ ::Myco.find_constant(:Reduction).component_eval {(
146
+ ::Myco.cscope.for_method_definition.const_set(:Environment, ::Myco::Component.new([
147
+ ::Myco.find_constant(:EmptyObject),
148
+ ::Myco.find_constant(:BasicDecorators)
149
+ ], ::Myco.cscope.for_method_definition, __FILE__, __LINE__)
150
+ .tap { |__c__| __c__.__last__ = __c__.component_eval {(
151
+ declare_meme(:captures, [[:var, []]], nil, ::Myco.cscope.dup) { |*| nil}
152
+ declare_meme(:builder, [[:var, []]], nil, ::Myco.cscope.dup) { |*| nil}
153
+ declare_meme(:method_missing, [], nil, ::Myco.cscope.dup) { |name, *args, &block| (self.captures.fetch(name) { || (self.builder.send(
154
+ name,
155
+ *args,
156
+ &block
157
+ ))})}
158
+ declare_meme(:!, [], nil, ::Myco.cscope.dup) { |*| (nil)}
159
+ )}})
160
+ .tap { |__c__| __c__.__name__ = :Environment }
161
+ declare_meme(:code, [], nil, ::Myco.cscope.dup) { |*| (self.block.block.compiled_code)}
162
+ )}
163
+ )}})
164
+ .tap { |__c__| __c__.__name__ = :Patterns })}}.instance
@@ -0,0 +1,236 @@
1
+
2
+ Processor < BasicObject {
3
+ var string: "" # The source string to be processed
4
+ var capture_items: [] # The stream of capture tokens to be processed
5
+ var builder: null # The AST Builder to use in the reduction environment
6
+
7
+ # Process the inputs and return the final captures layer
8
+ process: setup; process_each; validate_state; final_captures
9
+
10
+ # A lightweight class used for string captures in the reduction environment
11
+ Token < BasicObject {
12
+ var type
13
+ var text
14
+ var row
15
+ var col
16
+
17
+ inspect: [type, text, row, col].inspect
18
+ to_s: [type, text, row, col].inspect
19
+
20
+ line: row # alias
21
+
22
+ sym: text.to_sym
23
+ float: text.to_f
24
+ integer: |base=0| text.to_inum(base, true)
25
+ }
26
+
27
+ # The environment for performing reduction actions to build an AST in the PEG.
28
+ # It gives implicit access to both local captures and AST builder methods.
29
+ var reduction_env:
30
+ Patterns::Reduction::Environment { }
31
+ var reduction_env_cscope:
32
+ ::Rubinius::ConstantScope.new(Patterns::Reduction::Environment) # TODO: fix
33
+
34
+ var cidx_stack: [] # A FILO stack of start indices for captures
35
+ var sidx_stack: [] # A FILO stack of start indices for string captures
36
+ var tidx_stack: [] # A FILO stack of start indices for token captures
37
+ var midx_stack: [] # A FILO stack of start indices for multiplicit captures
38
+ var ridx_stack: [] # A FILO stack of start indices for reductions
39
+ var capt_stack: [] # A FILO stack of Hashes with capture names, values
40
+
41
+ # Given a string, return a map of indices of newline positions to line numbers
42
+ memoize line_map_for: |string| {
43
+ idx_hash = ::Hash.new
44
+ idx_hash[0] = 0
45
+ count = 0
46
+ idx = 0
47
+ loop {
48
+ idx = string.index("\n", idx + 1)
49
+ idx || break
50
+ count = count + 1
51
+ idx_hash[idx] = count
52
+ }
53
+ idx_hash
54
+ }
55
+
56
+ # Given an index and string, return the row (line) and column numbers
57
+ position_of: |idx, string| {
58
+ nl_idx = string.rindex("\n", idx) || 0
59
+ row = line_map_for(string).fetch(nl_idx) + 1
60
+ col = idx - nl_idx
61
+ [row, col]
62
+ }
63
+
64
+ # Push or pop a layer to/from the capture stack
65
+ push_layer: capt_stack.push(::Hash.new)
66
+ pop_layer: capt_stack.pop
67
+
68
+ setup:
69
+ push_layer
70
+
71
+ final_captures:
72
+ pop_layer
73
+ .select |k,v| { k.is_a?(::Symbol) }
74
+ .map |k,v| { [k,v.last] }
75
+ .to_h
76
+
77
+ process_each: capture_items.each |idx, metadata| {
78
+ type = metadata[0]
79
+ captargs = metadata[1] || []
80
+ send(type, idx, *captargs)
81
+ }
82
+
83
+ validate_state: {
84
+ cidx_stack.empty? || raise("unbalanced cidx_stack: "cidx_stack"")
85
+ sidx_stack.empty? || raise("unbalanced sidx_stack: "sidx_stack"")
86
+ tidx_stack.empty? || raise("unbalanced tidx_stack: "tidx_stack"")
87
+ midx_stack.empty? || raise("unbalanced midx_stack: "midx_stack"")
88
+ ridx_stack.empty? || raise("unbalanced ridx_stack: "ridx_stack"")
89
+ }
90
+
91
+ # Start of a named capture
92
+ c_start: |idx| {
93
+ # Note the starting index of the capture
94
+ cidx_stack.push(idx)
95
+ }
96
+
97
+ # End of a named capture
98
+ c_end: |idx, name| {
99
+ captures = capt_stack.last
100
+ start_idx = cidx_stack.pop
101
+
102
+ # Pick up the captured reduction, if its start and end
103
+ # indices are within the bounds we are looking for.
104
+ use_reduction = false
105
+ value = captures[idx]
106
+ value &? (
107
+ loc = value.first
108
+ value = value.last
109
+ ((loc.first>=start_idx) && (loc.last<=idx)) &? (
110
+ use_reduction = true
111
+ ) ?? (
112
+ value = null
113
+ )
114
+ )
115
+
116
+ # If the reduction is not found and the string length is not zero
117
+ # slice the string with the given indices to get a text value.
118
+ !use_reduction && !(start_idx==idx) && (
119
+ value = string.slice(start_idx, idx-start_idx)
120
+ )
121
+
122
+ store_value = [[start_idx, idx], value]
123
+ captures.store(idx, store_value)
124
+ captures.store(name, store_value)
125
+ }
126
+
127
+ # Start of a named text capture
128
+ s_start: |idx| {
129
+ # Note the starting index of the text capture
130
+ sidx_stack.push(idx)
131
+ }
132
+
133
+ # End of a named text capture
134
+ s_end: |idx, name| {
135
+ captures = capt_stack.last
136
+ start_idx = sidx_stack.pop
137
+
138
+ value = string.slice(start_idx, idx-start_idx)
139
+ store_value = [[start_idx, idx], value]
140
+ captures.store(idx, store_value)
141
+ captures.store(name, store_value)
142
+ }
143
+
144
+ # Start of a named token capture
145
+ t_start: |idx| {
146
+ # Note the starting index of the text capture
147
+ tidx_stack.push(idx)
148
+ }
149
+
150
+ # End of a named token capture
151
+ t_end: |idx, name| {
152
+ captures = capt_stack.last
153
+ start_idx = tidx_stack.pop
154
+ pos = position_of(start_idx, string)
155
+
156
+ value = Token.new(
157
+ type: name
158
+ text: string.slice(start_idx, idx - start_idx)
159
+ row: pos.first
160
+ col: pos.last
161
+ )
162
+ store_value = [[start_idx, idx], value]
163
+ captures.store(idx, store_value)
164
+ captures.store(name, store_value)
165
+ }
166
+
167
+ # Start of a multiplicit capture
168
+ m_start: |idx| {
169
+ midx_stack.push(idx)
170
+ c_start(idx)
171
+ }
172
+
173
+ # Split of a multiplicit capture
174
+ m_split: |idx, name| {
175
+ c_end(idx, name)
176
+ c_start(idx)
177
+ }
178
+
179
+ # End of a multiplicit capture
180
+ m_end: |idx, name| {
181
+ captures = capt_stack.last
182
+ start_idx = midx_stack.pop
183
+ cidx_stack.pop # Discard cidx pushed by m_start/end calling c_start
184
+
185
+ # Try to find a group of "anonymous" captures by index first
186
+ value = []
187
+ captures.each |k,v| {
188
+ (k.is_a?(::Fixnum) && k<=idx && k>start_idx) && (
189
+ loc = v.first
190
+ (loc.first>=start_idx) && (
191
+ value.push(v.last)
192
+ )
193
+ )
194
+ }
195
+
196
+ # If the group is empty and the string length is not zero
197
+ # slice the string with the given indices to get a text value
198
+ (value.empty? && !(start_idx==idx)) && (
199
+ value = string.slice(start_idx, idx-start_idx)
200
+ )
201
+
202
+ store_value = [[start_idx, idx], value]
203
+ captures.store(idx, store_value)
204
+ captures.store(name, store_value)
205
+ }
206
+
207
+ # Start of a reduction
208
+ r_start: |idx| (
209
+ # Push a new layer of reduction context onto the stack
210
+ push_layer
211
+ ridx_stack.push(idx)
212
+ )
213
+
214
+ # End of a reduction
215
+ r_end: |idx, code, *args| {
216
+ captures = pop_layer
217
+ start_idx = ridx_stack.pop
218
+
219
+ # Set up the reduction environment
220
+ code.scope = reduction_env_cscope
221
+ reduction_env.builder = builder
222
+ reduction_env.captures = captures.map |k,v| { [k,v.last] }.to_h
223
+
224
+ # Invoke the reduction action to get a value
225
+ # Store with the string index as the key so the value can be recaptured
226
+ value = code.invoke(
227
+ code.name,
228
+ Patterns::Reduction::Environment,
229
+ reduction_env,
230
+ [],
231
+ null,
232
+ )
233
+ store_value = [[start_idx, idx], value]
234
+ capt_stack.last.store(idx, store_value)
235
+ }
236
+ }