rattler 0.3.0 → 0.4.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 +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 |
|