myco 0.1.4 → 0.1.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/myco/bootstrap/find_constant.rb +4 -11
- data/lib/myco/code_loader.rb +2 -1
- data/lib/myco/code_tools/AST/ConstantAccess.my +47 -3
- data/lib/myco/code_tools/AST/ConstantAccess.my.rb +13 -9
- data/lib/myco/code_tools/AST/ConstantAssignment.my +1 -5
- data/lib/myco/code_tools/AST/ConstantAssignment.my.rb +3 -9
- data/lib/myco/code_tools/AST/ToRuby.my +5 -2
- data/lib/myco/code_tools/AST/ToRuby.my.rb +7 -3
- data/lib/myco/code_tools/AST.my +1 -0
- data/lib/myco/code_tools/AST.my.rb +9 -1
- data/lib/myco/code_tools/Parser.my +24 -0
- data/lib/myco/code_tools/Parser.my.rb +25 -0
- data/lib/myco/code_tools/parser/MycoBuilder.my +67 -0
- data/lib/myco/code_tools/parser/MycoBuilder.my.rb +99 -0
- data/lib/myco/code_tools/parser/MycoCharacterClasses.my +20 -0
- data/lib/myco/code_tools/parser/MycoCharacterClasses.my.rb +56 -0
- data/lib/myco/code_tools/parser/MycoGrammar.my +564 -0
- data/lib/myco/code_tools/parser/MycoGrammar.my.rb +1851 -0
- data/lib/myco/code_tools/parser/MycoTokens.my +78 -0
- data/lib/myco/code_tools/parser/MycoTokens.my.rb +170 -0
- data/lib/myco/code_tools/parser/pegleromyces/lib/pegleromyces/Builder.my +4 -0
- data/lib/myco/code_tools/parser/pegleromyces/lib/pegleromyces/Builder.my.rb +5 -0
- data/lib/myco/code_tools/parser/pegleromyces/lib/pegleromyces/BytecodeHelpers.my +142 -0
- data/lib/myco/code_tools/parser/pegleromyces/lib/pegleromyces/BytecodeHelpers.my.rb +181 -0
- data/lib/myco/code_tools/parser/pegleromyces/lib/pegleromyces/BytecodeInstructions.my +420 -0
- data/lib/myco/code_tools/parser/pegleromyces/lib/pegleromyces/BytecodeInstructions.my.rb +415 -0
- data/lib/myco/code_tools/parser/pegleromyces/lib/pegleromyces/BytecodeParser.my +137 -0
- data/lib/myco/code_tools/parser/pegleromyces/lib/pegleromyces/BytecodeParser.my.rb +237 -0
- data/lib/myco/code_tools/parser/pegleromyces/lib/pegleromyces/Constructions.my +183 -0
- data/lib/myco/code_tools/parser/pegleromyces/lib/pegleromyces/Constructions.my.rb +370 -0
- data/lib/myco/code_tools/parser/pegleromyces/lib/pegleromyces/Grammar.my +65 -0
- data/lib/myco/code_tools/parser/pegleromyces/lib/pegleromyces/Grammar.my.rb +83 -0
- data/lib/myco/code_tools/parser/pegleromyces/lib/pegleromyces/Instructions.my +139 -0
- data/lib/myco/code_tools/parser/pegleromyces/lib/pegleromyces/Instructions.my.rb +284 -0
- data/lib/myco/code_tools/parser/pegleromyces/lib/pegleromyces/Machine.my +37 -0
- data/lib/myco/code_tools/parser/pegleromyces/lib/pegleromyces/Machine.my.rb +24 -0
- data/lib/myco/code_tools/parser/pegleromyces/lib/pegleromyces/Parser.my +42 -0
- data/lib/myco/code_tools/parser/pegleromyces/lib/pegleromyces/Parser.my.rb +52 -0
- data/lib/myco/code_tools/parser/pegleromyces/lib/pegleromyces/Patterns.my +123 -0
- data/lib/myco/code_tools/parser/pegleromyces/lib/pegleromyces/Patterns.my.rb +164 -0
- data/lib/myco/code_tools/parser/pegleromyces/lib/pegleromyces/Processor.my +236 -0
- data/lib/myco/code_tools/parser/pegleromyces/lib/pegleromyces/Processor.my.rb +339 -0
- data/lib/myco/code_tools/parser/pegleromyces/lib/pegleromyces.my +15 -0
- data/lib/myco/code_tools/parser/pegleromyces/lib/pegleromyces.my.rb +14 -0
- data/lib/myco/code_tools.rb +1 -1
- data/lib/myco/version.rb +1 -1
- data/lib/myco.rb +2 -0
- metadata +44 -25
- data/lib/myco/code_tools/parser/peg_parser.rb +0 -7182
- 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
|
+
}
|