rattler 0.3.0 → 0.4.0

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