myco 0.1.7 → 0.1.8
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/add_method.rb +38 -0
- data/lib/myco/bootstrap/component.rb +43 -21
- data/lib/myco/bootstrap/find_constant.rb +73 -25
- data/lib/myco/bootstrap/instance.rb +96 -25
- data/lib/myco/bootstrap/meme.rb +18 -12
- data/lib/myco/bootstrap/tuple.rb +13 -0
- data/lib/myco/bootstrap/undefined.rb +9 -0
- data/lib/myco/bootstrap/void.rb +5 -4
- data/lib/myco/bootstrap.my +24 -13
- data/lib/myco/bootstrap.my.rb +41 -4
- data/lib/myco/bootstrap.rb +4 -0
- data/lib/myco/code_loader.rb +11 -9
- data/lib/myco/code_tools/AST/Block.my.rb +2 -2
- data/lib/myco/code_tools/AST/ConstantAccess.my.rb +4 -4
- data/lib/myco/code_tools/AST/ConstantAssignment.my.rb +4 -4
- data/lib/myco/code_tools/AST/Invoke.my +1 -1
- data/lib/myco/code_tools/AST/Invoke.my.rb +1 -1
- data/lib/myco/code_tools/AST/Node.my +2 -4
- data/lib/myco/code_tools/AST/Node.my.rb +3 -3
- data/lib/myco/code_tools/AST/PipeOperator.my.rb +1 -1
- data/lib/myco/code_tools/AST/ToRuby.my.rb +8 -8
- data/lib/myco/code_tools/AST/misc.my.rb +1 -1
- data/lib/myco/code_tools/Parser.my +8 -15
- data/lib/myco/code_tools/Parser.my.rb +8 -14
- data/lib/myco/code_tools/parser/MycoBuilder.my +3 -4
- data/lib/myco/code_tools/parser/MycoBuilder.my.rb +5 -6
- data/lib/myco/code_tools/parser/pegleromyces/lib/pegleromyces/BytecodeHelpers.my +8 -4
- data/lib/myco/code_tools/parser/pegleromyces/lib/pegleromyces/BytecodeHelpers.my.rb +5 -5
- data/lib/myco/code_tools/parser/pegleromyces/lib/pegleromyces/BytecodeInstructions.my +2 -2
- data/lib/myco/code_tools/parser/pegleromyces/lib/pegleromyces/BytecodeInstructions.my.rb +12 -12
- data/lib/myco/code_tools/parser/pegleromyces/lib/pegleromyces/BytecodeParser.my +54 -44
- data/lib/myco/code_tools/parser/pegleromyces/lib/pegleromyces/BytecodeParser.my.rb +69 -83
- data/lib/myco/code_tools/parser/pegleromyces/lib/pegleromyces/Grammar.my +18 -8
- data/lib/myco/code_tools/parser/pegleromyces/lib/pegleromyces/Grammar.my.rb +24 -10
- data/lib/myco/code_tools/parser/pegleromyces/lib/pegleromyces/Machine.my.rb +1 -1
- data/lib/myco/code_tools/parser/pegleromyces/lib/pegleromyces/Parser.my +1 -1
- data/lib/myco/code_tools/parser/pegleromyces/lib/pegleromyces/Parser.my.rb +1 -2
- data/lib/myco/code_tools/parser/pegleromyces/lib/pegleromyces/Patterns.my +1 -1
- data/lib/myco/code_tools/parser/pegleromyces/lib/pegleromyces/Patterns.my.rb +1 -1
- data/lib/myco/code_tools/parser/pegleromyces/lib/pegleromyces/Processor.my +3 -3
- data/lib/myco/code_tools/parser/pegleromyces/lib/pegleromyces/Processor.my.rb +5 -6
- data/lib/myco/code_tools/parser/pegleromyces/spec/BasicSpec.my +35 -0
- data/lib/myco/code_tools/parser/pegleromyces/spec/BasicSpec.my.rb +35 -0
- data/lib/myco/code_tools/parser/pegleromyces/spec/Builder.test.my +10 -0
- data/lib/myco/code_tools/parser/pegleromyces/spec/Builder.test.my.rb +9 -0
- data/lib/myco/code_tools/parser/pegleromyces/spec/BytecodeInstructions.test.my +10 -0
- data/lib/myco/code_tools/parser/pegleromyces/spec/BytecodeInstructions.test.my.rb +9 -0
- data/lib/myco/code_tools/parser/pegleromyces/spec/BytecodeParser.test.my +81 -0
- data/lib/myco/code_tools/parser/pegleromyces/spec/BytecodeParser.test.my.rb +209 -0
- data/lib/myco/code_tools/parser/pegleromyces/spec/Constructions.test.my +229 -0
- data/lib/myco/code_tools/parser/pegleromyces/spec/Constructions.test.my.rb +663 -0
- data/lib/myco/code_tools/parser/pegleromyces/spec/Grammar.test.my +10 -0
- data/lib/myco/code_tools/parser/pegleromyces/spec/Grammar.test.my.rb +9 -0
- data/lib/myco/code_tools/parser/pegleromyces/spec/Instructions.test.my +10 -0
- data/lib/myco/code_tools/parser/pegleromyces/spec/Instructions.test.my.rb +9 -0
- data/lib/myco/code_tools/parser/pegleromyces/spec/Machine.test.my +13 -0
- data/lib/myco/code_tools/parser/pegleromyces/spec/Machine.test.my.rb +20 -0
- data/lib/myco/code_tools/parser/pegleromyces/spec/Parser.test.my +54 -0
- data/lib/myco/code_tools/parser/pegleromyces/spec/Parser.test.my.rb +215 -0
- data/lib/myco/code_tools/parser/pegleromyces/spec/Patterns.test.my +156 -0
- data/lib/myco/code_tools/parser/pegleromyces/spec/Patterns.test.my.rb +334 -0
- data/lib/myco/code_tools/parser/pegleromyces/spec/Processor.test.my +10 -0
- data/lib/myco/code_tools/parser/pegleromyces/spec/Processor.test.my.rb +9 -0
- data/lib/myco/code_tools/parser/pegleromyces/spec/run.my +20 -0
- data/lib/myco/code_tools/parser/pegleromyces/spec/run.my.rb +16 -0
- data/lib/myco/core/BasicDecorators.my +19 -11
- data/lib/myco/core/BasicDecorators.my.rb +24 -20
- data/lib/myco/core/BasicObject.my +12 -7
- data/lib/myco/core/BasicObject.my.rb +50 -44
- data/lib/myco/core/Category.my +12 -2
- data/lib/myco/core/Category.my.rb +15 -7
- data/lib/myco/core/Decorator.my +1 -1
- data/lib/myco/core/Decorator.my.rb +8 -10
- data/lib/myco/core/FileToplevel.my +3 -3
- data/lib/myco/core/FileToplevel.my.rb +4 -6
- data/lib/myco/core/Object.my +7 -10
- data/lib/myco/core/Object.my.rb +11 -17
- data/lib/myco/core/Ruby.my +6 -0
- data/lib/myco/core/Ruby.my.rb +16 -0
- data/lib/myco/core/Switch.my +1 -1
- data/lib/myco/core/Switch.my.rb +1 -1
- data/lib/myco/core.my +4 -0
- data/lib/myco/core.my.rb +7 -0
- data/lib/myco/dev/call_sites.rb +39 -0
- data/lib/myco/dev/counter.rb +26 -0
- data/lib/myco/dev.rb +3 -0
- data/lib/myco/eval.rb +1 -1
- data/lib/myco/tools/BasicCommand.my.rb +1 -1
- data/lib/myco/version.rb +1 -1
- data/lib/myco.rb +2 -3
- metadata +53 -20
- data/lib/myco/bootstrap/evaluator.rb +0 -58
@@ -0,0 +1,9 @@
|
|
1
|
+
|
2
|
+
::Myco::Component.new([::Myco::FileToplevel], ::Myco.cscope.for_method_definition, __FILE__, __LINE__)
|
3
|
+
.tap { |__c__| __c__.__last__ = __c__.component_eval {(::Myco::Component.new([::Myco.find_constant(:BasicSpec)], ::Myco.cscope.for_method_definition, __FILE__, __LINE__)
|
4
|
+
.tap { |__c__| __c__.__last__ = __c__.component_eval {(
|
5
|
+
declare_meme(:name, [], nil, ::Myco.cscope.dup) { |*| ("Builder")}
|
6
|
+
declare_meme(:new_builder, [], nil, ::Myco.cscope.dup) { |*| (::Myco::Component.new([::Myco.find_constant(:Builder)], ::Myco.cscope.for_method_definition, __FILE__, __LINE__)
|
7
|
+
.tap { |__c__| __c__.__last__ = __c__.component_eval {nil}}.instance)}
|
8
|
+
__category__(:tests).component_eval {(declare_meme(:exists, [[:it, []]], nil, ::Myco.cscope.dup) { |*| (self.assert(self.new_builder))})}
|
9
|
+
)}}.instance)}}.instance
|
@@ -0,0 +1,9 @@
|
|
1
|
+
|
2
|
+
::Myco::Component.new([::Myco::FileToplevel], ::Myco.cscope.for_method_definition, __FILE__, __LINE__)
|
3
|
+
.tap { |__c__| __c__.__last__ = __c__.component_eval {(::Myco::Component.new([::Myco.find_constant(:BasicSpec)], ::Myco.cscope.for_method_definition, __FILE__, __LINE__)
|
4
|
+
.tap { |__c__| __c__.__last__ = __c__.component_eval {(
|
5
|
+
declare_meme(:name, [], nil, ::Myco.cscope.dup) { |*| ("BytecodeInstructions")}
|
6
|
+
declare_meme(:instructions, [], nil, ::Myco.cscope.dup) { |*| (::Myco::Component.new([::Myco.find_constant(:BytecodeInstructions)], ::Myco.cscope.for_method_definition, __FILE__, __LINE__)
|
7
|
+
.tap { |__c__| __c__.__last__ = __c__.component_eval {nil}}.instance)}
|
8
|
+
__category__(:tests).component_eval {(declare_meme(:exists, [[:it, []]], nil, ::Myco.cscope.dup) { |*| (self.assert(self.instructions))})}
|
9
|
+
)}}.instance)}}.instance
|
@@ -0,0 +1,81 @@
|
|
1
|
+
|
2
|
+
BasicSpec {
|
3
|
+
name: "BytecodeParser"
|
4
|
+
|
5
|
+
new_parser: BytecodeParser { }
|
6
|
+
|
7
|
+
[tests]
|
8
|
+
|
9
|
+
it "can match from a tiny grammar": {
|
10
|
+
parser = new_parser
|
11
|
+
parser.grammar = Grammar {
|
12
|
+
[rules]
|
13
|
+
rule root:
|
14
|
+
str('abc') / str('x') + set('Yy') + !str('y') + !!range('a','z') + any
|
15
|
+
}
|
16
|
+
state = parser.parse('xyz')
|
17
|
+
assert_equal(state.end_idx, 3)
|
18
|
+
}
|
19
|
+
|
20
|
+
it "can match from a grammar with multiplicit patterns": {
|
21
|
+
parser = new_parser
|
22
|
+
parser.grammar = Grammar {
|
23
|
+
[rules]
|
24
|
+
rule root: str('x').+ + str('y').* + str('z').-
|
25
|
+
}
|
26
|
+
state = parser.parse('xxz')
|
27
|
+
assert_equal(state.end_idx, 3)
|
28
|
+
}
|
29
|
+
|
30
|
+
it "can match from a grammar with rule calls": {
|
31
|
+
parser = new_parser
|
32
|
+
parser.grammar = Grammar {
|
33
|
+
[rules]
|
34
|
+
rule root: unintended / intended
|
35
|
+
rule unintended: abc
|
36
|
+
rule intended: x + any_y + not_y + any_lower
|
37
|
+
|
38
|
+
rule abc: str('abc')
|
39
|
+
rule x: str('x')
|
40
|
+
rule any_y: set('Yy')
|
41
|
+
rule not_y: !str('y')
|
42
|
+
rule lower: range('a','z')
|
43
|
+
rule any_lower: !!lower + any
|
44
|
+
}
|
45
|
+
state = parser.parse('xyz')
|
46
|
+
assert_equal(state.end_idx, 3)
|
47
|
+
}
|
48
|
+
|
49
|
+
it "skips memoized rule calls without result corruption": {
|
50
|
+
parser = new_parser
|
51
|
+
parser.grammar = Grammar {
|
52
|
+
[rules]
|
53
|
+
rule root: moot
|
54
|
+
rule moot:
|
55
|
+
(array[:root] + str('NO')) / (array[:root] + str('NOPE')) / array[:root]
|
56
|
+
rule array:
|
57
|
+
r(str('[').token(:foo)[:t0] + (!str(']') + any).*[:list] + str(']'))
|
58
|
+
{ [:array, t0.line, *list.map(&:to_sym)] }
|
59
|
+
}
|
60
|
+
state = parser.parse('[abc]')
|
61
|
+
assert(state.end_idx)
|
62
|
+
assert_equal(state.result[:root], [:array, 1, :a, :b, :c])
|
63
|
+
}
|
64
|
+
|
65
|
+
it "can save a parser to a file to load and run it later": {
|
66
|
+
parser = new_parser
|
67
|
+
parser.grammar = Grammar {
|
68
|
+
[rules]
|
69
|
+
rule root: (r(character.+[:clist]) { clist })[:root]
|
70
|
+
rule character: r(any[:text]) { text.to_sym }
|
71
|
+
}
|
72
|
+
state = parser.parse('xyz')
|
73
|
+
assert_equal(state.result.fetch(:root), [:x, :y, :z])
|
74
|
+
parser.save_prototype("/tmp/pegleromyces_output.my.rbc")
|
75
|
+
|
76
|
+
parser = new_parser
|
77
|
+
parser.load_prototype("/tmp/pegleromyces_output.my.rbc")
|
78
|
+
state = parser.parse('xyz')
|
79
|
+
assert_equal(state.result.fetch(:root), [:x, :y, :z])
|
80
|
+
}
|
81
|
+
}
|
@@ -0,0 +1,209 @@
|
|
1
|
+
|
2
|
+
::Myco::Component.new([::Myco::FileToplevel], ::Myco.cscope.for_method_definition, __FILE__, __LINE__)
|
3
|
+
.tap { |__c__| __c__.__last__ = __c__.component_eval {(::Myco::Component.new([::Myco.find_constant(:BasicSpec)], ::Myco.cscope.for_method_definition, __FILE__, __LINE__)
|
4
|
+
.tap { |__c__| __c__.__last__ = __c__.component_eval {(
|
5
|
+
declare_meme(:name, [], nil, ::Myco.cscope.dup) { |*| ("BytecodeParser")}
|
6
|
+
declare_meme(:new_parser, [], nil, ::Myco.cscope.dup) { |*| (::Myco::Component.new([::Myco.find_constant(:BytecodeParser)], ::Myco.cscope.for_method_definition, __FILE__, __LINE__)
|
7
|
+
.tap { |__c__| __c__.__last__ = __c__.component_eval {nil}}.instance)}
|
8
|
+
__category__(:tests).component_eval {(
|
9
|
+
declare_meme(:"can match from a tiny grammar", [[:it, []]], nil, ::Myco.cscope.dup) { |*| (
|
10
|
+
parser = self.new_parser
|
11
|
+
parser.__send__(
|
12
|
+
:grammar=,
|
13
|
+
::Myco::Component.new([::Myco.find_constant(:Grammar)], ::Myco.cscope.for_method_definition, __FILE__, __LINE__)
|
14
|
+
.tap { |__c__| __c__.__last__ = __c__.component_eval {(__category__(:rules).component_eval {(declare_meme(:root, [[:rule, []]], nil, ::Myco.cscope.dup) { |*| (self.str("abc").__send__(
|
15
|
+
:/,
|
16
|
+
self.str("x")
|
17
|
+
).__send__(
|
18
|
+
:+,
|
19
|
+
self.set("Yy")
|
20
|
+
).__send__(
|
21
|
+
:+,
|
22
|
+
self.str("y").__send__(:!)
|
23
|
+
).__send__(
|
24
|
+
:+,
|
25
|
+
self.range(
|
26
|
+
"a",
|
27
|
+
"z"
|
28
|
+
).__send__(:!).__send__(:!)
|
29
|
+
).__send__(
|
30
|
+
:+,
|
31
|
+
self.any
|
32
|
+
))})})}}.instance
|
33
|
+
)
|
34
|
+
state = parser.parse("xyz")
|
35
|
+
self.assert_equal(
|
36
|
+
state.end_idx,
|
37
|
+
3
|
38
|
+
)
|
39
|
+
)}
|
40
|
+
declare_meme(:"can match from a grammar with multiplicit patterns", [[:it, []]], nil, ::Myco.cscope.dup) { |*| (
|
41
|
+
parser = self.new_parser
|
42
|
+
parser.__send__(
|
43
|
+
:grammar=,
|
44
|
+
::Myco::Component.new([::Myco.find_constant(:Grammar)], ::Myco.cscope.for_method_definition, __FILE__, __LINE__)
|
45
|
+
.tap { |__c__| __c__.__last__ = __c__.component_eval {(__category__(:rules).component_eval {(declare_meme(:root, [[:rule, []]], nil, ::Myco.cscope.dup) { |*| (self.str("x").__send__(:+).__send__(
|
46
|
+
:+,
|
47
|
+
self.str("y").__send__(:*)
|
48
|
+
).__send__(
|
49
|
+
:+,
|
50
|
+
self.str("z").__send__(:-)
|
51
|
+
))})})}}.instance
|
52
|
+
)
|
53
|
+
state = parser.parse("xxz")
|
54
|
+
self.assert_equal(
|
55
|
+
state.end_idx,
|
56
|
+
3
|
57
|
+
)
|
58
|
+
)}
|
59
|
+
declare_meme(:"can match from a grammar with rule calls", [[:it, []]], nil, ::Myco.cscope.dup) { |*| (
|
60
|
+
parser = self.new_parser
|
61
|
+
parser.__send__(
|
62
|
+
:grammar=,
|
63
|
+
::Myco::Component.new([::Myco.find_constant(:Grammar)], ::Myco.cscope.for_method_definition, __FILE__, __LINE__)
|
64
|
+
.tap { |__c__| __c__.__last__ = __c__.component_eval {(__category__(:rules).component_eval {(
|
65
|
+
declare_meme(:root, [[:rule, []]], nil, ::Myco.cscope.dup) { |*| (self.unintended.__send__(
|
66
|
+
:/,
|
67
|
+
self.intended
|
68
|
+
))}
|
69
|
+
declare_meme(:unintended, [[:rule, []]], nil, ::Myco.cscope.dup) { |*| (self.abc)}
|
70
|
+
declare_meme(:intended, [[:rule, []]], nil, ::Myco.cscope.dup) { |*| (self.x.__send__(
|
71
|
+
:+,
|
72
|
+
self.any_y
|
73
|
+
).__send__(
|
74
|
+
:+,
|
75
|
+
self.not_y
|
76
|
+
).__send__(
|
77
|
+
:+,
|
78
|
+
self.any_lower
|
79
|
+
))}
|
80
|
+
declare_meme(:abc, [[:rule, []]], nil, ::Myco.cscope.dup) { |*| (self.str("abc"))}
|
81
|
+
declare_meme(:x, [[:rule, []]], nil, ::Myco.cscope.dup) { |*| (self.str("x"))}
|
82
|
+
declare_meme(:any_y, [[:rule, []]], nil, ::Myco.cscope.dup) { |*| (self.set("Yy"))}
|
83
|
+
declare_meme(:not_y, [[:rule, []]], nil, ::Myco.cscope.dup) { |*| (self.str("y").__send__(:!))}
|
84
|
+
declare_meme(:lower, [[:rule, []]], nil, ::Myco.cscope.dup) { |*| (self.range(
|
85
|
+
"a",
|
86
|
+
"z"
|
87
|
+
))}
|
88
|
+
declare_meme(:any_lower, [[:rule, []]], nil, ::Myco.cscope.dup) { |*| (self.lower.__send__(:!).__send__(:!).__send__(
|
89
|
+
:+,
|
90
|
+
self.any
|
91
|
+
))}
|
92
|
+
)})}}.instance
|
93
|
+
)
|
94
|
+
state = parser.parse("xyz")
|
95
|
+
self.assert_equal(
|
96
|
+
state.end_idx,
|
97
|
+
3
|
98
|
+
)
|
99
|
+
)}
|
100
|
+
declare_meme(:"skips memoized rule calls without result corruption", [[:it, []]], nil, ::Myco.cscope.dup) { |*| (
|
101
|
+
parser = self.new_parser
|
102
|
+
parser.__send__(
|
103
|
+
:grammar=,
|
104
|
+
::Myco::Component.new([::Myco.find_constant(:Grammar)], ::Myco.cscope.for_method_definition, __FILE__, __LINE__)
|
105
|
+
.tap { |__c__| __c__.__last__ = __c__.component_eval {(__category__(:rules).component_eval {(
|
106
|
+
declare_meme(:root, [[:rule, []]], nil, ::Myco.cscope.dup) { |*| (self.moot)}
|
107
|
+
declare_meme(:moot, [[:rule, []]], nil, ::Myco.cscope.dup) { |*| (self.array.__send__(
|
108
|
+
:[],
|
109
|
+
:root
|
110
|
+
).__send__(
|
111
|
+
:+,
|
112
|
+
self.str("NO")
|
113
|
+
).__send__(
|
114
|
+
:/,
|
115
|
+
self.array.__send__(
|
116
|
+
:[],
|
117
|
+
:root
|
118
|
+
).__send__(
|
119
|
+
:+,
|
120
|
+
self.str("NOPE")
|
121
|
+
)
|
122
|
+
).__send__(
|
123
|
+
:/,
|
124
|
+
self.array.__send__(
|
125
|
+
:[],
|
126
|
+
:root
|
127
|
+
)
|
128
|
+
))}
|
129
|
+
declare_meme(:array, [[:rule, []]], nil, ::Myco.cscope.dup) { |*| (self.r(self.str("[").token(:foo).__send__(
|
130
|
+
:[],
|
131
|
+
:t0
|
132
|
+
).__send__(
|
133
|
+
:+,
|
134
|
+
self.str("]").__send__(:!).__send__(
|
135
|
+
:+,
|
136
|
+
self.any
|
137
|
+
).__send__(:*).__send__(
|
138
|
+
:[],
|
139
|
+
:list
|
140
|
+
)
|
141
|
+
).__send__(
|
142
|
+
:+,
|
143
|
+
self.str("]")
|
144
|
+
)) { || ([
|
145
|
+
:array,
|
146
|
+
self.__send__(:t0).line,
|
147
|
+
*self.list.map(&:to_sym)
|
148
|
+
])})}
|
149
|
+
)})}}.instance
|
150
|
+
)
|
151
|
+
state = parser.parse("[abc]")
|
152
|
+
self.assert(state.end_idx)
|
153
|
+
self.assert_equal(
|
154
|
+
state.result.__send__(
|
155
|
+
:[],
|
156
|
+
:root
|
157
|
+
),
|
158
|
+
[
|
159
|
+
:array,
|
160
|
+
1,
|
161
|
+
:a,
|
162
|
+
:b,
|
163
|
+
:c
|
164
|
+
]
|
165
|
+
)
|
166
|
+
)}
|
167
|
+
declare_meme(:"can save a parser to a file to load and run it later", [[:it, []]], nil, ::Myco.cscope.dup) { |*| (
|
168
|
+
parser = self.new_parser
|
169
|
+
parser.__send__(
|
170
|
+
:grammar=,
|
171
|
+
::Myco::Component.new([::Myco.find_constant(:Grammar)], ::Myco.cscope.for_method_definition, __FILE__, __LINE__)
|
172
|
+
.tap { |__c__| __c__.__last__ = __c__.component_eval {(__category__(:rules).component_eval {(
|
173
|
+
declare_meme(:root, [[:rule, []]], nil, ::Myco.cscope.dup) { |*| (self.r(self.character.__send__(:+).__send__(
|
174
|
+
:[],
|
175
|
+
:clist
|
176
|
+
)) { || (self.clist)}.__send__(
|
177
|
+
:[],
|
178
|
+
:root
|
179
|
+
))}
|
180
|
+
declare_meme(:character, [[:rule, []]], nil, ::Myco.cscope.dup) { |*| (self.r(self.any.__send__(
|
181
|
+
:[],
|
182
|
+
:text
|
183
|
+
)) { || (self.text.to_sym)})}
|
184
|
+
)})}}.instance
|
185
|
+
)
|
186
|
+
state = parser.parse("xyz")
|
187
|
+
self.assert_equal(
|
188
|
+
state.result.fetch(:root),
|
189
|
+
[
|
190
|
+
:x,
|
191
|
+
:y,
|
192
|
+
:z
|
193
|
+
]
|
194
|
+
)
|
195
|
+
parser.save_prototype("/tmp/pegleromyces_output.my.rbc")
|
196
|
+
parser = self.new_parser
|
197
|
+
parser.load_prototype("/tmp/pegleromyces_output.my.rbc")
|
198
|
+
state = parser.parse("xyz")
|
199
|
+
self.assert_equal(
|
200
|
+
state.result.fetch(:root),
|
201
|
+
[
|
202
|
+
:x,
|
203
|
+
:y,
|
204
|
+
:z
|
205
|
+
]
|
206
|
+
)
|
207
|
+
)}
|
208
|
+
)}
|
209
|
+
)}}.instance)}}.instance
|
@@ -0,0 +1,229 @@
|
|
1
|
+
|
2
|
+
BasicSpec {
|
3
|
+
name: "Constructions"
|
4
|
+
|
5
|
+
[tests]
|
6
|
+
|
7
|
+
specify "AnyCharacter creates a single any instruction": {
|
8
|
+
construct = Constructions::AnyCharacter.new
|
9
|
+
assert_equal(construct.sequence, [
|
10
|
+
[:any, 1]
|
11
|
+
])
|
12
|
+
}
|
13
|
+
|
14
|
+
specify "Character creates a single char instruction": {
|
15
|
+
construct = Constructions::Character.new(code:120)
|
16
|
+
assert_equal(construct.sequence, [
|
17
|
+
[:char, 120]
|
18
|
+
])
|
19
|
+
}
|
20
|
+
|
21
|
+
specify "CharacterString creates a string of char instructions": {
|
22
|
+
construct = Constructions::CharacterString.new(codes:[120,121,122])
|
23
|
+
assert_equal(construct.sequence, [
|
24
|
+
[:char, 120]
|
25
|
+
[:char, 121]
|
26
|
+
[:char, 122]
|
27
|
+
])
|
28
|
+
}
|
29
|
+
|
30
|
+
specify "CharacterSet creates a single charset instruction": {
|
31
|
+
construct = Constructions::CharacterSet.new(codes:[120,121,122])
|
32
|
+
expected_table = [120,121,122].map |code| { [code,true] }.to_h
|
33
|
+
assert_equal(construct.sequence, [
|
34
|
+
[:charset, expected_table]
|
35
|
+
])
|
36
|
+
}
|
37
|
+
|
38
|
+
specify "CharacterRange creates a single charrange instruction": {
|
39
|
+
construct = Constructions::CharacterRange.new(start:120, stop:122)
|
40
|
+
assert_equal(construct.sequence, [
|
41
|
+
[:charrange, 120, 122]
|
42
|
+
])
|
43
|
+
}
|
44
|
+
|
45
|
+
specify "NegativePredicate assembles choice, fail_twice instructions": {
|
46
|
+
a = Constructions::CharacterString.new(codes:[120,121,122])
|
47
|
+
construct = Constructions::NegativePredicate.new(inner:a)
|
48
|
+
assert_equal(construct.sequence, [
|
49
|
+
[:choice, 5] # ip+5 == L1
|
50
|
+
[:char, 120]
|
51
|
+
[:char, 121]
|
52
|
+
[:char, 122]
|
53
|
+
[:fail_twice]
|
54
|
+
]) # (L1)
|
55
|
+
}
|
56
|
+
|
57
|
+
specify "PositivePredicate assembles choice, commit, fail instructions": {
|
58
|
+
a = Constructions::CharacterString.new(codes:[120,121,122])
|
59
|
+
construct = Constructions::PositivePredicate.new(inner:a)
|
60
|
+
assert_equal(construct.sequence, [
|
61
|
+
[:choice, 7] # ip+7 == L1
|
62
|
+
[:choice, 4] # ip+4 == L2
|
63
|
+
[:char, 120]
|
64
|
+
[:char, 121]
|
65
|
+
[:char, 122]
|
66
|
+
[:commit, 1] # ip+1 == L3 (L2)
|
67
|
+
[:fail] # (L3)
|
68
|
+
]) # (L1)
|
69
|
+
}
|
70
|
+
|
71
|
+
specify "OneOrMore assembles UNOPTIMIZED instructions": {
|
72
|
+
a = Constructions::CharacterString.new(codes:[120,121,122])
|
73
|
+
construct = Constructions::OneOrMore.new(inner:a)
|
74
|
+
assert_equal(construct.sequence, [
|
75
|
+
[:char, 120] # TODO: optimize and eliminate the double specification here
|
76
|
+
[:char, 121]
|
77
|
+
[:char, 122]
|
78
|
+
[:choice, 5] # ip+5 == L2
|
79
|
+
[:char, 120] # (L1)
|
80
|
+
[:char, 121]
|
81
|
+
[:char, 122]
|
82
|
+
[:partial_commit, -3] # ip-3 == L1
|
83
|
+
]) # (L2)
|
84
|
+
}
|
85
|
+
|
86
|
+
specify "ZeroOrOne assembles choice and commit instructions": {
|
87
|
+
a = Constructions::CharacterString.new(codes:[120,121,122])
|
88
|
+
construct = Constructions::ZeroOrOne.new(inner:a)
|
89
|
+
assert_equal(construct.sequence, [
|
90
|
+
[:choice, 5] # ip+5 == L1
|
91
|
+
[:char, 120]
|
92
|
+
[:char, 121]
|
93
|
+
[:char, 122]
|
94
|
+
[:commit, 1] # ip+1 == L1
|
95
|
+
]) # (L1)
|
96
|
+
}
|
97
|
+
|
98
|
+
specify "ZeroOrMore assembles choice and partial_commit instructions": {
|
99
|
+
a = Constructions::CharacterString.new(codes:[120,121,122])
|
100
|
+
construct = Constructions::ZeroOrMore.new(inner:a)
|
101
|
+
assert_equal(construct.sequence, [
|
102
|
+
[:choice, 5] # ip+5 == L2
|
103
|
+
[:char, 120] # (L1)
|
104
|
+
[:char, 121]
|
105
|
+
[:char, 122]
|
106
|
+
[:partial_commit, -3] # ip-3 == L1
|
107
|
+
]) # (L2)
|
108
|
+
}
|
109
|
+
|
110
|
+
specify "ZeroOrMore<CharacterSet> creates a single span instruction": {
|
111
|
+
a = Constructions::CharacterSet.new(codes:[120,121,122])
|
112
|
+
construct = Constructions::ZeroOrMore.new(inner:a)
|
113
|
+
expected_table = [120,121,122].map |code| { [code,true] }.to_h
|
114
|
+
assert_equal(construct.sequence, [
|
115
|
+
[:span, expected_table]
|
116
|
+
])
|
117
|
+
}
|
118
|
+
|
119
|
+
specify "OrderedChoice assembles choice and commit instructions": {
|
120
|
+
a = Constructions::CharacterString.new(codes:[110,111,112])
|
121
|
+
b = Constructions::CharacterString.new(codes:[120,121,122])
|
122
|
+
construct = Constructions::OrderedChoice.new(first:a, second:b)
|
123
|
+
assert_equal(construct.sequence, [
|
124
|
+
[:choice, 5] # ip+5 == L1
|
125
|
+
[:char, 110]
|
126
|
+
[:char, 111]
|
127
|
+
[:char, 112]
|
128
|
+
[:commit, 4] # ip+4 == L2
|
129
|
+
[:char, 120] # (L1)
|
130
|
+
[:char, 121]
|
131
|
+
[:char, 122]
|
132
|
+
]) # (L2)
|
133
|
+
|
134
|
+
a = Constructions::CharacterString.new(codes:[110,111,112])
|
135
|
+
b = Constructions::CharacterString.new(codes:[120,121,122])
|
136
|
+
c = Constructions::CharacterString.new(codes:[130,131,132])
|
137
|
+
construct = Constructions::OrderedChoice.new(first:b, second:c)
|
138
|
+
construct = Constructions::OrderedChoice.new(first:a, second:construct)
|
139
|
+
assert_equal(construct.sequence, [
|
140
|
+
[:choice, 5] # ip+5 == L1
|
141
|
+
[:char, 110]
|
142
|
+
[:char, 111]
|
143
|
+
[:char, 112]
|
144
|
+
[:commit, 9] # ip+9 == L2
|
145
|
+
[:choice, 5] # ip+5 == L3; (L1)
|
146
|
+
[:char, 120]
|
147
|
+
[:char, 121]
|
148
|
+
[:char, 122]
|
149
|
+
[:commit, 4] # ip+4 == L2
|
150
|
+
[:char, 130] # (L3)
|
151
|
+
[:char, 131]
|
152
|
+
[:char, 132]
|
153
|
+
]) # (L2)
|
154
|
+
}
|
155
|
+
|
156
|
+
specify "Concatenation simply concatenates the operands": {
|
157
|
+
a = Constructions::CharacterString.new(codes:[110,111,112])
|
158
|
+
b = Constructions::CharacterString.new(codes:[120,121,122])
|
159
|
+
construct = Constructions::Concatenation.new(first:a, second:b)
|
160
|
+
assert_equal(construct.sequence, [
|
161
|
+
[:char, 110]
|
162
|
+
[:char, 111]
|
163
|
+
[:char, 112]
|
164
|
+
[:char, 120]
|
165
|
+
[:char, 121]
|
166
|
+
[:char, 122]
|
167
|
+
])
|
168
|
+
}
|
169
|
+
|
170
|
+
specify "NamedCapture assembles capture instructions": {
|
171
|
+
a = Constructions::CharacterString.new(codes:[120,121,122])
|
172
|
+
construct = Constructions::NamedCapture.new(inner:a)
|
173
|
+
assert_equal(construct.sequence, [
|
174
|
+
[:capture, [:c_start]]
|
175
|
+
[:char, 120]
|
176
|
+
[:char, 121]
|
177
|
+
[:char, 122]
|
178
|
+
[:capture, [:c_end, construct.captargs]]
|
179
|
+
])
|
180
|
+
}
|
181
|
+
|
182
|
+
specify "NamedCapture of ZeroOrMore has a special multiplicit strategy": {
|
183
|
+
a = Constructions::CharacterString.new(codes:[120,121,122])
|
184
|
+
b = Constructions::ZeroOrMore.new(inner:a)
|
185
|
+
construct = Constructions::NamedCapture.new(inner:b)
|
186
|
+
assert_equal(construct.sequence, [
|
187
|
+
[:capture, [:m_start]]
|
188
|
+
[:choice, 6]
|
189
|
+
[:char, 120]
|
190
|
+
[:char, 121]
|
191
|
+
[:char, 122]
|
192
|
+
[:capture, [:m_split, null]]
|
193
|
+
[:partial_commit, -4]
|
194
|
+
[:capture, [:m_end, null]]
|
195
|
+
])
|
196
|
+
}
|
197
|
+
|
198
|
+
specify "NamedCapture of OneOrMore has a special multiplicit strategy": {
|
199
|
+
a = Constructions::CharacterString.new(codes:[120,121,122])
|
200
|
+
b = Constructions::OneOrMore.new(inner:a)
|
201
|
+
construct = Constructions::NamedCapture.new(inner:b)
|
202
|
+
assert_equal(construct.sequence, [
|
203
|
+
[:capture, [:m_start]]
|
204
|
+
[:char, 120]
|
205
|
+
[:char, 121]
|
206
|
+
[:char, 122]
|
207
|
+
[:capture, [:m_split, null]]
|
208
|
+
[:choice, 6]
|
209
|
+
[:char, 120]
|
210
|
+
[:char, 121]
|
211
|
+
[:char, 122]
|
212
|
+
[:capture, [:m_split, null]]
|
213
|
+
[:partial_commit, -4]
|
214
|
+
[:capture, [:m_end, null]]
|
215
|
+
])
|
216
|
+
}
|
217
|
+
|
218
|
+
specify "Reduction assembles capture instructions": {
|
219
|
+
a = Constructions::CharacterString.new(codes:[120,121,122])
|
220
|
+
construct = Constructions::Reduction.new(inner:a)
|
221
|
+
assert_equal(construct.sequence, [
|
222
|
+
[:capture, [:r_start]]
|
223
|
+
[:char, 120]
|
224
|
+
[:char, 121]
|
225
|
+
[:char, 122]
|
226
|
+
[:capture, [:r_end, construct.captargs]]
|
227
|
+
])
|
228
|
+
}
|
229
|
+
}
|