rattler 0.2.2 → 0.3.0
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.
- data/README.rdoc +83 -64
- data/features/grammar/comments.feature +24 -0
- data/features/grammar/list_matching.feature +41 -0
- data/features/grammar/symantic_action.feature +30 -12
- data/lib/rattler/back_end/parser_generator/assert_generator.rb +27 -27
- data/lib/rattler/back_end/parser_generator/choice_generator.rb +29 -29
- data/lib/rattler/back_end/parser_generator/direct_action_generator.rb +17 -17
- data/lib/rattler/back_end/parser_generator/disallow_generator.rb +27 -27
- data/lib/rattler/back_end/parser_generator/dispatch_action_generator.rb +17 -17
- data/lib/rattler/back_end/parser_generator/expr_generator.rb +129 -40
- data/lib/rattler/back_end/parser_generator/label_generator.rb +15 -15
- data/lib/rattler/back_end/parser_generator/list1_generator.rb +61 -0
- data/lib/rattler/back_end/parser_generator/list_generating.rb +71 -0
- data/lib/rattler/back_end/parser_generator/list_generator.rb +57 -0
- data/lib/rattler/back_end/parser_generator/one_or_more_generator.rb +14 -15
- data/lib/rattler/back_end/parser_generator/optional_generator.rb +24 -24
- data/lib/rattler/back_end/parser_generator/predicate_propogating.rb +9 -9
- data/lib/rattler/back_end/parser_generator/repeat_generating.rb +16 -16
- data/lib/rattler/back_end/parser_generator/sequence_generator.rb +40 -40
- data/lib/rattler/back_end/parser_generator/skip_generator.rb +18 -18
- data/lib/rattler/back_end/parser_generator/skip_propogating.rb +5 -5
- data/lib/rattler/back_end/parser_generator/sub_generating.rb +128 -0
- data/lib/rattler/back_end/parser_generator/token_generator.rb +15 -15
- data/lib/rattler/back_end/parser_generator/token_propogating.rb +1 -1
- data/lib/rattler/back_end/parser_generator/zero_or_more_generator.rb +12 -13
- data/lib/rattler/back_end/parser_generator.rb +10 -7
- data/lib/rattler/grammar/grammar_parser.rb +16 -21
- data/lib/rattler/grammar/metagrammar.rb +1039 -1035
- data/lib/rattler/grammar/rattler.rtlr +28 -28
- data/lib/rattler/parsers/action_code.rb +20 -9
- data/lib/rattler/parsers/fail.rb +7 -1
- data/lib/rattler/parsers/list.rb +57 -0
- data/lib/rattler/parsers/list1.rb +58 -0
- data/lib/rattler/parsers/parser_dsl.rb +60 -38
- data/lib/rattler/parsers.rb +5 -3
- data/lib/rattler/runtime/extended_packrat_parser.rb +88 -20
- data/lib/rattler/runtime/packrat_parser.rb +21 -14
- data/lib/rattler/runtime/parser.rb +74 -18
- data/lib/rattler/runtime/recursive_descent_parser.rb +15 -46
- data/spec/rattler/back_end/compiler_spec.rb +173 -107
- data/spec/rattler/back_end/parser_generator/list1_generator_spec.rb +304 -0
- data/spec/rattler/back_end/parser_generator/list_generator_spec.rb +288 -0
- data/spec/rattler/grammar/grammar_parser_spec.rb +65 -76
- data/spec/rattler/parsers/action_code_spec.rb +84 -34
- data/spec/rattler/parsers/direct_action_spec.rb +56 -34
- data/spec/rattler/parsers/fail_spec.rb +20 -0
- data/spec/rattler/parsers/list1_spec.rb +82 -0
- data/spec/rattler/parsers/list_spec.rb +82 -0
- data/spec/rattler/parsers/parser_dsl_spec.rb +48 -19
- data/spec/rattler/runtime/extended_packrat_parser_spec.rb +0 -1
- metadata +92 -173
- data/bin/rtlr.bat +0 -3
- data/lib/rattler/back_end/parser_generator/generator_helper.rb +0 -130
- data/lib/rattler/back_end/parser_generator/generators.rb +0 -86
- data/lib/rattler/back_end/parser_generator/nested_generators.rb +0 -15
- data/lib/rattler/back_end/parser_generator/top_level_generators.rb +0 -15
data/README.rdoc
CHANGED
@@ -14,13 +14,13 @@ A language syntax is specified in a grammar using the Rattler syntax. Parser
|
|
14
14
|
classes and modules can be generated statically using the "rtlr" command or
|
15
15
|
dynamically from strings.
|
16
16
|
|
17
|
-
{RDoc}[http://rubydoc.info/gems/rattler/0.2.
|
17
|
+
{RDoc}[http://rubydoc.info/gems/rattler/0.2.2/frames]
|
18
18
|
|
19
19
|
== FEATURES:
|
20
20
|
|
21
21
|
* Uses readable PEG-like grammars
|
22
22
|
* A packrat parser to cache results for backtracking
|
23
|
-
*
|
23
|
+
* An extended packrat parser that supports left-recursive grammars
|
24
24
|
* Whitespace can be specified in one place and skipped automatically
|
25
25
|
* Automatic and custom parse error reporting
|
26
26
|
* Optimizing parser generator
|
@@ -30,91 +30,109 @@ dynamically from strings.
|
|
30
30
|
|
31
31
|
== PROBLEMS/LIMITATIONS:
|
32
32
|
|
33
|
-
* Indirect left-recursion is not yet supported
|
34
33
|
* Optimizations are very limited at this point
|
35
34
|
* Only strings can be parsed, so files have to be read completely before parsing
|
36
|
-
* There are undoubtedly many bugs
|
35
|
+
* There are many holes in the tests so there are undoubtedly many bugs
|
37
36
|
|
38
37
|
== EXAMPLES:
|
39
38
|
|
40
39
|
=== Example 1: Statically generated parser class
|
41
40
|
|
42
|
-
====
|
41
|
+
==== json.rtlr:
|
43
42
|
|
44
|
-
parser
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
43
|
+
# JSON parser based on the grammar at http://www.json.org
|
44
|
+
|
45
|
+
parser JsonParser < Rattler::Runtime::PackratParser
|
46
|
+
|
47
|
+
%whitespace (SPACE+ | '/*' (! '*/' .)* '*/' | '//' [^\n]*)*
|
48
|
+
|
49
|
+
object <- ~'{' members ~'}' { object _ }
|
50
|
+
|
51
|
+
members <- pair *^ ','
|
52
|
+
|
53
|
+
pair <- string ~':' value
|
54
|
+
|
55
|
+
array <- ~'[' elements ~']'
|
56
|
+
|
57
|
+
elements <- value *^ ','
|
58
|
+
|
59
|
+
value <- string { string _ }
|
60
|
+
| number !DIGIT { _.to_f }
|
61
|
+
| object
|
62
|
+
| array
|
63
|
+
| `true` { :true }
|
64
|
+
| `false` { :false }
|
65
|
+
| `null` { :null }
|
66
|
+
| fail "value expected"
|
67
|
+
|
68
|
+
string <- @('"' ('\\' . | [^"])* '"')
|
69
|
+
|
70
|
+
number <- @('-'? ('0' | [1-9] DIGIT*) ('.' DIGIT+)? ([eE] [+-]? DIGIT+)?)
|
71
|
+
|
72
|
+
==== json_helper.rb:
|
73
|
+
|
74
|
+
module JsonHelper
|
75
|
+
|
76
|
+
def object(members)
|
77
|
+
Hash[*members.flatten(1)]
|
78
|
+
end
|
79
|
+
|
80
|
+
def string(expr)
|
81
|
+
eval expr, TOPLEVEL_BINDING
|
82
|
+
end
|
83
|
+
|
84
|
+
end
|
85
|
+
|
86
|
+
==== $ rtlr json.rtlr
|
62
87
|
|
63
|
-
|
64
|
-
calculator.rtlr -> calculator.rb
|
88
|
+
json.rtlr -> json_parser.rb
|
65
89
|
|
66
|
-
====
|
90
|
+
==== parse_json.rb:
|
67
91
|
|
68
92
|
require 'rubygems'
|
69
93
|
require 'rattler'
|
70
|
-
require '
|
94
|
+
require 'json_parser'
|
71
95
|
|
72
96
|
begin
|
73
|
-
|
97
|
+
p JsonParser.parse!(open(ARGV[0]) {|io| io.read })
|
74
98
|
rescue Rattler::Runtime::SyntaxError => e
|
75
99
|
puts e
|
76
100
|
end
|
77
101
|
|
78
102
|
=== Example 2: Statically generated grammar module
|
79
103
|
|
80
|
-
====
|
81
|
-
|
82
|
-
grammar CalculatorGrammar
|
83
|
-
|
84
|
-
%whitespace SPACE*
|
85
|
-
|
86
|
-
start <- expr EOF
|
104
|
+
==== json.rtlr:
|
87
105
|
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
primary <- ~'(' expr ~')'
|
97
|
-
| @(DIGIT+ ('.' DIGIT+)?) {|_| _.to_f }
|
106
|
+
# JSON parser based on the grammar at http://www.json.org
|
107
|
+
|
108
|
+
grammar JsonGrammar
|
109
|
+
|
110
|
+
%whitespace (SPACE+ | '/*' (! '*/' .)* '*/' | '//' [^\n]*)*
|
111
|
+
|
112
|
+
...
|
98
113
|
|
99
|
-
====
|
114
|
+
==== $ rtlr json.rtlr
|
100
115
|
|
101
|
-
|
102
|
-
calculator.rtlr -> calculator_grammar.rb
|
116
|
+
json.rtlr -> json_grammar.rb
|
103
117
|
|
104
|
-
====
|
118
|
+
==== json_parser.rb:
|
105
119
|
|
106
120
|
require 'rubygems'
|
107
121
|
require 'rattler'
|
108
|
-
require '
|
122
|
+
require 'json_grammar'
|
109
123
|
|
110
|
-
class
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
124
|
+
class JsonParser < Rattler::Runtime::PackratParser
|
125
|
+
|
126
|
+
include JsonGrammar
|
127
|
+
|
128
|
+
def object(members)
|
129
|
+
Hash[*members.flatten(1)]
|
130
|
+
end
|
131
|
+
|
132
|
+
def string(expr)
|
133
|
+
eval expr, TOPLEVEL_BINDING
|
134
|
+
end
|
135
|
+
|
118
136
|
end
|
119
137
|
|
120
138
|
=== Example 3: Dynamically generated parser class
|
@@ -127,17 +145,18 @@ dynamically from strings.
|
|
127
145
|
|
128
146
|
start <- expr EOF
|
129
147
|
|
130
|
-
expr <- expr ~'+' term
|
131
|
-
| expr ~'-' term
|
148
|
+
expr <- expr ~'+' term {|a, b| a + b }
|
149
|
+
| expr ~'-' term {|a, b| a - b }
|
132
150
|
| term
|
133
151
|
|
134
|
-
term <- term ~'*' primary
|
135
|
-
| term ~'/' primary
|
152
|
+
term <- term ~'*' primary {|a, b| a * b }
|
153
|
+
| term ~'/' primary {|a, b| a / b }
|
136
154
|
| primary
|
137
155
|
|
138
156
|
primary <- ~'(' expr ~')'
|
139
|
-
| @(DIGIT+
|
140
|
-
|
157
|
+
| @('-'? DIGIT+ '.' DIGIT+) { _.to_f }
|
158
|
+
| @('-'? DIGIT+) { _.to_i }
|
159
|
+
}, :type => :extended_packrat
|
141
160
|
|
142
161
|
begin
|
143
162
|
puts Calculator.parse!(expr)
|
@@ -0,0 +1,24 @@
|
|
1
|
+
Feature: Whitespace
|
2
|
+
|
3
|
+
Comments start with "#" and continue to the end of the line.
|
4
|
+
|
5
|
+
In order to clarify my grammars
|
6
|
+
As a language designer
|
7
|
+
I want to use comments
|
8
|
+
|
9
|
+
Scenario: Entire line as a comment
|
10
|
+
Given a grammar with:
|
11
|
+
"""
|
12
|
+
# match one or more alphanumeric or underscore characters
|
13
|
+
word <- @WORD+
|
14
|
+
"""
|
15
|
+
When I parse "foo"
|
16
|
+
Then the parse result should be "foo"
|
17
|
+
|
18
|
+
Scenario: Comment at the end of a line
|
19
|
+
Given a grammar with:
|
20
|
+
"""
|
21
|
+
word <- @WORD+ # WORD matches any alphanumeric or underscore character
|
22
|
+
"""
|
23
|
+
When I parse "foo"
|
24
|
+
Then the parse result should be "foo"
|
@@ -0,0 +1,41 @@
|
|
1
|
+
Feature: List Matching
|
2
|
+
|
3
|
+
An term expression followed by "*^" or "+^" and a separator expression means
|
4
|
+
to match a list of terms with separators between them. "*^" matches a list of
|
5
|
+
zero or more terms, "+^" matches a list of one or more term.
|
6
|
+
|
7
|
+
In order to clearly and easily match list expressions
|
8
|
+
As a language designer
|
9
|
+
I want to use a list-matching expression
|
10
|
+
|
11
|
+
Scenario Outline: Zero or more terms
|
12
|
+
Given a grammar with:
|
13
|
+
"""
|
14
|
+
words <- @WORD+ *^ ','
|
15
|
+
"""
|
16
|
+
When I parse <input>
|
17
|
+
Then the parse result should be <result>
|
18
|
+
And the parse position should be <pos>
|
19
|
+
|
20
|
+
Examples:
|
21
|
+
| input | result | pos |
|
22
|
+
| "foo" | ["foo"] | 3 |
|
23
|
+
| "foo,bar,baz" | ["foo", "bar", "baz"] | 11 |
|
24
|
+
| "foo,bar," | ["foo", "bar"] | 7 |
|
25
|
+
| " " | [] | 0 |
|
26
|
+
|
27
|
+
Scenario Outline: One or more terms
|
28
|
+
Given a grammar with:
|
29
|
+
"""
|
30
|
+
words <- @WORD+ +^ ','
|
31
|
+
"""
|
32
|
+
When I parse <input>
|
33
|
+
Then the parse result should be <result>
|
34
|
+
And the parse position should be <pos>
|
35
|
+
|
36
|
+
Examples:
|
37
|
+
| input | result | pos |
|
38
|
+
| "foo" | ["foo"] | 3 |
|
39
|
+
| "foo,bar,baz" | ["foo", "bar", "baz"] | 11 |
|
40
|
+
| "foo,bar," | ["foo", "bar"] | 7 |
|
41
|
+
| " " | FAIL | 0 |
|
@@ -6,7 +6,7 @@ Feature: Symantic Actions
|
|
6
6
|
specified like Ruby block parameters and are bound to the parse results from
|
7
7
|
the match. If there are fewer parameters than parse results the extra results
|
8
8
|
are simply ignored. Labeled parse results can be refered to as identifiers in
|
9
|
-
the action.
|
9
|
+
the action. The special identifier "_" refers to the entire parse results.
|
10
10
|
|
11
11
|
In order to add simple symantics to parse results
|
12
12
|
As a language designer
|
@@ -15,19 +15,11 @@ Feature: Symantic Actions
|
|
15
15
|
Scenario: Single token
|
16
16
|
Given a grammar with:
|
17
17
|
"""
|
18
|
-
integer <- /\d+/ {|
|
18
|
+
integer <- /\d+/ {|s| s.to_i }
|
19
19
|
"""
|
20
20
|
When I parse "42"
|
21
21
|
Then the parse result should be 42
|
22
22
|
|
23
|
-
Scenario: Shortcut form
|
24
|
-
Given a grammar with:
|
25
|
-
"""
|
26
|
-
integer <- /\d+/ <.to_i>
|
27
|
-
"""
|
28
|
-
When I parse "23"
|
29
|
-
Then the parse result should be 23
|
30
|
-
|
31
23
|
Scenario: Sequence
|
32
24
|
Given a grammar with:
|
33
25
|
"""
|
@@ -36,7 +28,7 @@ Feature: Symantic Actions
|
|
36
28
|
"""
|
37
29
|
When I parse "3 16"
|
38
30
|
Then the parse result should be 48
|
39
|
-
|
31
|
+
|
40
32
|
Scenario: Sequence with non-capturing expressions
|
41
33
|
Given a grammar with:
|
42
34
|
"""
|
@@ -51,4 +43,30 @@ Feature: Symantic Actions
|
|
51
43
|
sum <- "(" left:/\d+/ "+" right:/\d+/ ")" { left.to_i + right.to_i }
|
52
44
|
"""
|
53
45
|
When I parse "(17+29)"
|
54
|
-
Then the parse result should be 46
|
46
|
+
Then the parse result should be 46
|
47
|
+
|
48
|
+
Scenario: Single token using "_"
|
49
|
+
Given a grammar with:
|
50
|
+
"""
|
51
|
+
integer <- /\d+/ { _.to_i }
|
52
|
+
"""
|
53
|
+
When I parse "23"
|
54
|
+
Then the parse result should be 23
|
55
|
+
|
56
|
+
Scenario: Sequence using "_"
|
57
|
+
Given a grammar with:
|
58
|
+
"""
|
59
|
+
%whitespace SPACE*
|
60
|
+
ints <- /\d+/ /\d+/ { _.reverse }
|
61
|
+
"""
|
62
|
+
When I parse "3 16"
|
63
|
+
Then the parse result should be ["16", "3"]
|
64
|
+
|
65
|
+
Scenario: Sequence using "_" as a parameter name
|
66
|
+
Given a grammar with:
|
67
|
+
"""
|
68
|
+
%whitespace SPACE*
|
69
|
+
ints <- /\d+/ /\d+/ {|_| _.to_i }
|
70
|
+
"""
|
71
|
+
When I parse "3 16"
|
72
|
+
Then the parse result should be 3
|
@@ -1,94 +1,94 @@
|
|
1
1
|
require 'rattler/back_end/parser_generator'
|
2
2
|
|
3
3
|
module Rattler::BackEnd::ParserGenerator
|
4
|
-
|
4
|
+
|
5
5
|
# @private
|
6
6
|
class AssertGenerator < ExprGenerator #:nodoc:
|
7
|
-
|
7
|
+
|
8
8
|
def gen_basic(assert)
|
9
|
-
generate assert.child, :
|
9
|
+
generate assert.child, :assert
|
10
10
|
end
|
11
|
-
|
11
|
+
|
12
12
|
def gen_assert(assert)
|
13
13
|
gen_basic assert
|
14
14
|
end
|
15
|
-
|
15
|
+
|
16
16
|
def gen_disallow(assert)
|
17
17
|
@g << 'false'
|
18
18
|
end
|
19
|
-
|
19
|
+
|
20
20
|
def gen_skip_nested(assert)
|
21
21
|
gen_basic_nested assert
|
22
22
|
end
|
23
|
-
|
23
|
+
|
24
24
|
def gen_skip_top_level(assert)
|
25
25
|
gen_basic_top_level assert
|
26
26
|
end
|
27
|
-
|
27
|
+
|
28
28
|
def gen_dispatch_action_nested(assert, target, method_name)
|
29
29
|
atomic_block { gen_dispatch_action_top_level assert, target, method_name }
|
30
30
|
end
|
31
|
-
|
31
|
+
|
32
32
|
def gen_dispatch_action_top_level(assert, target, method_name)
|
33
33
|
gen_action assert,
|
34
34
|
dispatch_action_result(target, method_name, :array_expr => '[]')
|
35
35
|
end
|
36
|
-
|
36
|
+
|
37
37
|
def gen_direct_action_nested(assert, code)
|
38
38
|
atomic_block { gen_direct_action_top_level assert, code }
|
39
39
|
end
|
40
|
-
|
40
|
+
|
41
41
|
def gen_direct_action_top_level(assert, code)
|
42
42
|
gen_action assert, direct_action_result(code)
|
43
43
|
end
|
44
|
-
|
44
|
+
|
45
45
|
def gen_token_nested(assert)
|
46
46
|
atomic_block { gen_token_top_level assert }
|
47
47
|
end
|
48
|
-
|
48
|
+
|
49
49
|
def gen_token_top_level(assert)
|
50
50
|
gen_action assert, "''"
|
51
51
|
end
|
52
|
-
|
52
|
+
|
53
53
|
def gen_intermediate(assert)
|
54
|
-
generate assert.child, :
|
54
|
+
generate assert.child, :intermediate_assert
|
55
55
|
end
|
56
|
-
|
56
|
+
|
57
57
|
def gen_intermediate_assert(assert)
|
58
58
|
gen_intermediate assert
|
59
59
|
end
|
60
|
-
|
60
|
+
|
61
61
|
def gen_intermediate_skip(assert)
|
62
62
|
gen_intermediate assert
|
63
63
|
end
|
64
|
-
|
64
|
+
|
65
65
|
private
|
66
|
-
|
66
|
+
|
67
67
|
def gen_action(assert, result_code)
|
68
68
|
gen_intermediate assert
|
69
69
|
(@g << ' &&').newline << result_code
|
70
70
|
end
|
71
|
-
|
71
|
+
|
72
72
|
end
|
73
|
-
|
73
|
+
|
74
74
|
# @private
|
75
75
|
class NestedAssertGenerator < AssertGenerator #:nodoc:
|
76
76
|
include Nested
|
77
|
-
include
|
77
|
+
include NestedSubGenerating
|
78
78
|
end
|
79
|
-
|
79
|
+
|
80
80
|
def AssertGenerator.nested(*args)
|
81
81
|
NestedAssertGenerator.new(*args)
|
82
82
|
end
|
83
|
-
|
83
|
+
|
84
84
|
# @private
|
85
85
|
class TopLevelAssertGenerator < AssertGenerator #:nodoc:
|
86
86
|
include TopLevel
|
87
|
-
include
|
87
|
+
include TopLevelSubGenerating
|
88
88
|
end
|
89
|
-
|
89
|
+
|
90
90
|
def AssertGenerator.top_level(*args)
|
91
91
|
TopLevelAssertGenerator.new(*args)
|
92
92
|
end
|
93
|
-
|
93
|
+
|
94
94
|
end
|
@@ -1,88 +1,88 @@
|
|
1
1
|
require 'rattler/back_end/parser_generator'
|
2
2
|
|
3
3
|
module Rattler::BackEnd::ParserGenerator
|
4
|
-
|
4
|
+
|
5
5
|
# @private
|
6
6
|
class ChoiceGenerator < ExprGenerator #:nodoc:
|
7
|
-
include
|
8
|
-
|
7
|
+
include NestedSubGenerating
|
8
|
+
|
9
9
|
def gen_basic_nested(choice)
|
10
10
|
atomic_block { gen_basic_top_level choice }
|
11
11
|
end
|
12
|
-
|
12
|
+
|
13
13
|
def gen_basic_top_level(choice)
|
14
14
|
@g.intersperse_nl(choice, ' ||') {|_| generate _ }
|
15
15
|
end
|
16
|
-
|
16
|
+
|
17
17
|
def gen_assert_nested(choice)
|
18
18
|
atomic_expr { gen_assert_top_level choice }
|
19
19
|
end
|
20
|
-
|
20
|
+
|
21
21
|
def gen_assert_top_level(choice)
|
22
22
|
gen_intermediate_assert choice
|
23
23
|
@g << ' && true'
|
24
24
|
end
|
25
|
-
|
25
|
+
|
26
26
|
def gen_disallow(choice)
|
27
27
|
@g << '!'
|
28
28
|
gen_intermediate_assert choice
|
29
29
|
end
|
30
|
-
|
30
|
+
|
31
31
|
def gen_dispatch_action_nested(choice, target, method_name)
|
32
32
|
atomic_block { gen_dispatch_action_top_level choice, target, method_name }
|
33
33
|
end
|
34
|
-
|
34
|
+
|
35
35
|
def gen_dispatch_action_top_level(choice, target, method_name)
|
36
36
|
gen_action_code choice do |labeled|
|
37
37
|
dispatch_action_result(target, method_name, :labeled => labeled)
|
38
38
|
end
|
39
39
|
end
|
40
|
-
|
40
|
+
|
41
41
|
def gen_direct_action_nested(choice, action)
|
42
42
|
atomic_block { gen_direct_action_top_level choice, action }
|
43
43
|
end
|
44
|
-
|
44
|
+
|
45
45
|
def gen_direct_action_top_level(choice, action)
|
46
46
|
gen_action_code choice do |labeled|
|
47
47
|
direct_action_result(action, :labeled => labeled)
|
48
48
|
end
|
49
49
|
end
|
50
|
-
|
50
|
+
|
51
51
|
def gen_token_nested(choice)
|
52
52
|
atomic_block { gen_token_top_level choice }
|
53
53
|
end
|
54
|
-
|
54
|
+
|
55
55
|
def gen_token_top_level(choice)
|
56
|
-
@g.intersperse_nl(choice, ' ||') {|_| generate _, :
|
56
|
+
@g.intersperse_nl(choice, ' ||') {|_| generate _, :token }
|
57
57
|
end
|
58
|
-
|
58
|
+
|
59
59
|
def gen_skip_nested(choice)
|
60
60
|
@g.surround('(', ')') { gen_skip_top_level choice }
|
61
61
|
end
|
62
|
-
|
62
|
+
|
63
63
|
def gen_skip_top_level(choice)
|
64
64
|
gen_intermediate_skip choice
|
65
65
|
@g << ' && true'
|
66
66
|
end
|
67
|
-
|
67
|
+
|
68
68
|
def gen_intermediate_assert(choice)
|
69
69
|
atomic_block do
|
70
70
|
@g.intersperse_nl(choice, ' ||') do |_|
|
71
|
-
generate _, :
|
71
|
+
generate _, :intermediate_assert
|
72
72
|
end
|
73
73
|
end
|
74
74
|
end
|
75
|
-
|
75
|
+
|
76
76
|
def gen_intermediate_skip(choice)
|
77
77
|
atomic_block do
|
78
78
|
@g.intersperse_nl(choice, ' ||') do |_|
|
79
|
-
generate _, :
|
79
|
+
generate _, :intermediate_skip
|
80
80
|
end
|
81
81
|
end
|
82
82
|
end
|
83
|
-
|
83
|
+
|
84
84
|
private
|
85
|
-
|
85
|
+
|
86
86
|
def gen_action_code(choice)
|
87
87
|
labeled = choice.any? {|_| _.labeled? } ? labeled_name : nil
|
88
88
|
@g.block("(#{result_name} = begin", 'end)') do
|
@@ -101,29 +101,29 @@ module Rattler::BackEnd::ParserGenerator
|
|
101
101
|
end << ' && '
|
102
102
|
@g << yield(labeled)
|
103
103
|
end
|
104
|
-
|
104
|
+
|
105
105
|
def labeled_name
|
106
106
|
"l#{choice_level}"
|
107
107
|
end
|
108
|
-
|
108
|
+
|
109
109
|
end
|
110
|
-
|
110
|
+
|
111
111
|
# @private
|
112
112
|
class NestedChoiceGenerator < ChoiceGenerator #:nodoc:
|
113
113
|
include Nested
|
114
114
|
end
|
115
|
-
|
115
|
+
|
116
116
|
def ChoiceGenerator.nested(*args)
|
117
117
|
NestedChoiceGenerator.new(*args)
|
118
118
|
end
|
119
|
-
|
119
|
+
|
120
120
|
# @private
|
121
121
|
class TopLevelChoiceGenerator < ChoiceGenerator #:nodoc:
|
122
122
|
include TopLevel
|
123
123
|
end
|
124
|
-
|
124
|
+
|
125
125
|
def ChoiceGenerator.top_level(*args)
|
126
126
|
TopLevelChoiceGenerator.new(*args)
|
127
127
|
end
|
128
|
-
|
128
|
+
|
129
129
|
end
|
@@ -1,59 +1,59 @@
|
|
1
1
|
require 'rattler/back_end/parser_generator'
|
2
2
|
|
3
3
|
module Rattler::BackEnd::ParserGenerator
|
4
|
-
|
4
|
+
|
5
5
|
# @private
|
6
6
|
class DirectActionGenerator < ExprGenerator #:nodoc:
|
7
7
|
include PredicatePropogating
|
8
8
|
include TokenPropogating
|
9
9
|
include SkipPropogating
|
10
|
-
|
10
|
+
|
11
11
|
def gen_basic_nested(action)
|
12
|
-
generate action.child, :
|
12
|
+
generate action.child, :direct_action_nested, action.bindable_code
|
13
13
|
end
|
14
|
-
|
14
|
+
|
15
15
|
def gen_basic_top_level(action)
|
16
|
-
generate action.child, :
|
16
|
+
generate action.child, :direct_action_top_level, action.bindable_code
|
17
17
|
end
|
18
|
-
|
18
|
+
|
19
19
|
def gen_dispatch_action_nested(inner, target, method_name)
|
20
20
|
atomic_block { gen_dispatch_action_top_level inner, target, method_name }
|
21
21
|
end
|
22
|
-
|
22
|
+
|
23
23
|
def gen_dispatch_action_top_level(inner, target, method_name)
|
24
24
|
@g.surround("(#{result_name} = ", ')') { gen_basic_nested inner }
|
25
25
|
(@g << ' &&').newline << dispatch_action_result(target, method_name)
|
26
26
|
end
|
27
|
-
|
27
|
+
|
28
28
|
def gen_direct_action_nested(inner, code)
|
29
29
|
atomic_block { gen_direct_action_top_level inner, code }
|
30
30
|
end
|
31
|
-
|
31
|
+
|
32
32
|
def gen_direct_action_top_level(inner, code)
|
33
33
|
@g.surround("(#{result_name} = ", ')') { gen_basic_nested inner }
|
34
34
|
(@g << ' &&').newline << direct_action_result(code)
|
35
35
|
end
|
36
|
-
|
36
|
+
|
37
37
|
end
|
38
|
-
|
38
|
+
|
39
39
|
# @private
|
40
40
|
class NestedDirectActionGenerator < DirectActionGenerator #:nodoc:
|
41
41
|
include Nested
|
42
|
-
include
|
42
|
+
include NestedSubGenerating
|
43
43
|
end
|
44
|
-
|
44
|
+
|
45
45
|
def DirectActionGenerator.nested(*args)
|
46
46
|
NestedDirectActionGenerator.new(*args)
|
47
47
|
end
|
48
|
-
|
48
|
+
|
49
49
|
# @private
|
50
50
|
class TopLevelDirectActionGenerator < DirectActionGenerator #:nodoc:
|
51
51
|
include TopLevel
|
52
|
-
include
|
52
|
+
include TopLevelSubGenerating
|
53
53
|
end
|
54
|
-
|
54
|
+
|
55
55
|
def DirectActionGenerator.top_level(*args)
|
56
56
|
TopLevelDirectActionGenerator.new(*args)
|
57
57
|
end
|
58
|
-
|
58
|
+
|
59
59
|
end
|