rattler 0.3.0 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.rdoc +57 -37
- data/features/command_line/dest_option.feature +8 -21
- data/features/command_line/lib_option.feature +37 -0
- data/features/command_line/parser_generator.feature +7 -4
- data/features/grammar/back_reference.feature +37 -0
- data/features/grammar/fail.feature +3 -3
- data/features/grammar/labels.feature +11 -3
- data/features/grammar/list_matching.feature +14 -5
- data/features/grammar/literal.feature +30 -4
- data/features/grammar/nonterminal.feature +1 -1
- data/features/grammar/ordered_choice.feature +2 -2
- data/features/grammar/skip_operator.feature +1 -1
- data/features/grammar/symantic_action.feature +7 -7
- data/features/grammar/whitespace.feature +2 -2
- data/features/step_definitions/grammar_steps.rb +2 -2
- data/lib/rattler/back_end.rb +1 -0
- data/lib/rattler/back_end/compiler.rb +19 -20
- data/lib/rattler/back_end/optimizer.rb +100 -0
- data/lib/rattler/back_end/optimizer/composite_reducing.rb +18 -0
- data/lib/rattler/back_end/optimizer/flatten_choice.rb +31 -0
- data/lib/rattler/back_end/optimizer/flatten_sequence.rb +59 -0
- data/lib/rattler/back_end/optimizer/flattening.rb +17 -0
- data/lib/rattler/back_end/optimizer/inline_regular_rules.rb +46 -0
- data/lib/rattler/back_end/optimizer/join_match_capturing_sequence.rb +71 -0
- data/lib/rattler/back_end/optimizer/join_match_choice.rb +37 -0
- data/lib/rattler/back_end/optimizer/join_match_matching_sequence.rb +38 -0
- data/lib/rattler/back_end/optimizer/join_match_sequence.rb +17 -0
- data/lib/rattler/back_end/optimizer/join_predicate_bare_match.rb +68 -0
- data/lib/rattler/back_end/optimizer/join_predicate_match.rb +17 -0
- data/lib/rattler/back_end/optimizer/join_predicate_nested_match.rb +37 -0
- data/lib/rattler/back_end/optimizer/join_predicate_or_bare_match.rb +68 -0
- data/lib/rattler/back_end/optimizer/join_predicate_or_match.rb +17 -0
- data/lib/rattler/back_end/optimizer/join_predicate_or_nested_match.rb +36 -0
- data/lib/rattler/back_end/optimizer/match_joining.rb +60 -0
- data/lib/rattler/back_end/optimizer/optimization.rb +94 -0
- data/lib/rattler/back_end/optimizer/optimization_context.rb +72 -0
- data/lib/rattler/back_end/optimizer/optimization_sequence.rb +37 -0
- data/lib/rattler/back_end/optimizer/optimize_children.rb +46 -0
- data/lib/rattler/back_end/optimizer/reduce_repeat_match.rb +44 -0
- data/lib/rattler/back_end/optimizer/remove_meaningless_wrapper.rb +32 -0
- data/lib/rattler/back_end/optimizer/simplify_redundant_repeat.rb +43 -0
- data/lib/rattler/back_end/optimizer/simplify_token_match.rb +38 -0
- data/lib/rattler/back_end/parser_generator.rb +21 -14
- data/lib/rattler/back_end/parser_generator/apply_generator.rb +35 -35
- data/lib/rattler/back_end/parser_generator/assert_generator.rb +29 -30
- data/lib/rattler/back_end/parser_generator/back_reference_generator.rb +93 -0
- data/lib/rattler/back_end/parser_generator/choice_generator.rb +33 -49
- data/lib/rattler/back_end/parser_generator/direct_action_generator.rb +14 -14
- data/lib/rattler/back_end/parser_generator/disallow_generator.rb +29 -30
- data/lib/rattler/back_end/parser_generator/dispatch_action_generator.rb +11 -13
- data/lib/rattler/back_end/parser_generator/expr_generator.rb +36 -56
- data/lib/rattler/back_end/parser_generator/fail_generator.rb +18 -18
- data/lib/rattler/back_end/parser_generator/group_match.rb +18 -0
- data/lib/rattler/back_end/parser_generator/group_match_generator.rb +76 -0
- data/lib/rattler/back_end/parser_generator/label_generator.rb +25 -6
- data/lib/rattler/back_end/parser_generator/list1_generator.rb +7 -7
- data/lib/rattler/back_end/parser_generator/list_generating.rb +19 -20
- data/lib/rattler/back_end/parser_generator/list_generator.rb +5 -5
- data/lib/rattler/back_end/parser_generator/match_generator.rb +52 -52
- data/lib/rattler/back_end/parser_generator/one_or_more_generator.rb +6 -6
- data/lib/rattler/back_end/parser_generator/optional_generator.rb +30 -29
- data/lib/rattler/back_end/parser_generator/predicate_propogating.rb +8 -8
- data/lib/rattler/back_end/parser_generator/repeat_generating.rb +23 -25
- data/lib/rattler/back_end/parser_generator/rule_generator.rb +27 -79
- data/lib/rattler/back_end/parser_generator/rule_set_generator.rb +102 -0
- data/lib/rattler/back_end/parser_generator/sequence_generator.rb +49 -41
- data/lib/rattler/back_end/parser_generator/skip_generator.rb +14 -20
- data/lib/rattler/back_end/parser_generator/skip_propogating.rb +4 -4
- data/lib/rattler/back_end/parser_generator/sub_generating.rb +6 -0
- data/lib/rattler/back_end/parser_generator/token_generator.rb +12 -12
- data/lib/rattler/back_end/parser_generator/token_propogating.rb +2 -2
- data/lib/rattler/back_end/parser_generator/zero_or_more_generator.rb +4 -4
- data/lib/rattler/grammar.rb +4 -3
- data/lib/rattler/grammar/analysis.rb +91 -0
- data/lib/rattler/grammar/grammar.rb +37 -25
- data/lib/rattler/grammar/grammar_parser.rb +19 -11
- data/lib/rattler/grammar/metagrammar.rb +569 -800
- data/lib/rattler/grammar/rattler.rtlr +162 -144
- data/lib/rattler/parsers.rb +5 -1
- data/lib/rattler/parsers/action_code.rb +29 -15
- data/lib/rattler/parsers/apply.rb +5 -5
- data/lib/rattler/parsers/assert.rb +4 -18
- data/lib/rattler/parsers/back_reference.rb +46 -0
- data/lib/rattler/parsers/choice.rb +6 -39
- data/lib/rattler/parsers/combinator_parser.rb +32 -0
- data/lib/rattler/parsers/combining.rb +3 -29
- data/lib/rattler/parsers/direct_action.rb +27 -30
- data/lib/rattler/parsers/disallow.rb +4 -18
- data/lib/rattler/parsers/dispatch_action.rb +30 -25
- data/lib/rattler/parsers/label.rb +9 -18
- data/lib/rattler/parsers/list.rb +3 -34
- data/lib/rattler/parsers/list1.rb +4 -36
- data/lib/rattler/parsers/list_parser.rb +64 -0
- data/lib/rattler/parsers/match.rb +7 -42
- data/lib/rattler/parsers/node_code.rb +44 -0
- data/lib/rattler/parsers/one_or_more.rb +7 -27
- data/lib/rattler/parsers/optional.rb +5 -25
- data/lib/rattler/parsers/parser.rb +16 -44
- data/lib/rattler/parsers/parser_dsl.rb +13 -3
- data/lib/rattler/parsers/predicate.rb +4 -12
- data/lib/rattler/parsers/rule.rb +18 -19
- data/lib/rattler/parsers/rule_set.rb +63 -0
- data/lib/rattler/parsers/sequence.rb +12 -46
- data/lib/rattler/parsers/skip.rb +12 -26
- data/lib/rattler/parsers/token.rb +6 -21
- data/lib/rattler/parsers/zero_or_more.rb +6 -26
- data/lib/rattler/runner.rb +66 -28
- data/lib/rattler/runtime/extended_packrat_parser.rb +26 -20
- data/lib/rattler/runtime/packrat_parser.rb +17 -21
- data/lib/rattler/runtime/parser.rb +12 -2
- data/lib/rattler/runtime/recursive_descent_parser.rb +3 -11
- data/lib/rattler/util.rb +2 -1
- data/lib/rattler/util/graphviz.rb +29 -0
- data/lib/rattler/util/graphviz/digraph_builder.rb +71 -0
- data/lib/rattler/util/graphviz/node_builder.rb +84 -0
- data/lib/rattler/util/node.rb +37 -19
- data/lib/rattler/util/parser_spec_helper.rb +61 -35
- data/spec/rattler/back_end/compiler_spec.rb +6 -860
- data/spec/rattler/back_end/optimizer/flatten_choice_spec.rb +70 -0
- data/spec/rattler/back_end/optimizer/flatten_sequence_spec.rb +130 -0
- data/spec/rattler/back_end/optimizer/inline_regular_rules_spec.rb +80 -0
- data/spec/rattler/back_end/optimizer/join_match_capturing_sequence_spec.rb +241 -0
- data/spec/rattler/back_end/optimizer/join_match_choice_spec.rb +100 -0
- data/spec/rattler/back_end/optimizer/join_match_matching_sequence_spec.rb +112 -0
- data/spec/rattler/back_end/optimizer/join_predicate_bare_match_spec.rb +194 -0
- data/spec/rattler/back_end/optimizer/join_predicate_nested_match_spec.rb +180 -0
- data/spec/rattler/back_end/optimizer/join_predicate_or_bare_match_spec.rb +153 -0
- data/spec/rattler/back_end/optimizer/join_predicate_or_nested_match_spec.rb +153 -0
- data/spec/rattler/back_end/optimizer/reduce_repeat_match_spec.rb +98 -0
- data/spec/rattler/back_end/optimizer/simplify_redundant_repeat_spec.rb +226 -0
- data/spec/rattler/back_end/optimizer/simplify_token_match_spec.rb +85 -0
- data/spec/rattler/back_end/parser_generator/apply_generator_spec.rb +38 -33
- data/spec/rattler/back_end/parser_generator/assert_generator_spec.rb +38 -33
- data/spec/rattler/back_end/parser_generator/back_reference_generator_spec.rb +181 -0
- data/spec/rattler/back_end/parser_generator/choice_generator_spec.rb +38 -33
- data/spec/rattler/back_end/parser_generator/direct_action_generator_spec.rb +38 -33
- data/spec/rattler/back_end/parser_generator/disallow_generator_spec.rb +38 -33
- data/spec/rattler/back_end/parser_generator/dispatch_action_generator_spec.rb +38 -33
- data/spec/rattler/back_end/parser_generator/group_match_generator_spec.rb +185 -0
- data/spec/rattler/back_end/parser_generator/label_generator_spec.rb +38 -33
- data/spec/rattler/back_end/parser_generator/list1_generator_spec.rb +10 -5
- data/spec/rattler/back_end/parser_generator/list_generator_spec.rb +10 -5
- data/spec/rattler/back_end/parser_generator/match_generator_spec.rb +38 -33
- data/spec/rattler/back_end/parser_generator/one_or_more_generator_spec.rb +38 -33
- data/spec/rattler/back_end/parser_generator/optional_generator_spec.rb +38 -33
- data/spec/rattler/back_end/parser_generator/rule_generator_spec.rb +13 -46
- data/spec/rattler/back_end/parser_generator/rule_set_generator_spec.rb +97 -0
- data/spec/rattler/back_end/parser_generator/sequence_generator_spec.rb +38 -33
- data/spec/rattler/back_end/parser_generator/skip_generator_spec.rb +38 -33
- data/spec/rattler/back_end/parser_generator/token_generator_spec.rb +38 -33
- data/spec/rattler/back_end/parser_generator/zero_or_more_generator_spec.rb +39 -34
- data/spec/rattler/back_end/shared_compiler_examples.rb +885 -0
- data/spec/rattler/grammar/analysis_spec.rb +167 -0
- data/spec/rattler/grammar/grammar_parser_spec.rb +169 -179
- data/spec/rattler/grammar/grammar_spec.rb +24 -21
- data/spec/rattler/parsers/action_code_spec.rb +64 -19
- data/spec/rattler/parsers/apply_spec.rb +9 -9
- data/spec/rattler/parsers/back_reference_spec.rb +38 -0
- data/spec/rattler/parsers/combinator_parser_spec.rb +14 -0
- data/spec/rattler/parsers/direct_action_spec.rb +16 -2
- data/spec/rattler/parsers/dispatch_action_spec.rb +15 -32
- data/spec/rattler/parsers/fail_spec.rb +6 -4
- data/spec/rattler/parsers/label_spec.rb +10 -28
- data/spec/rattler/parsers/node_code_spec.rb +48 -0
- data/spec/rattler/parsers/parser_dsl_spec.rb +1 -1
- data/spec/rattler/parsers/rule_set_spec.rb +35 -0
- data/spec/rattler/parsers/sequence_spec.rb +15 -24
- data/spec/rattler/runtime/extended_packrat_parser_spec.rb +22 -17
- data/spec/rattler/runtime/packrat_parser_spec.rb +1 -1
- data/spec/rattler/runtime/parse_node_spec.rb +15 -19
- data/spec/rattler/runtime/recursive_descent_parser_spec.rb +1 -1
- data/spec/rattler/runtime/shared_parser_examples.rb +61 -28
- data/spec/rattler/util/graphviz/node_builder_spec.rb +84 -0
- data/spec/rattler/util/node_spec.rb +92 -65
- data/spec/rattler_spec.rb +16 -16
- data/spec/support/combinator_parser_spec_helper.rb +19 -18
- data/spec/support/compiler_spec_helper.rb +56 -87
- data/spec/support/runtime_parser_spec_helper.rb +6 -14
- metadata +117 -22
- data/features/grammar/regex.feature +0 -24
- data/lib/rattler/parsers/match_joining.rb +0 -67
- data/lib/rattler/parsers/rules.rb +0 -43
data/README.rdoc
CHANGED
@@ -14,25 +14,25 @@ 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.
|
17
|
+
{RDoc}[http://rubydoc.info/gems/rattler/0.4.0/frames]
|
18
18
|
|
19
19
|
== FEATURES:
|
20
20
|
|
21
21
|
* Uses readable PEG-like grammars
|
22
|
-
*
|
23
|
-
* An extended packrat parser that supports left-recursive grammars
|
22
|
+
* Supports directly and indirectly left-recursive grammars
|
24
23
|
* Whitespace can be specified in one place and skipped automatically
|
25
24
|
* Automatic and custom parse error reporting
|
26
|
-
* Optimizing parser generator
|
27
|
-
* Generated parsers are relatively readable
|
25
|
+
* Optimizing parser generator generates efficient pure-ruby parsers
|
28
26
|
* Compatible with Ruby 1.8.7 and 1.9.2, tested with MRI and JRuby on Linux and
|
29
27
|
Windows
|
30
28
|
|
31
29
|
== PROBLEMS/LIMITATIONS:
|
32
30
|
|
33
|
-
* Optimizations are very limited at this point
|
34
31
|
* Only strings can be parsed, so files have to be read completely before parsing
|
35
32
|
* There are many holes in the tests so there are undoubtedly many bugs
|
33
|
+
* Optimzations are not complete
|
34
|
+
* Support for composable grammars is not yet implemented
|
35
|
+
* Symantics of automatic whitespace skipping could be refined
|
36
36
|
|
37
37
|
== EXAMPLES:
|
38
38
|
|
@@ -42,32 +42,52 @@ dynamically from strings.
|
|
42
42
|
|
43
43
|
# JSON parser based on the grammar at http://www.json.org
|
44
44
|
|
45
|
+
require File.expand_path('json_helper', File.dirname(__FILE__))
|
46
|
+
|
45
47
|
parser JsonParser < Rattler::Runtime::PackratParser
|
46
48
|
|
47
|
-
|
49
|
+
include JsonHelper
|
50
|
+
|
51
|
+
%whitespace (SPACE+ / comment)* {
|
52
|
+
|
53
|
+
object <- ~'{' members ~'}' { object _ }
|
54
|
+
|
55
|
+
members <- pair *, ','
|
56
|
+
|
57
|
+
pair <- string ~':' value
|
58
|
+
|
59
|
+
array <- ~'[' elements ~']'
|
60
|
+
|
61
|
+
elements <- value *, ','
|
62
|
+
|
63
|
+
value <- string
|
64
|
+
/ number
|
65
|
+
/ object
|
66
|
+
/ array
|
67
|
+
/ `true` { :true }
|
68
|
+
/ `false` { :false }
|
69
|
+
/ `null` { :null }
|
70
|
+
/ fail "value expected"
|
48
71
|
|
49
|
-
|
72
|
+
string <- @('"' char* '"') { string _ }
|
50
73
|
|
51
|
-
|
74
|
+
number <- @(int frac? exp?) { number _ }
|
75
|
+
}
|
52
76
|
|
53
|
-
|
77
|
+
%inline {
|
54
78
|
|
55
|
-
|
79
|
+
char <- !('"' / '\\' / CNTRL) .
|
80
|
+
/ '\\' (["\\/bfnrt] / 'u' XDIGIT XDIGIT XDIGIT XDIGIT)
|
56
81
|
|
57
|
-
|
82
|
+
int <- '-'? ('0' !DIGIT / [1-9] DIGIT*)
|
58
83
|
|
59
|
-
|
60
|
-
| number !DIGIT { _.to_f }
|
61
|
-
| object
|
62
|
-
| array
|
63
|
-
| `true` { :true }
|
64
|
-
| `false` { :false }
|
65
|
-
| `null` { :null }
|
66
|
-
| fail "value expected"
|
84
|
+
frac <- '.' DIGIT+
|
67
85
|
|
68
|
-
|
86
|
+
exp <- [eE] [+-]? DIGIT+
|
69
87
|
|
70
|
-
|
88
|
+
comment <- '/*' (! '*/' .)* '*/'
|
89
|
+
/ '//' [^\n]*
|
90
|
+
}
|
71
91
|
|
72
92
|
==== json_helper.rb:
|
73
93
|
|
@@ -78,6 +98,10 @@ dynamically from strings.
|
|
78
98
|
end
|
79
99
|
|
80
100
|
def string(expr)
|
101
|
+
eval "%q#{expr}", TOPLEVEL_BINDING
|
102
|
+
end
|
103
|
+
|
104
|
+
def number(expr)
|
81
105
|
eval expr, TOPLEVEL_BINDING
|
82
106
|
end
|
83
107
|
|
@@ -107,7 +131,7 @@ dynamically from strings.
|
|
107
131
|
|
108
132
|
grammar JsonGrammar
|
109
133
|
|
110
|
-
%whitespace (SPACE+
|
134
|
+
%whitespace (SPACE+ / comment)* {
|
111
135
|
|
112
136
|
...
|
113
137
|
|
@@ -129,11 +153,7 @@ dynamically from strings.
|
|
129
153
|
Hash[*members.flatten(1)]
|
130
154
|
end
|
131
155
|
|
132
|
-
|
133
|
-
eval expr, TOPLEVEL_BINDING
|
134
|
-
end
|
135
|
-
|
136
|
-
end
|
156
|
+
...
|
137
157
|
|
138
158
|
=== Example 3: Dynamically generated parser class
|
139
159
|
|
@@ -145,18 +165,18 @@ dynamically from strings.
|
|
145
165
|
|
146
166
|
start <- expr EOF
|
147
167
|
|
148
|
-
expr <- expr ~'+' term
|
149
|
-
|
150
|
-
|
168
|
+
expr <- expr ~'+' term {|a, b| a + b }
|
169
|
+
/ expr ~'-' term {|a, b| a - b }
|
170
|
+
/ term
|
151
171
|
|
152
|
-
term <- term ~'*' primary
|
153
|
-
|
154
|
-
|
172
|
+
term <- term ~'*' primary {|a, b| a * b }
|
173
|
+
/ term ~'/' primary {|a, b| a / b }
|
174
|
+
/ primary
|
155
175
|
|
156
176
|
primary <- ~'(' expr ~')'
|
157
|
-
|
158
|
-
|
159
|
-
|
177
|
+
/ @('-'? DIGIT+ ('.' DIGIT+)?) { _.to_f }
|
178
|
+
},
|
179
|
+
:type => :extended_packrat
|
160
180
|
|
161
181
|
begin
|
162
182
|
puts Calculator.parse!(expr)
|
@@ -1,32 +1,19 @@
|
|
1
1
|
Feature: --dest option
|
2
2
|
|
3
|
-
Use the --dest (or -d) option to specify
|
4
|
-
|
3
|
+
Use the --dest (or -d) option to specify an explicit destination directory.
|
4
|
+
By default Rattler uses the module path of the grammar to build a destination
|
5
|
+
directory by converting camel-case to underscore.
|
5
6
|
|
6
|
-
Scenario:
|
7
|
-
Given a file named "binary.rtlr" with:
|
8
|
-
"""
|
9
|
-
grammar BinaryGrammar
|
10
|
-
expr <- [01]*
|
11
|
-
"""
|
12
|
-
And a directory named "lib"
|
13
|
-
When I run "rtlr --dest lib binary.rtlr"
|
14
|
-
Then the output should contain "binary.rtlr -> lib/binary_grammar.rb"
|
15
|
-
And the file "lib/binary_grammar.rb" should contain:
|
16
|
-
"""
|
17
|
-
module BinaryGrammar
|
18
|
-
"""
|
19
|
-
|
20
|
-
Scenario: Grammar as top-level module
|
7
|
+
Scenario: Overriding the destination directory
|
21
8
|
Given a file named "binary.rtlr" with:
|
22
9
|
"""
|
23
10
|
grammar Examples::BinaryGrammar
|
24
11
|
expr <- [01]*
|
25
12
|
"""
|
26
|
-
And a directory named "lib/
|
27
|
-
When I run "rtlr --dest lib binary.rtlr"
|
28
|
-
Then the output should contain "binary.rtlr -> lib/
|
29
|
-
And the file "lib/
|
13
|
+
And a directory named "lib/my_examples"
|
14
|
+
When I run "rtlr --dest lib/my_examples binary.rtlr"
|
15
|
+
Then the output should contain "binary.rtlr -> lib/my_examples/binary_grammar.rb"
|
16
|
+
And the file "lib/my_examples/binary_grammar.rb" should contain:
|
30
17
|
"""
|
31
18
|
module Examples
|
32
19
|
# @private
|
@@ -0,0 +1,37 @@
|
|
1
|
+
Feature: --lib option
|
2
|
+
|
3
|
+
Use the --lib (or -l) option to specify a different destination library
|
4
|
+
directory. If not specified, the default is the current directory. Rattler
|
5
|
+
uses the module path of the grammar to build a destination directory based
|
6
|
+
on the library directory by converting camel-case to underscore. To specify
|
7
|
+
an explicit destination directory use the --dest (or -d) option.
|
8
|
+
|
9
|
+
Scenario: Grammar as top-level module
|
10
|
+
Given a file named "binary.rtlr" with:
|
11
|
+
"""
|
12
|
+
grammar BinaryGrammar
|
13
|
+
expr <- [01]*
|
14
|
+
"""
|
15
|
+
And a directory named "lib"
|
16
|
+
When I run "rtlr --lib lib binary.rtlr"
|
17
|
+
Then the output should contain "binary.rtlr -> lib/binary_grammar.rb"
|
18
|
+
And the file "lib/binary_grammar.rb" should contain:
|
19
|
+
"""
|
20
|
+
module BinaryGrammar
|
21
|
+
"""
|
22
|
+
|
23
|
+
Scenario: Grammar as a nested module
|
24
|
+
Given a file named "binary.rtlr" with:
|
25
|
+
"""
|
26
|
+
grammar Examples::BinaryGrammar
|
27
|
+
expr <- [01]*
|
28
|
+
"""
|
29
|
+
And a directory named "lib/examples"
|
30
|
+
When I run "rtlr --lib lib binary.rtlr"
|
31
|
+
Then the output should contain "binary.rtlr -> lib/examples/binary_grammar.rb"
|
32
|
+
And the file "lib/examples/binary_grammar.rb" should contain:
|
33
|
+
"""
|
34
|
+
module Examples
|
35
|
+
# @private
|
36
|
+
module BinaryGrammar
|
37
|
+
"""
|
@@ -9,9 +9,12 @@ Feature: Parser Generator
|
|
9
9
|
"""
|
10
10
|
Usage: rtlr FILENAME [options]
|
11
11
|
|
12
|
-
-
|
13
|
-
-
|
12
|
+
-l, --lib DIRECTORY Specify the destination lib directory
|
13
|
+
-d, --dest DIRECTORY Specify an explicit destination directory
|
14
|
+
-o, --output FILENAME Specify a different output filename ("-" = STDOUT)
|
14
15
|
-f, --force Force overwrite if the output file exists
|
16
|
+
-s, --standalone Optimize for use as a standalone parser
|
17
|
+
-n, --no-optimize Disable optimization
|
15
18
|
|
16
19
|
-h, --help Show this message
|
17
20
|
"""
|
@@ -22,7 +25,7 @@ Feature: Parser Generator
|
|
22
25
|
grammar BinaryGrammar
|
23
26
|
expr <- [01]*
|
24
27
|
"""
|
25
|
-
When I run "rtlr binary.rtlr"
|
28
|
+
When I run "rtlr binary.rtlr --standalone"
|
26
29
|
Then the output should contain "binary.rtlr -> binary_grammar.rb"
|
27
30
|
And the file "binary_grammar.rb" should contain:
|
28
31
|
"""
|
@@ -53,7 +56,7 @@ Feature: Parser Generator
|
|
53
56
|
parser BinaryParser < Rattler::Runtime::PackratParser
|
54
57
|
expr <- [01]*
|
55
58
|
"""
|
56
|
-
When I run "rtlr binary.rtlr"
|
59
|
+
When I run "rtlr binary.rtlr --standalone"
|
57
60
|
Then the output should contain "binary.rtlr -> binary_parser.rb"
|
58
61
|
And the file "binary_parser.rb" should contain:
|
59
62
|
"""
|
@@ -0,0 +1,37 @@
|
|
1
|
+
Feature: Back References
|
2
|
+
|
3
|
+
A back reference is a "$" followed by a label defined earlier in a sequence.
|
4
|
+
The reference refers to the previous parse result and it means to match the
|
5
|
+
same exact input again.
|
6
|
+
|
7
|
+
In order to reuse a previous parse result to match the same text again
|
8
|
+
As a language designer
|
9
|
+
I want to use back references in my grammar
|
10
|
+
|
11
|
+
Scenario Outline: Parsing
|
12
|
+
Given a grammar with:
|
13
|
+
"""
|
14
|
+
expr <- a:ALPHA DIGIT+ $a
|
15
|
+
"""
|
16
|
+
When I parse <input>
|
17
|
+
Then the parse result should be <result>
|
18
|
+
|
19
|
+
Examples:
|
20
|
+
| input | result |
|
21
|
+
| "a12a" | ["a", ["1", "2"], "a"] |
|
22
|
+
| "b12b" | ["b", ["1", "2"], "b"] |
|
23
|
+
| "a12b" | FAIL |
|
24
|
+
|
25
|
+
Scenario Outline: Token
|
26
|
+
Given a grammar with:
|
27
|
+
"""
|
28
|
+
string <- @('%' q:PUNCT (! $q .)* $q)
|
29
|
+
"""
|
30
|
+
When I parse <input>
|
31
|
+
Then the parse result should be <result>
|
32
|
+
|
33
|
+
Examples:
|
34
|
+
| input | result |
|
35
|
+
| "%/a b/ c" | "%/a b/" |
|
36
|
+
| "%!a b! c" | "%!a b!" |
|
37
|
+
| "%/a b! c" | FAIL |
|
@@ -25,7 +25,7 @@ Feature: Fail Expressions
|
|
25
25
|
Given a grammar with:
|
26
26
|
"""
|
27
27
|
expr <- fail_rule "something really bad happened"
|
28
|
-
|
28
|
+
/ .*
|
29
29
|
"""
|
30
30
|
When I parse "anything"
|
31
31
|
Then the parse should fail
|
@@ -34,7 +34,7 @@ Feature: Fail Expressions
|
|
34
34
|
Scenario: Fail-parse
|
35
35
|
Given a grammar with:
|
36
36
|
"""
|
37
|
-
a <- b
|
37
|
+
a <- b / .*
|
38
38
|
b <- fail_parse "something catastrophic happened"
|
39
39
|
"""
|
40
40
|
When I parse "anything"
|
@@ -44,7 +44,7 @@ Feature: Fail Expressions
|
|
44
44
|
Scenario: Fail-expression at the end of an ordered choice
|
45
45
|
Given a grammar with:
|
46
46
|
"""
|
47
|
-
expr <- a
|
47
|
+
expr <- a / b / fail "something bad happened"
|
48
48
|
a <- "a"
|
49
49
|
b <- "b"
|
50
50
|
"""
|
@@ -8,7 +8,7 @@ Feature: Labels
|
|
8
8
|
Scenario: Normal symantic action
|
9
9
|
Given a grammar with:
|
10
10
|
"""
|
11
|
-
fraction <- numer
|
11
|
+
fraction <- numer:@DIGIT+ "/" denom:@DIGIT+ { numer.to_i / denom.to_i }
|
12
12
|
"""
|
13
13
|
When I parse "6/2"
|
14
14
|
Then the parse result should be 3
|
@@ -16,11 +16,19 @@ Feature: Labels
|
|
16
16
|
Scenario: Node action
|
17
17
|
Given a grammar with:
|
18
18
|
"""
|
19
|
-
fraction <- numer
|
19
|
+
fraction <- numer:@DIGIT+ "/" denom:@DIGIT+ <Fraction>
|
20
20
|
"""
|
21
21
|
And a class definition:
|
22
22
|
"""
|
23
23
|
class Fraction < Rattler::Runtime::ParseNode; end
|
24
24
|
"""
|
25
25
|
When I parse "6/2"
|
26
|
-
Then the parse result should be Fraction[["6", "/", "2"], {:labeled => {:numer => "6", :denom => "2"}}]
|
26
|
+
Then the parse result should be Fraction[["6", "/", "2"], {:labeled => {:numer => "6", :denom => "2"}}]
|
27
|
+
|
28
|
+
Scenario: Nested scope
|
29
|
+
Given a grammar with:
|
30
|
+
"""
|
31
|
+
a <- word:@ALPHA+ (@DIGIT+ {|num| "#{num} #{word}" })
|
32
|
+
"""
|
33
|
+
When I parse "abc123"
|
34
|
+
Then the parse result should be ["abc", "123 abc"]
|
@@ -1,8 +1,8 @@
|
|
1
1
|
Feature: List Matching
|
2
2
|
|
3
|
-
|
4
|
-
to match a list of terms with separators between them. "
|
5
|
-
zero or more terms, "
|
3
|
+
A 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
6
|
|
7
7
|
In order to clearly and easily match list expressions
|
8
8
|
As a language designer
|
@@ -11,7 +11,7 @@ Feature: List Matching
|
|
11
11
|
Scenario Outline: Zero or more terms
|
12
12
|
Given a grammar with:
|
13
13
|
"""
|
14
|
-
words <- @WORD+
|
14
|
+
words <- @WORD+ *, ','
|
15
15
|
"""
|
16
16
|
When I parse <input>
|
17
17
|
Then the parse result should be <result>
|
@@ -27,7 +27,7 @@ Feature: List Matching
|
|
27
27
|
Scenario Outline: One or more terms
|
28
28
|
Given a grammar with:
|
29
29
|
"""
|
30
|
-
words <- @WORD+
|
30
|
+
words <- @WORD+ +, ','
|
31
31
|
"""
|
32
32
|
When I parse <input>
|
33
33
|
Then the parse result should be <result>
|
@@ -39,3 +39,12 @@ Feature: List Matching
|
|
39
39
|
| "foo,bar,baz" | ["foo", "bar", "baz"] | 11 |
|
40
40
|
| "foo,bar," | ["foo", "bar"] | 7 |
|
41
41
|
| " " | FAIL | 0 |
|
42
|
+
|
43
|
+
Scenario: Using whitespace
|
44
|
+
Given a grammar with:
|
45
|
+
"""
|
46
|
+
%whitespace SPACE*
|
47
|
+
words <- @WORD+ *, ','
|
48
|
+
"""
|
49
|
+
When I parse "foo, bar ,baz"
|
50
|
+
Then the parse result should be ["foo", "bar", "baz"]
|
@@ -1,13 +1,13 @@
|
|
1
1
|
Feature: Literal Expressions
|
2
2
|
|
3
|
-
A string literal
|
4
|
-
if that exact text is next in the input.
|
3
|
+
A string literal has the same syntax as a Ruby string literal and it means to
|
4
|
+
match if that exact text is next in the input.
|
5
5
|
|
6
6
|
In order to define symbols and keywords
|
7
7
|
As a language designer
|
8
8
|
I want to use string literals in my grammar
|
9
9
|
|
10
|
-
Scenario Outline:
|
10
|
+
Scenario Outline: Normal String
|
11
11
|
Given a grammar with:
|
12
12
|
"""
|
13
13
|
a <- "while"
|
@@ -19,4 +19,30 @@ Feature: Literal Expressions
|
|
19
19
|
| input | result |
|
20
20
|
| "while" | "while" |
|
21
21
|
| " while" | FAIL |
|
22
|
-
| "whip" | FAIL |
|
22
|
+
| "whip" | FAIL |
|
23
|
+
|
24
|
+
Scenario Outline: General delimited String with brackets
|
25
|
+
Given a grammar with:
|
26
|
+
"""
|
27
|
+
a <- %{while}
|
28
|
+
"""
|
29
|
+
When I parse <input>
|
30
|
+
Then the parse result should be <result>
|
31
|
+
|
32
|
+
Examples:
|
33
|
+
| input | result |
|
34
|
+
| "while" | "while" |
|
35
|
+
| "whip" | FAIL |
|
36
|
+
|
37
|
+
Scenario Outline: General delimited String with arbitrary delimiters
|
38
|
+
Given a grammar with:
|
39
|
+
"""
|
40
|
+
a <- %!while!
|
41
|
+
"""
|
42
|
+
When I parse <input>
|
43
|
+
Then the parse result should be <result>
|
44
|
+
|
45
|
+
Examples:
|
46
|
+
| input | result |
|
47
|
+
| "while" | "while" |
|
48
|
+
| "whip" | FAIL |
|