myco 0.1.4 → 0.1.5

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 (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
+ }