rattler 0.2.2 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|