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,284 @@
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(:Instructions, ::Myco::Component.new([::Myco.find_constant(:EmptyObject)], ::Myco.cscope.for_method_definition, __FILE__, __LINE__)
4
+ .tap { |__c__| __c__.__last__ = __c__.component_eval {(
5
+ declare_meme(:char, [], nil, ::Myco.cscope.dup) { |code| (::Myco.branch_op(:"??", ::Myco.branch_op(:"&?", self.subject.at(self.idx).__send__(
6
+ :==,
7
+ code
8
+ )) {(
9
+ self.__send__(
10
+ :ip=,
11
+ self.ip.__send__(
12
+ :+,
13
+ 1
14
+ )
15
+ )
16
+ self.__send__(
17
+ :idx=,
18
+ self.idx.__send__(
19
+ :+,
20
+ 1
21
+ )
22
+ )
23
+ )}) {self.__send__(
24
+ :ip=,
25
+ nil
26
+ )})}
27
+ declare_meme(:jump, [], nil, ::Myco.cscope.dup) { |label| (self.__send__(
28
+ :ip=,
29
+ self.ip.__send__(
30
+ :+,
31
+ label
32
+ )
33
+ ))}
34
+ declare_meme(:choice, [], nil, ::Myco.cscope.dup) { |label| (
35
+ self.stack.push([
36
+ self.ip.__send__(
37
+ :+,
38
+ label
39
+ ),
40
+ self.idx,
41
+ self.captures.dup
42
+ ])
43
+ self.__send__(
44
+ :ip=,
45
+ self.ip.__send__(
46
+ :+,
47
+ 1
48
+ )
49
+ )
50
+ )}
51
+ declare_meme(:call, [], nil, ::Myco.cscope.dup) { |new_ipk| (
52
+ self.stack.push([
53
+ self.ip.__send__(
54
+ :+,
55
+ 1
56
+ ),
57
+ self.ipk
58
+ ])
59
+ self.__send__(
60
+ :ip=,
61
+ 0
62
+ )
63
+ self.__send__(
64
+ :ipk=,
65
+ new_ipk
66
+ )
67
+ )}
68
+ declare_meme(:return, [], nil, ::Myco.cscope.dup) { |*| (
69
+ addr = self.stack.pop
70
+ ::Myco.branch_op(:"??", ::Myco.branch_op(:"&?", addr) {(
71
+ self.__send__(
72
+ :ipk=,
73
+ addr.pop
74
+ )
75
+ self.__send__(
76
+ :ip=,
77
+ addr.pop
78
+ )
79
+ true
80
+ )}) {self.finish}
81
+ )}
82
+ declare_meme(:commit, [], nil, ::Myco.cscope.dup) { |label| (
83
+ self.stack.pop
84
+ self.__send__(
85
+ :ip=,
86
+ self.ip.__send__(
87
+ :+,
88
+ label
89
+ )
90
+ )
91
+ )}
92
+ declare_meme(:capture, [], nil, ::Myco.cscope.dup) { |metadata| (
93
+ self.captures.push([
94
+ self.idx,
95
+ metadata
96
+ ])
97
+ self.__send__(
98
+ :ip=,
99
+ self.ip.__send__(
100
+ :+,
101
+ 1
102
+ )
103
+ )
104
+ )}
105
+ declare_meme(:handle_fail, [], nil, ::Myco.cscope.dup) { |*| (::Myco.branch_op(:"??", ::Myco.branch_op(:"&?", self.stack.__send__(:empty?)) {::Myco.find_constant(:ErrorCondition).new}) {(
106
+ entry = self.stack.pop
107
+ size = entry.size
108
+ ::Myco.branch_op(:"??", ::Myco.branch_op(:"&?", size.__send__(
109
+ :==,
110
+ 3
111
+ )) {(
112
+ self.__send__(
113
+ :captures=,
114
+ entry.pop
115
+ )
116
+ self.__send__(
117
+ :idx=,
118
+ entry.pop
119
+ )
120
+ self.__send__(
121
+ :ip=,
122
+ entry.pop
123
+ )
124
+ true
125
+ )}) {::Myco.branch_op(:"??", ::Myco.branch_op(:"&?", size.__send__(
126
+ :==,
127
+ 2
128
+ )) {(
129
+ self.__send__(
130
+ :ipk=,
131
+ entry.pop
132
+ )
133
+ self.__send__(
134
+ :ip=,
135
+ nil
136
+ )
137
+ )}) {::Myco.find_constant(:ErrorCondition).new}}
138
+ )})}
139
+ declare_meme(:finish, [], nil, ::Myco.cscope.dup) { |*| (self.__send__(
140
+ :ip=,
141
+ true
142
+ ))}
143
+ declare_meme(:charset, [], nil, ::Myco.cscope.dup) { |table| (::Myco.branch_op(:"??", ::Myco.branch_op(:"&?", (
144
+ code = self.subject.at(self.idx)
145
+ ::Myco.branch_op(:"&&", code) {table.__send__(
146
+ :key?,
147
+ code
148
+ )}
149
+ )) {(
150
+ self.__send__(
151
+ :ip=,
152
+ self.ip.__send__(
153
+ :+,
154
+ 1
155
+ )
156
+ )
157
+ self.__send__(
158
+ :idx=,
159
+ self.idx.__send__(
160
+ :+,
161
+ 1
162
+ )
163
+ )
164
+ )}) {self.__send__(
165
+ :ip=,
166
+ nil
167
+ )})}
168
+ declare_meme(:charrange, [], nil, ::Myco.cscope.dup) { |start, stop| (::Myco.branch_op(:"??", ::Myco.branch_op(:"&?", (
169
+ code = self.subject.at(self.idx)
170
+ ::Myco.branch_op(:"&&", ::Myco.branch_op(:"&&", code) {code.__send__(
171
+ :>=,
172
+ start
173
+ )}) {code.__send__(
174
+ :<=,
175
+ stop
176
+ )}
177
+ )) {(
178
+ self.__send__(
179
+ :ip=,
180
+ self.ip.__send__(
181
+ :+,
182
+ 1
183
+ )
184
+ )
185
+ self.__send__(
186
+ :idx=,
187
+ self.idx.__send__(
188
+ :+,
189
+ 1
190
+ )
191
+ )
192
+ )}) {self.__send__(
193
+ :ip=,
194
+ nil
195
+ )})}
196
+ declare_meme(:span, [], nil, ::Myco.cscope.dup) { |table| (self.loop { || (::Myco.branch_op(:"??", ::Myco.branch_op(:"&?", (
197
+ code = self.subject.at(self.idx)
198
+ ::Myco.branch_op(:"&&", code) {table.__send__(
199
+ :key?,
200
+ code
201
+ )}
202
+ )) {self.__send__(
203
+ :idx=,
204
+ self.idx.__send__(
205
+ :+,
206
+ 1
207
+ )
208
+ )}) {(
209
+ self.__send__(
210
+ :ip=,
211
+ self.ip.__send__(
212
+ :+,
213
+ 1
214
+ )
215
+ )
216
+ self.__send__(:break)
217
+ )})})}
218
+ declare_meme(:any, [], nil, ::Myco.cscope.dup) { |count| (::Myco.branch_op(:"??", ::Myco.branch_op(:"&?", self.idx.__send__(
219
+ :+,
220
+ count
221
+ ).__send__(
222
+ :>,
223
+ self.subject.size
224
+ )) {(
225
+ self.__send__(
226
+ :ip=,
227
+ nil
228
+ )
229
+ true
230
+ )}) {(
231
+ self.__send__(
232
+ :ip=,
233
+ self.ip.__send__(
234
+ :+,
235
+ 1
236
+ )
237
+ )
238
+ self.__send__(
239
+ :idx=,
240
+ self.idx.__send__(
241
+ :+,
242
+ count
243
+ )
244
+ )
245
+ )})}
246
+ declare_meme(:partial_commit, [], nil, ::Myco.cscope.dup) { |label| (
247
+ entry = self.stack.pop
248
+ self.stack.push([
249
+ entry.first,
250
+ self.idx,
251
+ self.captures.dup
252
+ ])
253
+ self.__send__(
254
+ :ip=,
255
+ self.ip.__send__(
256
+ :+,
257
+ label
258
+ )
259
+ )
260
+ )}
261
+ declare_meme(:back_commit, [], nil, ::Myco.cscope.dup) { |label| (
262
+ entry = self.stack.pop
263
+ self.__send__(
264
+ :captures=,
265
+ entry.pop
266
+ )
267
+ self.__send__(
268
+ :idx=,
269
+ entry.pop
270
+ )
271
+ self.__send__(
272
+ :ip=,
273
+ self.ip.__send__(
274
+ :+,
275
+ label
276
+ )
277
+ )
278
+ )}
279
+ declare_meme(:fail_twice, [], nil, ::Myco.cscope.dup) { |*| (
280
+ ::Myco.branch_op(:"??", ::Myco.branch_op(:"&?", self.stack.__send__(:empty?)) {::Myco.find_constant(:ErrorCondition).new}) {self.stack.pop}
281
+ self.handle_fail
282
+ )}
283
+ )}})
284
+ .tap { |__c__| __c__.__name__ = :Instructions })}}.instance
@@ -0,0 +1,37 @@
1
+
2
+ Machine < BasicObject, Instructions {
3
+ # The index of the next program instruction, or null indicating fail condition
4
+ var ip: 0
5
+
6
+ # The key name in the rule table of the next program instruction
7
+ var ipk: :root
8
+
9
+ # The current index into the subject string
10
+ var idx: 0
11
+
12
+ # A list of stack entries, each of which is either a:
13
+ # return_address (the instruction index to return to)
14
+ # or a list containing:
15
+ # [fail_address, current_idx, current_capture_list] (a pending alternative)
16
+ var stack: []
17
+
18
+ # A list of tuples, each containing:
19
+ # [idx, captor] (the index into the subject and the captor to notify)
20
+ var captures: []
21
+
22
+ # The subject string as an array of character codes
23
+ var subject: []
24
+
25
+ # The sequence of instructions to execute for each rule name
26
+ var sequence_table: Hash.new
27
+
28
+
29
+ # Execute the root rule instruction sequence over the given subject
30
+ execute: loop {
31
+ ip |? handle_fail ?? (
32
+ (ip==true) &? break ?? send(*sequence_table.fetch(ipk)[ip])
33
+ )
34
+ }
35
+
36
+ had_failure: !ip
37
+ }
@@ -0,0 +1,24 @@
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(:Machine, ::Myco::Component.new([
4
+ ::Myco.find_constant(:BasicObject),
5
+ ::Myco.find_constant(:Instructions)
6
+ ], ::Myco.cscope.for_method_definition, __FILE__, __LINE__)
7
+ .tap { |__c__| __c__.__last__ = __c__.component_eval {(
8
+ declare_meme(:ip, [[:var, []]], nil, ::Myco.cscope.dup) { |*| (0)}
9
+ declare_meme(:ipk, [[:var, []]], nil, ::Myco.cscope.dup) { |*| (:root)}
10
+ declare_meme(:idx, [[:var, []]], nil, ::Myco.cscope.dup) { |*| (0)}
11
+ declare_meme(:stack, [[:var, []]], nil, ::Myco.cscope.dup) { |*| ([])}
12
+ declare_meme(:captures, [[:var, []]], nil, ::Myco.cscope.dup) { |*| ([])}
13
+ declare_meme(:subject, [[:var, []]], nil, ::Myco.cscope.dup) { |*| ([])}
14
+ declare_meme(:sequence_table, [[:var, []]], nil, ::Myco.cscope.dup) { |*| (::Myco.find_constant(:Hash).new)}
15
+ declare_meme(:execute, [], nil, ::Myco.cscope.dup) { |*| (self.loop { || (::Myco.branch_op(:"??", ::Myco.branch_op(:"|?", self.ip) {self.handle_fail}) {::Myco.branch_op(:"??", ::Myco.branch_op(:"&?", self.ip.__send__(
16
+ :==,
17
+ true
18
+ )) {self.__send__(:break)}) {self.send(*self.sequence_table.fetch(self.ipk).__send__(
19
+ :[],
20
+ self.ip
21
+ ))}})})}
22
+ declare_meme(:had_failure, [], nil, ::Myco.cscope.dup) { |*| (self.ip.__send__(:!))}
23
+ )}})
24
+ .tap { |__c__| __c__.__name__ = :Machine })}}.instance
@@ -0,0 +1,42 @@
1
+
2
+ Parser < BasicObject {
3
+
4
+ var grammar: Grammar { }
5
+ var string: ""
6
+
7
+ var result: null
8
+
9
+ memoize make_sequence_table: |grammar| {
10
+ grammar.construct_all_rules
11
+ grammar.rule_table.map |k,v| {
12
+ [k, v.construct_rule.sequence + [[:return]]]
13
+ }.to_h
14
+ }
15
+
16
+ new_machine: Machine.new(
17
+ sequence_table: make_sequence_table(grammar)
18
+ subject: string.each_char.map(&:ord)
19
+ )
20
+
21
+ new_processor: Processor.new(
22
+ builder: new_builder
23
+ string: string
24
+ )
25
+
26
+ new_builder: Builder.new
27
+
28
+ parse: |string=null| {
29
+ string && (self.string = string)
30
+ machine = new_machine
31
+
32
+ machine.execute
33
+
34
+ unless(machine.had_failure) {
35
+ processor = new_processor
36
+ processor.capture_items = machine.captures
37
+ self.result = processor.process
38
+ }
39
+
40
+ self
41
+ }
42
+ }
@@ -0,0 +1,52 @@
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(:Parser, ::Myco::Component.new([::Myco.find_constant(:BasicObject)], ::Myco.cscope.for_method_definition, __FILE__, __LINE__)
4
+ .tap { |__c__| __c__.__last__ = __c__.component_eval {(
5
+ declare_meme(:grammar, [[:var, []]], nil, ::Myco.cscope.dup) { |*| (::Myco::Component.new([::Myco.find_constant(:Grammar)], ::Myco.cscope.for_method_definition, __FILE__, __LINE__)
6
+ .tap { |__c__| __c__.__last__ = __c__.component_eval {nil}}.instance)}
7
+ declare_meme(:string, [[:var, []]], nil, ::Myco.cscope.dup) { |*| ("")}
8
+ declare_meme(:result, [[:var, []]], nil, ::Myco.cscope.dup) { |*| (nil)}
9
+ declare_meme(:make_sequence_table, [[:memoize, []]], nil, ::Myco.cscope.dup) { |grammar| (
10
+ grammar.construct_all_rules
11
+ grammar.rule_table.map { |k, v| ([
12
+ k,
13
+ v.construct_rule.sequence.__send__(
14
+ :+,
15
+ [[:return]]
16
+ )
17
+ ])}.to_h
18
+ )}
19
+ declare_meme(:new_machine, [], nil, ::Myco.cscope.dup) { |*| (::Myco.find_constant(:Machine).new({
20
+ :sequence_table => self.make_sequence_table(self.grammar),
21
+ :subject => self.string.each_char.map(&:ord)
22
+ }))}
23
+ declare_meme(:new_processor, [], nil, ::Myco.cscope.dup) { |*| (::Myco.find_constant(:Processor).new({
24
+ :builder => self.new_builder,
25
+ :string => self.string
26
+ }))}
27
+ declare_meme(:new_builder, [], nil, ::Myco.cscope.dup) { |*| (::Myco.find_constant(:Builder).new)}
28
+ declare_meme(:parse, [], nil, ::Myco.cscope.dup) { |string=nil| (
29
+ ::Myco.branch_op(:"&&", string) {self.__send__(
30
+ :string=,
31
+ string
32
+ )}
33
+ machine = self.new_machine
34
+ machine.execute
35
+ self.__send__(
36
+ :unless,
37
+ machine.had_failure
38
+ ) { || (
39
+ processor = self.new_processor
40
+ processor.__send__(
41
+ :capture_items=,
42
+ machine.captures
43
+ )
44
+ self.__send__(
45
+ :result=,
46
+ processor.process
47
+ )
48
+ )}
49
+ self
50
+ )}
51
+ )}})
52
+ .tap { |__c__| __c__.__name__ = :Parser })}}.instance
@@ -0,0 +1,123 @@
1
+
2
+ Patterns < EmptyObject {
3
+
4
+ ##
5
+ # Basic types of patterns.
6
+
7
+ Base < BasicObject { var name: parent_meme.name }
8
+ UnaryBase < Base { var inner }
9
+ BinaryBase < Base { var first, var second }
10
+
11
+ AnyCharacter < Base { }
12
+ Character < Base { var code }
13
+ CharacterString < Base { var codes } # Concatenation for Characters
14
+ CharacterSet < Base { var codes } # OrderedChoice for Characters
15
+ CharacterRange < Base { var start, var stop }
16
+
17
+ NegativePredicate < UnaryBase { }
18
+ PositivePredicate < UnaryBase { }
19
+ OneOrMore < UnaryBase { }
20
+ ZeroOrOne < UnaryBase { }
21
+ ZeroOrMore < UnaryBase { }
22
+ OrderedChoice < BinaryBase { }
23
+ Concatenation < BinaryBase { }
24
+
25
+ NamedCapture < UnaryBase { }
26
+ NamedTextCapture < UnaryBase { }
27
+ NamedTokenCapture < UnaryBase { }
28
+ Reduction < UnaryBase { var block, var args: [] }
29
+
30
+ ##
31
+ # Shorthand methods for creating primitive patterns
32
+
33
+ ShorthandMethods < EmptyObject {
34
+ any: AnyCharacter.new
35
+ char: |character| Character.new(code:character.ord)
36
+ str: |string| CharacterString.new(codes:string.each_char.map(&:ord))
37
+ set: |string| CharacterSet.new(codes:string.each_char.map(&:ord))
38
+ range: |start, stop| CharacterRange.new(start:start.ord, stop:stop.ord)
39
+ r: |pattern, &block| Reduction.new(inner:pattern, block:block)
40
+ }
41
+
42
+ ##
43
+ # Operator overloading for combining and modifying patterns.
44
+ #
45
+ # Each operation returns a new Pattern object composed of the operands
46
+ # so that complex grammars can be specified with relatively succint syntax.
47
+
48
+ Base << {
49
+ "!": NegativePredicate .new(inner:self)
50
+ "/": |other| OrderedChoice .new(first:self, second:other)
51
+ "+": |other=false|
52
+ other &? Concatenation .new(first:self, second:other)
53
+ ?? OneOrMore .new(inner:self)
54
+ "-": |other=false|
55
+ other &? ErrorCondition .new() # TODO: add exception handling to Myco
56
+ ?? ZeroOrOne .new(inner:self)
57
+ "*": |other=false|
58
+ other &? ErrorCondition .new()
59
+ ?? ZeroOrMore .new(inner:self)
60
+
61
+ "[]": |name| NamedCapture .new(inner:self, name:name)
62
+ text: |name=:text|
63
+ NamedTextCapture .new(inner:self, name:name)
64
+ token: |name|
65
+ NamedTokenCapture .new(inner:self, name:name)
66
+
67
+ [private]
68
+
69
+ # Add |other| to |orig| in a right-associative tree of type |type|
70
+ binary_right_assoc: |orig, other, type| {
71
+ cursor = orig
72
+ loop {
73
+ unless(cursor.second.is_a?(type)) { break }
74
+ cursor = cursor.second
75
+ }
76
+ cursor.second = type.new(first:cursor.second, second:other)
77
+ orig
78
+ }
79
+ }
80
+
81
+ NegativePredicate << {
82
+ # Invert the polarity of the predicate instead of nesting the predicate
83
+ "!": PositivePredicate.new(inner:inner)
84
+ }
85
+
86
+ PositivePredicate << {
87
+ # Invert the polarity of the predicate instead of nesting the predicate
88
+ "!": NegativePredicate.new(inner:inner)
89
+ }
90
+
91
+ OrderedChoice << {
92
+ # Build a right-associative tree if the first operand of another "/"
93
+ "/": |other|
94
+ private.binary_right_assoc(self, other, OrderedChoice)
95
+ }
96
+
97
+ Concatenation << {
98
+ # Build a right-associative tree if the first operand of another "+"
99
+ "+": |other=false|
100
+ other
101
+ &? private.binary_right_assoc(self, other, Concatenation)
102
+ ?? OneOrMore.new(inner:self)
103
+ }
104
+
105
+ ##
106
+ # Reduction and associated named captures implementation
107
+
108
+ Reduction << {
109
+ Environment < EmptyObject, BasicDecorators {
110
+ var captures # A Hash of capture names to values
111
+ var builder # The fallback delegate for methods that are not capture names
112
+
113
+ method_missing: |name, *args, &block|
114
+ captures.fetch(name) { builder.send(name, *args, &block) }
115
+
116
+ # Implement the action for the reduction in the '!' method.
117
+ # It will have access to the captures via method_missing.
118
+ "!": null
119
+ }
120
+
121
+ code: block.block.compiled_code
122
+ }
123
+ }