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.
Files changed (182) hide show
  1. data/README.rdoc +57 -37
  2. data/features/command_line/dest_option.feature +8 -21
  3. data/features/command_line/lib_option.feature +37 -0
  4. data/features/command_line/parser_generator.feature +7 -4
  5. data/features/grammar/back_reference.feature +37 -0
  6. data/features/grammar/fail.feature +3 -3
  7. data/features/grammar/labels.feature +11 -3
  8. data/features/grammar/list_matching.feature +14 -5
  9. data/features/grammar/literal.feature +30 -4
  10. data/features/grammar/nonterminal.feature +1 -1
  11. data/features/grammar/ordered_choice.feature +2 -2
  12. data/features/grammar/skip_operator.feature +1 -1
  13. data/features/grammar/symantic_action.feature +7 -7
  14. data/features/grammar/whitespace.feature +2 -2
  15. data/features/step_definitions/grammar_steps.rb +2 -2
  16. data/lib/rattler/back_end.rb +1 -0
  17. data/lib/rattler/back_end/compiler.rb +19 -20
  18. data/lib/rattler/back_end/optimizer.rb +100 -0
  19. data/lib/rattler/back_end/optimizer/composite_reducing.rb +18 -0
  20. data/lib/rattler/back_end/optimizer/flatten_choice.rb +31 -0
  21. data/lib/rattler/back_end/optimizer/flatten_sequence.rb +59 -0
  22. data/lib/rattler/back_end/optimizer/flattening.rb +17 -0
  23. data/lib/rattler/back_end/optimizer/inline_regular_rules.rb +46 -0
  24. data/lib/rattler/back_end/optimizer/join_match_capturing_sequence.rb +71 -0
  25. data/lib/rattler/back_end/optimizer/join_match_choice.rb +37 -0
  26. data/lib/rattler/back_end/optimizer/join_match_matching_sequence.rb +38 -0
  27. data/lib/rattler/back_end/optimizer/join_match_sequence.rb +17 -0
  28. data/lib/rattler/back_end/optimizer/join_predicate_bare_match.rb +68 -0
  29. data/lib/rattler/back_end/optimizer/join_predicate_match.rb +17 -0
  30. data/lib/rattler/back_end/optimizer/join_predicate_nested_match.rb +37 -0
  31. data/lib/rattler/back_end/optimizer/join_predicate_or_bare_match.rb +68 -0
  32. data/lib/rattler/back_end/optimizer/join_predicate_or_match.rb +17 -0
  33. data/lib/rattler/back_end/optimizer/join_predicate_or_nested_match.rb +36 -0
  34. data/lib/rattler/back_end/optimizer/match_joining.rb +60 -0
  35. data/lib/rattler/back_end/optimizer/optimization.rb +94 -0
  36. data/lib/rattler/back_end/optimizer/optimization_context.rb +72 -0
  37. data/lib/rattler/back_end/optimizer/optimization_sequence.rb +37 -0
  38. data/lib/rattler/back_end/optimizer/optimize_children.rb +46 -0
  39. data/lib/rattler/back_end/optimizer/reduce_repeat_match.rb +44 -0
  40. data/lib/rattler/back_end/optimizer/remove_meaningless_wrapper.rb +32 -0
  41. data/lib/rattler/back_end/optimizer/simplify_redundant_repeat.rb +43 -0
  42. data/lib/rattler/back_end/optimizer/simplify_token_match.rb +38 -0
  43. data/lib/rattler/back_end/parser_generator.rb +21 -14
  44. data/lib/rattler/back_end/parser_generator/apply_generator.rb +35 -35
  45. data/lib/rattler/back_end/parser_generator/assert_generator.rb +29 -30
  46. data/lib/rattler/back_end/parser_generator/back_reference_generator.rb +93 -0
  47. data/lib/rattler/back_end/parser_generator/choice_generator.rb +33 -49
  48. data/lib/rattler/back_end/parser_generator/direct_action_generator.rb +14 -14
  49. data/lib/rattler/back_end/parser_generator/disallow_generator.rb +29 -30
  50. data/lib/rattler/back_end/parser_generator/dispatch_action_generator.rb +11 -13
  51. data/lib/rattler/back_end/parser_generator/expr_generator.rb +36 -56
  52. data/lib/rattler/back_end/parser_generator/fail_generator.rb +18 -18
  53. data/lib/rattler/back_end/parser_generator/group_match.rb +18 -0
  54. data/lib/rattler/back_end/parser_generator/group_match_generator.rb +76 -0
  55. data/lib/rattler/back_end/parser_generator/label_generator.rb +25 -6
  56. data/lib/rattler/back_end/parser_generator/list1_generator.rb +7 -7
  57. data/lib/rattler/back_end/parser_generator/list_generating.rb +19 -20
  58. data/lib/rattler/back_end/parser_generator/list_generator.rb +5 -5
  59. data/lib/rattler/back_end/parser_generator/match_generator.rb +52 -52
  60. data/lib/rattler/back_end/parser_generator/one_or_more_generator.rb +6 -6
  61. data/lib/rattler/back_end/parser_generator/optional_generator.rb +30 -29
  62. data/lib/rattler/back_end/parser_generator/predicate_propogating.rb +8 -8
  63. data/lib/rattler/back_end/parser_generator/repeat_generating.rb +23 -25
  64. data/lib/rattler/back_end/parser_generator/rule_generator.rb +27 -79
  65. data/lib/rattler/back_end/parser_generator/rule_set_generator.rb +102 -0
  66. data/lib/rattler/back_end/parser_generator/sequence_generator.rb +49 -41
  67. data/lib/rattler/back_end/parser_generator/skip_generator.rb +14 -20
  68. data/lib/rattler/back_end/parser_generator/skip_propogating.rb +4 -4
  69. data/lib/rattler/back_end/parser_generator/sub_generating.rb +6 -0
  70. data/lib/rattler/back_end/parser_generator/token_generator.rb +12 -12
  71. data/lib/rattler/back_end/parser_generator/token_propogating.rb +2 -2
  72. data/lib/rattler/back_end/parser_generator/zero_or_more_generator.rb +4 -4
  73. data/lib/rattler/grammar.rb +4 -3
  74. data/lib/rattler/grammar/analysis.rb +91 -0
  75. data/lib/rattler/grammar/grammar.rb +37 -25
  76. data/lib/rattler/grammar/grammar_parser.rb +19 -11
  77. data/lib/rattler/grammar/metagrammar.rb +569 -800
  78. data/lib/rattler/grammar/rattler.rtlr +162 -144
  79. data/lib/rattler/parsers.rb +5 -1
  80. data/lib/rattler/parsers/action_code.rb +29 -15
  81. data/lib/rattler/parsers/apply.rb +5 -5
  82. data/lib/rattler/parsers/assert.rb +4 -18
  83. data/lib/rattler/parsers/back_reference.rb +46 -0
  84. data/lib/rattler/parsers/choice.rb +6 -39
  85. data/lib/rattler/parsers/combinator_parser.rb +32 -0
  86. data/lib/rattler/parsers/combining.rb +3 -29
  87. data/lib/rattler/parsers/direct_action.rb +27 -30
  88. data/lib/rattler/parsers/disallow.rb +4 -18
  89. data/lib/rattler/parsers/dispatch_action.rb +30 -25
  90. data/lib/rattler/parsers/label.rb +9 -18
  91. data/lib/rattler/parsers/list.rb +3 -34
  92. data/lib/rattler/parsers/list1.rb +4 -36
  93. data/lib/rattler/parsers/list_parser.rb +64 -0
  94. data/lib/rattler/parsers/match.rb +7 -42
  95. data/lib/rattler/parsers/node_code.rb +44 -0
  96. data/lib/rattler/parsers/one_or_more.rb +7 -27
  97. data/lib/rattler/parsers/optional.rb +5 -25
  98. data/lib/rattler/parsers/parser.rb +16 -44
  99. data/lib/rattler/parsers/parser_dsl.rb +13 -3
  100. data/lib/rattler/parsers/predicate.rb +4 -12
  101. data/lib/rattler/parsers/rule.rb +18 -19
  102. data/lib/rattler/parsers/rule_set.rb +63 -0
  103. data/lib/rattler/parsers/sequence.rb +12 -46
  104. data/lib/rattler/parsers/skip.rb +12 -26
  105. data/lib/rattler/parsers/token.rb +6 -21
  106. data/lib/rattler/parsers/zero_or_more.rb +6 -26
  107. data/lib/rattler/runner.rb +66 -28
  108. data/lib/rattler/runtime/extended_packrat_parser.rb +26 -20
  109. data/lib/rattler/runtime/packrat_parser.rb +17 -21
  110. data/lib/rattler/runtime/parser.rb +12 -2
  111. data/lib/rattler/runtime/recursive_descent_parser.rb +3 -11
  112. data/lib/rattler/util.rb +2 -1
  113. data/lib/rattler/util/graphviz.rb +29 -0
  114. data/lib/rattler/util/graphviz/digraph_builder.rb +71 -0
  115. data/lib/rattler/util/graphviz/node_builder.rb +84 -0
  116. data/lib/rattler/util/node.rb +37 -19
  117. data/lib/rattler/util/parser_spec_helper.rb +61 -35
  118. data/spec/rattler/back_end/compiler_spec.rb +6 -860
  119. data/spec/rattler/back_end/optimizer/flatten_choice_spec.rb +70 -0
  120. data/spec/rattler/back_end/optimizer/flatten_sequence_spec.rb +130 -0
  121. data/spec/rattler/back_end/optimizer/inline_regular_rules_spec.rb +80 -0
  122. data/spec/rattler/back_end/optimizer/join_match_capturing_sequence_spec.rb +241 -0
  123. data/spec/rattler/back_end/optimizer/join_match_choice_spec.rb +100 -0
  124. data/spec/rattler/back_end/optimizer/join_match_matching_sequence_spec.rb +112 -0
  125. data/spec/rattler/back_end/optimizer/join_predicate_bare_match_spec.rb +194 -0
  126. data/spec/rattler/back_end/optimizer/join_predicate_nested_match_spec.rb +180 -0
  127. data/spec/rattler/back_end/optimizer/join_predicate_or_bare_match_spec.rb +153 -0
  128. data/spec/rattler/back_end/optimizer/join_predicate_or_nested_match_spec.rb +153 -0
  129. data/spec/rattler/back_end/optimizer/reduce_repeat_match_spec.rb +98 -0
  130. data/spec/rattler/back_end/optimizer/simplify_redundant_repeat_spec.rb +226 -0
  131. data/spec/rattler/back_end/optimizer/simplify_token_match_spec.rb +85 -0
  132. data/spec/rattler/back_end/parser_generator/apply_generator_spec.rb +38 -33
  133. data/spec/rattler/back_end/parser_generator/assert_generator_spec.rb +38 -33
  134. data/spec/rattler/back_end/parser_generator/back_reference_generator_spec.rb +181 -0
  135. data/spec/rattler/back_end/parser_generator/choice_generator_spec.rb +38 -33
  136. data/spec/rattler/back_end/parser_generator/direct_action_generator_spec.rb +38 -33
  137. data/spec/rattler/back_end/parser_generator/disallow_generator_spec.rb +38 -33
  138. data/spec/rattler/back_end/parser_generator/dispatch_action_generator_spec.rb +38 -33
  139. data/spec/rattler/back_end/parser_generator/group_match_generator_spec.rb +185 -0
  140. data/spec/rattler/back_end/parser_generator/label_generator_spec.rb +38 -33
  141. data/spec/rattler/back_end/parser_generator/list1_generator_spec.rb +10 -5
  142. data/spec/rattler/back_end/parser_generator/list_generator_spec.rb +10 -5
  143. data/spec/rattler/back_end/parser_generator/match_generator_spec.rb +38 -33
  144. data/spec/rattler/back_end/parser_generator/one_or_more_generator_spec.rb +38 -33
  145. data/spec/rattler/back_end/parser_generator/optional_generator_spec.rb +38 -33
  146. data/spec/rattler/back_end/parser_generator/rule_generator_spec.rb +13 -46
  147. data/spec/rattler/back_end/parser_generator/rule_set_generator_spec.rb +97 -0
  148. data/spec/rattler/back_end/parser_generator/sequence_generator_spec.rb +38 -33
  149. data/spec/rattler/back_end/parser_generator/skip_generator_spec.rb +38 -33
  150. data/spec/rattler/back_end/parser_generator/token_generator_spec.rb +38 -33
  151. data/spec/rattler/back_end/parser_generator/zero_or_more_generator_spec.rb +39 -34
  152. data/spec/rattler/back_end/shared_compiler_examples.rb +885 -0
  153. data/spec/rattler/grammar/analysis_spec.rb +167 -0
  154. data/spec/rattler/grammar/grammar_parser_spec.rb +169 -179
  155. data/spec/rattler/grammar/grammar_spec.rb +24 -21
  156. data/spec/rattler/parsers/action_code_spec.rb +64 -19
  157. data/spec/rattler/parsers/apply_spec.rb +9 -9
  158. data/spec/rattler/parsers/back_reference_spec.rb +38 -0
  159. data/spec/rattler/parsers/combinator_parser_spec.rb +14 -0
  160. data/spec/rattler/parsers/direct_action_spec.rb +16 -2
  161. data/spec/rattler/parsers/dispatch_action_spec.rb +15 -32
  162. data/spec/rattler/parsers/fail_spec.rb +6 -4
  163. data/spec/rattler/parsers/label_spec.rb +10 -28
  164. data/spec/rattler/parsers/node_code_spec.rb +48 -0
  165. data/spec/rattler/parsers/parser_dsl_spec.rb +1 -1
  166. data/spec/rattler/parsers/rule_set_spec.rb +35 -0
  167. data/spec/rattler/parsers/sequence_spec.rb +15 -24
  168. data/spec/rattler/runtime/extended_packrat_parser_spec.rb +22 -17
  169. data/spec/rattler/runtime/packrat_parser_spec.rb +1 -1
  170. data/spec/rattler/runtime/parse_node_spec.rb +15 -19
  171. data/spec/rattler/runtime/recursive_descent_parser_spec.rb +1 -1
  172. data/spec/rattler/runtime/shared_parser_examples.rb +61 -28
  173. data/spec/rattler/util/graphviz/node_builder_spec.rb +84 -0
  174. data/spec/rattler/util/node_spec.rb +92 -65
  175. data/spec/rattler_spec.rb +16 -16
  176. data/spec/support/combinator_parser_spec_helper.rb +19 -18
  177. data/spec/support/compiler_spec_helper.rb +56 -87
  178. data/spec/support/runtime_parser_spec_helper.rb +6 -14
  179. metadata +117 -22
  180. data/features/grammar/regex.feature +0 -24
  181. data/lib/rattler/parsers/match_joining.rb +0 -67
  182. data/lib/rattler/parsers/rules.rb +0 -43
@@ -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.2.2/frames]
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
- * A packrat parser to cache results for backtracking
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
- %whitespace (SPACE+ | '/*' (! '*/' .)* '*/' | '//' [^\n]*)*
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
- object <- ~'{' members ~'}' { object _ }
72
+ string <- @('"' char* '"') { string _ }
50
73
 
51
- members <- pair *^ ','
74
+ number <- @(int frac? exp?) { number _ }
75
+ }
52
76
 
53
- pair <- string ~':' value
77
+ %inline {
54
78
 
55
- array <- ~'[' elements ~']'
79
+ char <- !('"' / '\\' / CNTRL) .
80
+ / '\\' (["\\/bfnrt] / 'u' XDIGIT XDIGIT XDIGIT XDIGIT)
56
81
 
57
- elements <- value *^ ','
82
+ int <- '-'? ('0' !DIGIT / [1-9] DIGIT*)
58
83
 
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"
84
+ frac <- '.' DIGIT+
67
85
 
68
- string <- @('"' ('\\' . | [^"])* '"')
86
+ exp <- [eE] [+-]? DIGIT+
69
87
 
70
- number <- @('-'? ('0' | [1-9] DIGIT*) ('.' DIGIT+)? ([eE] [+-]? DIGIT+)?)
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+ | '/*' (! '*/' .)* '*/' | '//' [^\n]*)*
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
- def string(expr)
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 {|a, b| a + b }
149
- | expr ~'-' term {|a, b| a - b }
150
- | term
168
+ expr <- expr ~'+' term {|a, b| a + b }
169
+ / expr ~'-' term {|a, b| a - b }
170
+ / term
151
171
 
152
- term <- term ~'*' primary {|a, b| a * b }
153
- | term ~'/' primary {|a, b| a / b }
154
- | primary
172
+ term <- term ~'*' primary {|a, b| a * b }
173
+ / term ~'/' primary {|a, b| a / b }
174
+ / primary
155
175
 
156
176
  primary <- ~'(' expr ~')'
157
- | @('-'? DIGIT+ '.' DIGIT+) { _.to_f }
158
- | @('-'? DIGIT+) { _.to_i }
159
- }, :type => :extended_packrat
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 a different (base) destination
4
- directory.
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: Grammar as top-level module
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/examples"
27
- When I run "rtlr --dest lib binary.rtlr"
28
- Then the output should contain "binary.rtlr -> lib/examples/binary_grammar.rb"
29
- And the file "lib/examples/binary_grammar.rb" should contain:
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
- -d, --dest DIRECTORY Specify the destination directory
13
- -o, --output FILENAME Specify a different output filename
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 | b | fail "something bad happened"
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:/\d+/ "/" denom:/\d+/ { numer.to_i / denom.to_i }
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:/\d+/ "/" denom:/\d+/ <Fraction>
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
- 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.
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 is like a normal Ruby string literal and it means to match
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: Parsing
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 |