rattler 0.5.0 → 0.6.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 (329) hide show
  1. data/README.rdoc +3 -175
  2. data/features/README.markdown +27 -0
  3. data/features/Tutorial.md +224 -0
  4. data/features/command_line/output_option.feature +2 -1
  5. data/features/command_line/{parser_generator.feature → rtlr.feature} +43 -15
  6. data/features/error_reporting/automatic_error_messages.feature +40 -0
  7. data/features/error_reporting/custom_error_messages.feature +28 -0
  8. data/features/examples/json_parser.markdown +88 -0
  9. data/features/{grammar → extended_matching_syntax}/back_reference.feature +5 -3
  10. data/features/{grammar → extended_matching_syntax}/e_symbol.feature +2 -2
  11. data/features/{grammar → extended_matching_syntax}/eof.feature +4 -3
  12. data/features/{grammar → extended_matching_syntax}/fail.feature +8 -6
  13. data/features/extended_matching_syntax/fragments.feature +29 -0
  14. data/features/extended_matching_syntax/include.feature +42 -0
  15. data/features/{grammar → extended_matching_syntax}/list_matching.feature +7 -6
  16. data/features/extended_matching_syntax/posix_class.feature +127 -0
  17. data/features/{grammar → extended_matching_syntax}/repeat.feature +29 -3
  18. data/features/{grammar → extended_matching_syntax}/skip_operator.feature +2 -1
  19. data/features/extended_matching_syntax/super.feature +24 -0
  20. data/features/{grammar → extended_matching_syntax}/token.feature +6 -5
  21. data/features/{grammar → extended_matching_syntax}/whitespace.feature +7 -6
  22. data/features/{grammar → extended_matching_syntax}/word_literal.feature +10 -6
  23. data/features/grammar_heading/explicit_start_rule.feature +20 -0
  24. data/features/grammar_heading/grammar_declaration.feature +60 -0
  25. data/features/grammar_heading/include.feature +19 -0
  26. data/features/grammar_heading/require.feature +27 -0
  27. data/features/{grammar → peg_syntax}/any_character.feature +1 -1
  28. data/features/peg_syntax/character_class.feature +25 -0
  29. data/features/{grammar → peg_syntax}/comments.feature +1 -1
  30. data/features/{grammar → peg_syntax}/literal.feature +5 -3
  31. data/features/{grammar → peg_syntax}/negative_lookahead.feature +5 -3
  32. data/features/peg_syntax/nonterminal.feature +46 -0
  33. data/features/peg_syntax/one_or_more.feature +59 -0
  34. data/features/{grammar → peg_syntax}/optional.feature +2 -2
  35. data/features/peg_syntax/ordered_choice.feature +24 -0
  36. data/features/{grammar → peg_syntax}/positive_lookahead.feature +6 -4
  37. data/features/peg_syntax/sequence.feature +23 -0
  38. data/features/{grammar → peg_syntax}/start_rule.feature +1 -1
  39. data/features/peg_syntax/zero_or_more.feature +59 -0
  40. data/features/{grammar → semantics}/labels.feature +0 -0
  41. data/features/{grammar → semantics}/negative_semantic_predicate.feature +30 -9
  42. data/features/{grammar → semantics}/node_action.feature +0 -0
  43. data/features/{grammar → semantics}/positive_semantic_predicate.feature +29 -8
  44. data/features/{grammar/symantic_action.feature → semantics/semantic_action.feature} +2 -2
  45. data/features/semantics/semantic_result.feature +86 -0
  46. data/features/{grammar → semantics}/side_effect.feature +33 -21
  47. data/features/step_definitions/cli_steps.rb +1 -1
  48. data/features/step_definitions/grammar_steps.rb +19 -5
  49. data/features/support/env.rb +5 -0
  50. data/lib/rattler.rb +21 -44
  51. data/lib/rattler/compiler.rb +69 -0
  52. data/lib/rattler/{grammar → compiler}/grammar_parser.rb +58 -24
  53. data/lib/rattler/compiler/metagrammar.rb +1570 -0
  54. data/lib/rattler/compiler/optimizer.rb +77 -0
  55. data/lib/rattler/{back_end → compiler}/optimizer/composite_reducing.rb +2 -2
  56. data/lib/rattler/{back_end → compiler}/optimizer/flatten_choice.rb +3 -12
  57. data/lib/rattler/{back_end → compiler}/optimizer/flatten_sequence.rb +4 -16
  58. data/lib/rattler/{back_end → compiler}/optimizer/flattening.rb +2 -2
  59. data/lib/rattler/compiler/optimizer/inline_regular_rules.rb +24 -0
  60. data/lib/rattler/{back_end → compiler}/optimizer/join_match_capturing_sequence.rb +16 -14
  61. data/lib/rattler/{back_end → compiler}/optimizer/join_match_choice.rb +4 -13
  62. data/lib/rattler/{back_end → compiler}/optimizer/join_match_matching_sequence.rb +4 -13
  63. data/lib/rattler/compiler/optimizer/join_match_sequence.rb +7 -0
  64. data/lib/rattler/{back_end → compiler}/optimizer/join_predicate_bare_match.rb +3 -12
  65. data/lib/rattler/compiler/optimizer/join_predicate_match.rb +7 -0
  66. data/lib/rattler/{back_end → compiler}/optimizer/join_predicate_nested_match.rb +4 -13
  67. data/lib/rattler/{back_end → compiler}/optimizer/join_predicate_or_bare_match.rb +3 -12
  68. data/lib/rattler/compiler/optimizer/join_predicate_or_match.rb +7 -0
  69. data/lib/rattler/{back_end → compiler}/optimizer/join_predicate_or_nested_match.rb +4 -13
  70. data/lib/rattler/{back_end → compiler}/optimizer/match_joining.rb +2 -2
  71. data/lib/rattler/{back_end → compiler}/optimizer/optimization.rb +12 -34
  72. data/lib/rattler/compiler/optimizer/optimization_context.rb +83 -0
  73. data/lib/rattler/{back_end → compiler}/optimizer/optimization_sequence.rb +3 -11
  74. data/lib/rattler/compiler/optimizer/optimizations.rb +27 -0
  75. data/lib/rattler/{back_end → compiler}/optimizer/optimize_children.rb +6 -14
  76. data/lib/rattler/{back_end → compiler}/optimizer/reduce_repeat_match.rb +4 -13
  77. data/lib/rattler/compiler/optimizer/remove_meaningless_wrapper.rb +22 -0
  78. data/lib/rattler/{back_end → compiler}/optimizer/simplify_redundant_repeat.rb +4 -13
  79. data/lib/rattler/{back_end → compiler}/optimizer/simplify_token_match.rb +4 -13
  80. data/lib/rattler/compiler/parser_generator.rb +108 -0
  81. data/lib/rattler/{back_end → compiler}/parser_generator/apply_generator.rb +7 -21
  82. data/lib/rattler/{back_end → compiler}/parser_generator/assert_generator.rb +11 -19
  83. data/lib/rattler/compiler/parser_generator/attributed_sequence_generator.rb +37 -0
  84. data/lib/rattler/{back_end → compiler}/parser_generator/back_reference_generator.rb +10 -10
  85. data/lib/rattler/{back_end → compiler}/parser_generator/choice_generator.rb +10 -22
  86. data/lib/rattler/{back_end → compiler}/parser_generator/delegating_generator.rb +2 -2
  87. data/lib/rattler/{back_end → compiler}/parser_generator/disallow_generator.rb +11 -19
  88. data/lib/rattler/{back_end → compiler}/parser_generator/e_symbol_generator.rb +2 -10
  89. data/lib/rattler/{back_end → compiler}/parser_generator/eof_generator.rb +2 -10
  90. data/lib/rattler/{back_end → compiler}/parser_generator/expr_generator.rb +9 -35
  91. data/lib/rattler/{back_end → compiler}/parser_generator/fail_generator.rb +7 -3
  92. data/lib/rattler/{back_end → compiler}/parser_generator/gen_method_names.rb +3 -5
  93. data/lib/rattler/{back_end → compiler}/parser_generator/general_list_generator.rb +6 -18
  94. data/lib/rattler/{back_end → compiler}/parser_generator/general_repeat_generator.rb +16 -22
  95. data/lib/rattler/{back_end/parser_generator/rule_set_generator.rb → compiler/parser_generator/grammar_generator.rb} +24 -33
  96. data/lib/rattler/compiler/parser_generator/group_match.rb +33 -0
  97. data/lib/rattler/{back_end → compiler}/parser_generator/group_match_generator.rb +4 -17
  98. data/lib/rattler/compiler/parser_generator/label_generator.rb +37 -0
  99. data/lib/rattler/{back_end → compiler}/parser_generator/list0_generating.rb +5 -5
  100. data/lib/rattler/{back_end → compiler}/parser_generator/list1_generating.rb +3 -3
  101. data/lib/rattler/{back_end → compiler}/parser_generator/list_generator.rb +2 -2
  102. data/lib/rattler/{back_end → compiler}/parser_generator/match_generator.rb +10 -10
  103. data/lib/rattler/{back_end → compiler}/parser_generator/nested.rb +2 -2
  104. data/lib/rattler/compiler/parser_generator/node_action_generator.rb +49 -0
  105. data/lib/rattler/{back_end → compiler}/parser_generator/one_or_more_generating.rb +3 -3
  106. data/lib/rattler/{back_end → compiler}/parser_generator/optional_generating.rb +6 -22
  107. data/lib/rattler/compiler/parser_generator/predicate_propogating.rb +24 -0
  108. data/lib/rattler/{back_end → compiler}/parser_generator/repeat_generator.rb +2 -2
  109. data/lib/rattler/compiler/parser_generator/rule_generator.rb +66 -0
  110. data/lib/rattler/compiler/parser_generator/rule_set_generator.rb +33 -0
  111. data/lib/rattler/compiler/parser_generator/semantic_action_generator.rb +58 -0
  112. data/lib/rattler/compiler/parser_generator/sequence_generating.rb +138 -0
  113. data/lib/rattler/compiler/parser_generator/sequence_generator.rb +57 -0
  114. data/lib/rattler/{back_end → compiler}/parser_generator/skip_generator.rb +4 -18
  115. data/lib/rattler/compiler/parser_generator/skip_propogating.rb +16 -0
  116. data/lib/rattler/{back_end → compiler}/parser_generator/sub_generating.rb +19 -11
  117. data/lib/rattler/compiler/parser_generator/super_generator.rb +54 -0
  118. data/lib/rattler/{back_end → compiler}/parser_generator/token_generator.rb +3 -3
  119. data/lib/rattler/compiler/parser_generator/token_propogating.rb +10 -0
  120. data/lib/rattler/{back_end → compiler}/parser_generator/top_level.rb +2 -2
  121. data/lib/rattler/{back_end → compiler}/parser_generator/zero_or_more_generating.rb +5 -5
  122. data/lib/rattler/compiler/rattler.rtlr +201 -0
  123. data/lib/rattler/{back_end → compiler}/ruby_generator.rb +16 -25
  124. data/lib/rattler/parsers.rb +12 -33
  125. data/lib/rattler/parsers/action_code.rb +25 -16
  126. data/lib/rattler/{grammar → parsers}/analysis.rb +32 -11
  127. data/lib/rattler/parsers/apply.rb +10 -19
  128. data/lib/rattler/parsers/assert.rb +4 -14
  129. data/lib/rattler/parsers/atomic.rb +3 -10
  130. data/lib/rattler/parsers/attributed_sequence.rb +50 -0
  131. data/lib/rattler/parsers/back_reference.rb +19 -14
  132. data/lib/rattler/parsers/choice.rb +11 -12
  133. data/lib/rattler/parsers/combinator_parser.rb +15 -7
  134. data/lib/rattler/parsers/combining.rb +15 -9
  135. data/lib/rattler/parsers/disallow.rb +5 -12
  136. data/lib/rattler/parsers/e_symbol.rb +5 -14
  137. data/lib/rattler/parsers/eof.rb +10 -15
  138. data/lib/rattler/parsers/fail.rb +16 -26
  139. data/lib/rattler/{grammar → parsers}/grammar.rb +15 -20
  140. data/lib/rattler/parsers/label.rb +10 -16
  141. data/lib/rattler/parsers/list_parser.rb +14 -14
  142. data/lib/rattler/parsers/match.rb +5 -17
  143. data/lib/rattler/parsers/node_action.rb +72 -0
  144. data/lib/rattler/parsers/node_code.rb +47 -30
  145. data/lib/rattler/parsers/parser.rb +63 -32
  146. data/lib/rattler/parsers/parser_scope.rb +88 -0
  147. data/lib/rattler/parsers/predicate.rb +12 -10
  148. data/lib/rattler/parsers/repeat.rb +15 -8
  149. data/lib/rattler/parsers/rule.rb +8 -23
  150. data/lib/rattler/parsers/rule_set.rb +67 -12
  151. data/lib/rattler/parsers/semantic.rb +36 -0
  152. data/lib/rattler/parsers/semantic_action.rb +39 -0
  153. data/lib/rattler/parsers/sequence.rb +25 -40
  154. data/lib/rattler/parsers/sequencing.rb +40 -0
  155. data/lib/rattler/parsers/skip.rb +11 -12
  156. data/lib/rattler/parsers/super.rb +33 -0
  157. data/lib/rattler/parsers/token.rb +3 -13
  158. data/lib/rattler/rake_task.rb +50 -0
  159. data/lib/rattler/runner.rb +19 -22
  160. data/lib/rattler/runtime.rb +0 -10
  161. data/lib/rattler/runtime/extended_packrat_parser.rb +40 -45
  162. data/lib/rattler/runtime/packrat_parser.rb +17 -31
  163. data/lib/rattler/runtime/parse_failure.rb +16 -26
  164. data/lib/rattler/runtime/parse_node.rb +8 -18
  165. data/lib/rattler/runtime/parser.rb +6 -18
  166. data/lib/rattler/runtime/parser_helper.rb +3 -10
  167. data/lib/rattler/runtime/recursive_descent_parser.rb +26 -23
  168. data/lib/rattler/runtime/syntax_error.rb +0 -10
  169. data/lib/rattler/util.rb +2 -6
  170. data/lib/rattler/util/grammar_cli.rb +19 -0
  171. data/lib/rattler/util/graphviz.rb +6 -17
  172. data/lib/rattler/util/graphviz/digraph_builder.rb +10 -17
  173. data/lib/rattler/util/graphviz/node_builder.rb +45 -31
  174. data/lib/rattler/util/line_counter.rb +11 -20
  175. data/lib/rattler/util/node.rb +52 -30
  176. data/lib/rattler/util/parser_cli.rb +84 -0
  177. data/lib/rattler/util/parser_spec_helper.rb +8 -12
  178. data/spec/rattler/compiler/assert_compiler_examples.rb +284 -0
  179. data/spec/rattler/compiler/attributed_sequence_compiler_examples.rb +154 -0
  180. data/spec/rattler/compiler/disallow_compiler_examples.rb +293 -0
  181. data/spec/rattler/compiler/grammar_parser_spec.rb +700 -0
  182. data/spec/rattler/{back_end → compiler}/optimizer/flatten_choice_spec.rb +1 -1
  183. data/spec/rattler/{back_end → compiler}/optimizer/flatten_sequence_spec.rb +1 -1
  184. data/spec/rattler/compiler/optimizer/inline_regular_rules_spec.rb +50 -0
  185. data/spec/rattler/{back_end → compiler}/optimizer/join_match_capturing_sequence_spec.rb +106 -22
  186. data/spec/rattler/{back_end → compiler}/optimizer/join_match_choice_spec.rb +1 -1
  187. data/spec/rattler/{back_end → compiler}/optimizer/join_match_matching_sequence_spec.rb +1 -1
  188. data/spec/rattler/{back_end → compiler}/optimizer/join_predicate_bare_match_spec.rb +1 -1
  189. data/spec/rattler/{back_end → compiler}/optimizer/join_predicate_nested_match_spec.rb +1 -1
  190. data/spec/rattler/{back_end → compiler}/optimizer/join_predicate_or_bare_match_spec.rb +1 -1
  191. data/spec/rattler/{back_end → compiler}/optimizer/join_predicate_or_nested_match_spec.rb +1 -1
  192. data/spec/rattler/{back_end → compiler}/optimizer/reduce_repeat_match_spec.rb +1 -1
  193. data/spec/rattler/compiler/optimizer/remove_meaningless_wrapper_spec.rb +82 -0
  194. data/spec/rattler/{back_end → compiler}/optimizer/simplify_redundant_repeat_spec.rb +1 -1
  195. data/spec/rattler/{back_end → compiler}/optimizer/simplify_token_match_spec.rb +1 -1
  196. data/spec/rattler/{back_end → compiler}/optimizer_spec.rb +1 -1
  197. data/spec/rattler/{back_end → compiler}/parser_generator/apply_generator_spec.rb +1 -39
  198. data/spec/rattler/{back_end → compiler}/parser_generator/assert_generator_spec.rb +1 -55
  199. data/spec/rattler/compiler/parser_generator/attributed_sequence_generator_spec.rb +699 -0
  200. data/spec/rattler/{back_end → compiler}/parser_generator/back_reference_generator_spec.rb +3 -56
  201. data/spec/rattler/{back_end → compiler}/parser_generator/choice_generator_spec.rb +1 -63
  202. data/spec/rattler/{back_end → compiler}/parser_generator/disallow_generator_spec.rb +1 -55
  203. data/spec/rattler/{back_end → compiler}/parser_generator/e_symbol_generator_spec.rb +1 -39
  204. data/spec/rattler/{back_end → compiler}/parser_generator/eof_generator_spec.rb +1 -39
  205. data/spec/rattler/{back_end → compiler}/parser_generator/fail_generator_spec.rb +94 -23
  206. data/spec/rattler/compiler/parser_generator/grammar_generator_spec.rb +98 -0
  207. data/spec/rattler/compiler/parser_generator/group_match_generator_spec.rb +67 -0
  208. data/spec/rattler/{back_end → compiler}/parser_generator/group_match_spec.rb +1 -1
  209. data/spec/rattler/{back_end → compiler}/parser_generator/label_generator_spec.rb +1 -55
  210. data/spec/rattler/{back_end → compiler}/parser_generator/list0_generator_examples.rb +0 -88
  211. data/spec/rattler/{back_end → compiler}/parser_generator/list1_generator_examples.rb +0 -88
  212. data/spec/rattler/{back_end → compiler}/parser_generator/list_generator_spec.rb +1 -227
  213. data/spec/rattler/{back_end → compiler}/parser_generator/match_generator_spec.rb +1 -55
  214. data/spec/rattler/compiler/parser_generator/node_action_generator_spec.rb +135 -0
  215. data/spec/rattler/{back_end → compiler}/parser_generator/one_or_more_generator_examples.rb +0 -74
  216. data/spec/rattler/{back_end → compiler}/parser_generator/optional_generator_examples.rb +0 -62
  217. data/spec/rattler/{back_end → compiler}/parser_generator/repeat_generator_spec.rb +66 -1
  218. data/spec/rattler/{back_end → compiler}/parser_generator/rule_generator_spec.rb +3 -2
  219. data/spec/rattler/{back_end → compiler}/parser_generator/rule_set_generator_spec.rb +9 -27
  220. data/spec/rattler/compiler/parser_generator/semantic_action_generator_spec.rb +437 -0
  221. data/spec/rattler/{back_end → compiler}/parser_generator/sequence_generator_spec.rb +234 -68
  222. data/spec/rattler/{back_end → compiler}/parser_generator/skip_generator_spec.rb +1 -55
  223. data/spec/rattler/compiler/parser_generator/super_generator_spec.rb +93 -0
  224. data/spec/rattler/{back_end → compiler}/parser_generator/token_generator_spec.rb +1 -55
  225. data/spec/rattler/{back_end → compiler}/parser_generator/zero_or_more_generator_examples.rb +0 -74
  226. data/spec/rattler/{back_end → compiler}/ruby_generator_spec.rb +13 -13
  227. data/spec/rattler/compiler/semantic_action_compiler_examples.rb +57 -0
  228. data/spec/rattler/{back_end → compiler}/shared_compiler_examples.rb +111 -140
  229. data/spec/rattler/{back_end → compiler}/skip_compiler_examples.rb +60 -57
  230. data/spec/rattler/{back_end → compiler}/token_compiler_examples.rb +99 -104
  231. data/spec/rattler/compiler_spec.rb +67 -0
  232. data/spec/rattler/parsers/action_code_spec.rb +34 -18
  233. data/spec/rattler/{grammar → parsers}/analysis_spec.rb +13 -67
  234. data/spec/rattler/parsers/apply_spec.rb +6 -0
  235. data/spec/rattler/parsers/assert_spec.rb +38 -2
  236. data/spec/rattler/parsers/attributed_sequence_spec.rb +204 -0
  237. data/spec/rattler/parsers/back_reference_spec.rb +6 -0
  238. data/spec/rattler/parsers/choice_spec.rb +38 -1
  239. data/spec/rattler/parsers/combinator_parser_spec.rb +2 -1
  240. data/spec/rattler/parsers/disallow_spec.rb +38 -2
  241. data/spec/rattler/parsers/e_symbol_spec.rb +6 -0
  242. data/spec/rattler/parsers/eof_spec.rb +6 -0
  243. data/spec/rattler/parsers/fail_spec.rb +6 -0
  244. data/spec/rattler/{grammar → parsers}/grammar_spec.rb +10 -15
  245. data/spec/rattler/parsers/label_spec.rb +30 -0
  246. data/spec/rattler/parsers/list_parser_spec.rb +31 -2
  247. data/spec/rattler/parsers/match_spec.rb +6 -0
  248. data/spec/rattler/parsers/node_action_spec.rb +121 -0
  249. data/spec/rattler/parsers/parser_scope_spec.rb +105 -0
  250. data/spec/rattler/parsers/repeat_spec.rb +56 -0
  251. data/spec/rattler/parsers/rule_set_spec.rb +42 -0
  252. data/spec/rattler/parsers/semantic_action_spec.rb +89 -0
  253. data/spec/rattler/parsers/sequence_spec.rb +156 -12
  254. data/spec/rattler/parsers/skip_spec.rb +21 -0
  255. data/spec/rattler/parsers/super_spec.rb +45 -0
  256. data/spec/rattler/parsers/token_spec.rb +33 -14
  257. data/spec/rattler/runtime/extended_packrat_parser_spec.rb +10 -8
  258. data/spec/rattler/runtime/recursive_descent_parser_spec.rb +26 -0
  259. data/spec/rattler/runtime/shared_parser_examples.rb +22 -16
  260. data/spec/rattler/util/graphviz/node_builder_spec.rb +33 -17
  261. data/spec/rattler/util/line_counter_spec.rb +21 -21
  262. data/spec/rattler/util/node_spec.rb +62 -0
  263. data/spec/rattler_spec.rb +7 -41
  264. data/spec/spec_helper.rb +1 -2
  265. data/spec/support/combinator_parser_spec_helper.rb +1 -1
  266. data/spec/support/compiler_spec_helper.rb +0 -4
  267. data/spec/support/parser_generator_spec_helper.rb +7 -7
  268. data/spec/support/runtime_parser_spec_helper.rb +57 -3
  269. metadata +447 -303
  270. data/features/grammar/character_class.feature +0 -20
  271. data/features/grammar/nonterminal.feature +0 -24
  272. data/features/grammar/one_or_more.feature +0 -34
  273. data/features/grammar/ordered_choice.feature +0 -21
  274. data/features/grammar/posix_class.feature +0 -70
  275. data/features/grammar/sequence.feature +0 -20
  276. data/features/grammar/zero_or_more.feature +0 -34
  277. data/lib/rattler/back_end.rb +0 -22
  278. data/lib/rattler/back_end/compiler.rb +0 -128
  279. data/lib/rattler/back_end/optimizer.rb +0 -101
  280. data/lib/rattler/back_end/optimizer/inline_regular_rules.rb +0 -46
  281. data/lib/rattler/back_end/optimizer/join_match_sequence.rb +0 -17
  282. data/lib/rattler/back_end/optimizer/join_predicate_match.rb +0 -17
  283. data/lib/rattler/back_end/optimizer/join_predicate_or_match.rb +0 -17
  284. data/lib/rattler/back_end/optimizer/optimization_context.rb +0 -72
  285. data/lib/rattler/back_end/optimizer/remove_meaningless_wrapper.rb +0 -32
  286. data/lib/rattler/back_end/optimizer/specialize_repeat.rb +0 -40
  287. data/lib/rattler/back_end/parser_generator.rb +0 -113
  288. data/lib/rattler/back_end/parser_generator/direct_action_generator.rb +0 -45
  289. data/lib/rattler/back_end/parser_generator/dispatch_action_generator.rb +0 -45
  290. data/lib/rattler/back_end/parser_generator/group_match.rb +0 -26
  291. data/lib/rattler/back_end/parser_generator/label_generator.rb +0 -64
  292. data/lib/rattler/back_end/parser_generator/predicate_propogating.rb +0 -24
  293. data/lib/rattler/back_end/parser_generator/rule_generator.rb +0 -53
  294. data/lib/rattler/back_end/parser_generator/sequence_generator.rb +0 -190
  295. data/lib/rattler/back_end/parser_generator/skip_propogating.rb +0 -16
  296. data/lib/rattler/back_end/parser_generator/token_propogating.rb +0 -10
  297. data/lib/rattler/grammar.rb +0 -43
  298. data/lib/rattler/grammar/grammar_dsl.rb +0 -51
  299. data/lib/rattler/grammar/metagrammar.rb +0 -990
  300. data/lib/rattler/grammar/rattler.rtlr +0 -183
  301. data/lib/rattler/parsers/assert_code.rb +0 -31
  302. data/lib/rattler/parsers/direct_action.rb +0 -85
  303. data/lib/rattler/parsers/disallow_code.rb +0 -31
  304. data/lib/rattler/parsers/dispatch_action.rb +0 -121
  305. data/lib/rattler/parsers/effect_code.rb +0 -31
  306. data/lib/rattler/parsers/parser_dsl.rb +0 -414
  307. data/lib/rattler/parsers/semantic_assert.rb +0 -19
  308. data/lib/rattler/parsers/semantic_disallow.rb +0 -19
  309. data/lib/rattler/parsers/side_effect.rb +0 -19
  310. data/spec/rattler/back_end/assert_compiler_examples.rb +0 -187
  311. data/spec/rattler/back_end/compiler_spec.rb +0 -43
  312. data/spec/rattler/back_end/direct_action_compiler_examples.rb +0 -227
  313. data/spec/rattler/back_end/disallow_compiler_examples.rb +0 -187
  314. data/spec/rattler/back_end/dispatch_action_compiler_examples.rb +0 -225
  315. data/spec/rattler/back_end/optimizer/inline_regular_rules_spec.rb +0 -80
  316. data/spec/rattler/back_end/parser_generator/direct_action_generator_spec.rb +0 -204
  317. data/spec/rattler/back_end/parser_generator/dispatch_action_generator_spec.rb +0 -204
  318. data/spec/rattler/back_end/parser_generator/group_match_generator_spec.rb +0 -185
  319. data/spec/rattler/back_end/semantic_assert_compiler_examples.rb +0 -152
  320. data/spec/rattler/back_end/semantic_disallow_compiler_examples.rb +0 -152
  321. data/spec/rattler/back_end/side_effect_compiler_examples.rb +0 -227
  322. data/spec/rattler/grammar/grammar_parser_spec.rb +0 -626
  323. data/spec/rattler/parsers/direct_action_spec.rb +0 -224
  324. data/spec/rattler/parsers/dispatch_action_spec.rb +0 -209
  325. data/spec/rattler/parsers/node_code_spec.rb +0 -59
  326. data/spec/rattler/parsers/parser_dsl_spec.rb +0 -334
  327. data/spec/rattler/parsers/semantic_assert_spec.rb +0 -83
  328. data/spec/rattler/parsers/semantic_disallow_spec.rb +0 -83
  329. data/spec/rattler/parsers/side_effect_spec.rb +0 -214
@@ -0,0 +1,293 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
2
+
3
+ shared_examples_for 'a compiled parser with a disallow' do
4
+ include CompilerSpecHelper
5
+ include RuntimeParserSpecHelper
6
+
7
+ subject { compiled_parser }
8
+
9
+ let(:reference_parser) { combinator_parser grammar }
10
+
11
+ let(:grammar) { Rattler::Parsers::Grammar[Rattler::Parsers::RuleSet[*rules]] }
12
+
13
+ context 'with a nested match rule' do
14
+ let(:rules) { [
15
+ rule(:word) { disallow(/\w+/) }
16
+ ] }
17
+ it { should parse(' ').succeeding.like reference_parser }
18
+ it { should parse('abc123 ').failing.like reference_parser }
19
+ end
20
+
21
+ context 'with a nested eof rule' do
22
+ let(:rules) { [
23
+ rule(:foo) { disallow(eof) }
24
+ ] }
25
+ it { should parse('foo').succeeding.like reference_parser }
26
+ it { should parse('').failing.like reference_parser }
27
+ it { should parse('foo').from(3).failing.like reference_parser }
28
+ end
29
+
30
+ context 'with a nested "E" symbol rule' do
31
+ let(:rules) { [
32
+ rule(:foo) { disallow(e) }
33
+ ] }
34
+ it { should parse('').failing.like reference_parser }
35
+ it { should parse('foo').failing.like reference_parser }
36
+ end
37
+
38
+ context 'with a nested choice rule' do
39
+ let(:rules) { [
40
+ rule(:word) { disallow(match(/[[:alpha:]]/) | match(/[[:digit:]]/)) }
41
+ ] }
42
+ it { should parse(' ').succeeding.like reference_parser }
43
+ it { should parse('abc123 ').failing.like reference_parser }
44
+ end
45
+
46
+ context 'with a nested sequence rule' do
47
+ let(:rules) { [
48
+ rule(:word) { disallow(match(/[[:alpha:]]+/) & match(/[[:digit:]]+/)) }
49
+ ] }
50
+ it { should parse(' ').succeeding.like reference_parser }
51
+ it { should parse('abc123 ').failing.like reference_parser }
52
+
53
+ context 'with a semantic action' do
54
+
55
+ context 'when the expression has parameters' do
56
+ let(:rules) { [
57
+ rule(:a) {
58
+ disallow(match(/\d+/) >> semantic_action('|a| a.to_i * 2'))
59
+ }
60
+ ] }
61
+ it { should parse(' ').succeeding.like reference_parser }
62
+ it { should parse('451a').failing.like reference_parser }
63
+ end
64
+
65
+ context 'when the expression uses "_"' do
66
+
67
+ context 'given a single capture' do
68
+ let(:rules) { [
69
+ rule(:a) { disallow(match(/\d+/) >> semantic_action('_ * 2')) }
70
+ ] }
71
+ it { should parse(' ').succeeding.like reference_parser }
72
+ it { should parse('451a').failing.like reference_parser }
73
+ end
74
+
75
+ context 'given multiple captures' do
76
+ let(:rules) { [
77
+ rule(:a) { disallow(
78
+ (match(/\d+/) & skip(/\s+/) & match(/\d+/)) >> semantic_action('_')
79
+ ) }
80
+ ] }
81
+ it { should parse(' ').succeeding.like reference_parser }
82
+ it { should parse('23 42').failing.like reference_parser }
83
+ end
84
+ end
85
+
86
+ context 'when the expression uses labels' do
87
+ let(:rules) { [
88
+ rule(:a) { disallow(
89
+ label(:a, /\d+/) >> semantic_action('a.to_i * 2')
90
+ ) }
91
+ ] }
92
+ it { should parse(' ').succeeding.like reference_parser }
93
+ it { should parse('451a').failing.like reference_parser }
94
+ end
95
+ end
96
+ end
97
+
98
+ context 'with a nested optional rule' do
99
+ let(:rules) { [
100
+ rule(:word) { disallow(match(/\w+/).optional) }
101
+ ] }
102
+ it { should parse(' ').failing.like reference_parser }
103
+ it { should parse('abc123 ').failing.like reference_parser }
104
+ end
105
+
106
+ context 'with a nested zero_or_more rule' do
107
+ let(:rules) { [
108
+ rule(:word) { disallow(match(/\w/).zero_or_more) }
109
+ ] }
110
+ it { should parse(' ').failing.like reference_parser }
111
+ it { should parse('abc123 ').failing.like reference_parser }
112
+ end
113
+
114
+ context 'with a nested one_or_more rule' do
115
+ let(:rules) { [
116
+ rule(:word) { disallow(match(/\w/).one_or_more) }
117
+ ] }
118
+ it { should parse(' ').succeeding.like reference_parser }
119
+ it { should parse('abc123 ').failing.like reference_parser }
120
+ end
121
+
122
+ context 'with a nested repeat rule' do
123
+ let(:rules) { [
124
+ rule(:word) { disallow(match(/\w/).repeat(2, nil)) }
125
+ ] }
126
+ it { should parse('a ').succeeding.like reference_parser }
127
+ it { should parse('abc123 ').failing.like reference_parser }
128
+
129
+ context 'with zero-or-more bounds' do
130
+ let(:rules) { [
131
+ rule(:word) { disallow(match(/\w/).repeat(0, nil)) }
132
+ ] }
133
+ it { should parse(' ').failing.like reference_parser }
134
+ it { should parse('abc123 ').failing.like reference_parser }
135
+
136
+ context 'with an upper bound' do
137
+ let(:rules) { [
138
+ rule(:word) { disallow(match(/\w/).repeat(0, 2)) }
139
+ ] }
140
+ it { should parse(' ').failing.like reference_parser }
141
+ it { should parse('abc123 ').failing.like reference_parser }
142
+ end
143
+ end
144
+
145
+ context 'with one-or-more bounds' do
146
+ let(:rules) { [
147
+ rule(:word) { disallow(match(/\w/).repeat(1, nil)) }
148
+ ] }
149
+ it { should parse(' ').succeeding.like reference_parser }
150
+ it { should parse('abc123 ').failing.like reference_parser }
151
+
152
+ context 'with an upper bound' do
153
+ let(:rules) { [
154
+ rule(:word) { disallow(match(/\w/).repeat(1, 2)) }
155
+ ] }
156
+ it { should parse(' ').succeeding.like reference_parser }
157
+ it { should parse('abc123 ').failing.like reference_parser }
158
+ end
159
+ end
160
+ end
161
+
162
+ context 'with a nested list rule' do
163
+ let(:rules) { [
164
+ rule(:foo) { disallow match(/\w+/).list(match(/[,;]/), 2, nil) }
165
+ ] }
166
+ it { should parse('foo ').succeeding.like reference_parser }
167
+ it { should parse('foo,bar;baz ').failing.like reference_parser }
168
+
169
+ context 'with an upper bound' do
170
+ let(:rules) { [
171
+ rule(:foo) {
172
+ disallow(match(/\w+/).list(match(/[,;]/), 2, 4))
173
+ }
174
+ ] }
175
+ it { should parse('foo ').succeeding.like reference_parser }
176
+ it { should parse('foo,bar;baz ').failing.like reference_parser }
177
+ end
178
+
179
+ context 'with a non-capturing parser' do
180
+ let(:rules) { [
181
+ rule(:foo) {
182
+ disallow(skip(/\w+/).list(match(/[,;]/), 2, nil))
183
+ }
184
+ ] }
185
+ it { should parse('foo ').succeeding.like reference_parser }
186
+ it { should parse('foo,bar;baz ').failing.like reference_parser }
187
+
188
+ context 'with an upper bound' do
189
+ let(:rules) { [
190
+ rule(:foo) {
191
+ disallow skip(/\w+/).list(match(/[,;]/), 2, 4)
192
+ }
193
+ ] }
194
+ it { should parse('foo ').succeeding.like reference_parser }
195
+ it { should parse('foo,bar;baz ').failing.like reference_parser }
196
+ end
197
+ end
198
+ end
199
+
200
+ context 'with a nested apply rule' do
201
+ let(:rules) { [
202
+ rule(:foo) { match(:word) },
203
+ rule(:word) { disallow(/\w+/) }
204
+ ] }
205
+ it { should parse(' ').succeeding.like reference_parser }
206
+ it { should parse('abc123 ').failing.like reference_parser }
207
+ end
208
+
209
+ context 'with a nested attributed sequence' do
210
+
211
+ context 'with a single capture and a semantic action' do
212
+
213
+ context 'when the action uses a parameter' do
214
+ let(:rules) { [
215
+ rule(:a) { disallow(match(/\d+/) >> semantic_action('|a| a.to_i')) }
216
+ ] }
217
+ it { should parse(' ').succeeding.like reference_parser }
218
+ it { should parse('451a').failing.like reference_parser }
219
+ end
220
+
221
+ context 'when the action uses "_"' do
222
+ let(:rules) { [
223
+ rule(:a) { disallow(match(/\d+/) >> semantic_action('_.to_i')) }
224
+ ] }
225
+ it { should parse(' ').succeeding.like reference_parser }
226
+ it { should parse('451a').failing.like reference_parser }
227
+ end
228
+ end
229
+
230
+ context 'with multiple captures and a semantic action' do
231
+
232
+ context 'when the action uses parameters' do
233
+ let(:rules) { [
234
+ rule(:a) {
235
+ disallow(
236
+ (match(/[a-z]+/) & match(/\d+/)) >> semantic_action('|a,b| b+a')
237
+ )
238
+ }
239
+ ] }
240
+ it { should parse(' ').succeeding.like reference_parser }
241
+ it { should parse('abc123').failing.like reference_parser }
242
+ end
243
+
244
+ context 'when the action uses "_"' do
245
+ let(:rules) { [
246
+ rule(:a) {
247
+ disallow(
248
+ (match(/[a-z]+/) & match(/\d+/)) >> semantic_action('_.reverse')
249
+ )
250
+ }
251
+ ] }
252
+ it { should parse(' ').succeeding.like reference_parser }
253
+ it { should parse('abc123').failing.like reference_parser }
254
+ end
255
+ end
256
+
257
+ context 'with a single labeled capture and a semantic action' do
258
+ let(:rules) { [
259
+ rule(:e) { disallow(label(:a, /\d+/) >> semantic_action('a.to_i')) }
260
+ ] }
261
+ it { should parse(' ').succeeding.like reference_parser }
262
+ it { should parse('451a').failing.like reference_parser }
263
+ end
264
+
265
+ context 'with multiple labeled captures and a semantic action' do
266
+ let(:rules) { [
267
+ rule(:e) {
268
+ disallow(
269
+ (label(:a, /[a-z]+/) & label(:b, /\d+/)) >> semantic_action('b + a')
270
+ )
271
+ }
272
+ ] }
273
+ it { should parse(' ').succeeding.like reference_parser }
274
+ it { should parse('abc123').failing.like reference_parser }
275
+ end
276
+ end
277
+
278
+ context 'with a nested token rule' do
279
+ let(:rules) { [
280
+ rule(:word) { disallow(token(/\w+/)) }
281
+ ] }
282
+ it { should parse(' ').succeeding.like reference_parser }
283
+ it { should parse('abc123 ').failing.like reference_parser }
284
+ end
285
+
286
+ context 'with a nested skip rule' do
287
+ let(:rules) { [
288
+ rule(:word) { disallow(skip(/\w+/)) }
289
+ ] }
290
+ it { should parse(' ').succeeding.like reference_parser }
291
+ it { should parse('abc123 ').failing.like reference_parser }
292
+ end
293
+ end
@@ -0,0 +1,700 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
2
+
3
+ include Rattler::Parsers
4
+
5
+ describe Rattler::Compiler::GrammarParser do
6
+ include Rattler::Util::ParserSpecHelper
7
+
8
+ let :posix_names do
9
+ %w{alnum alpha blank cntrl digit graph lower print punct space upper xdigit}
10
+ end
11
+
12
+ describe '#match(:heading)' do
13
+
14
+ context 'given no contents' do
15
+ it 'parses as a hash with empty :requires and :includes' do
16
+ matching(' ').as(:heading).should result_in({
17
+ :requires => [],
18
+ :includes => []
19
+ })
20
+ end
21
+ end
22
+
23
+ context 'given require statements' do
24
+ it 'parses as a hash with :requires' do
25
+ matching(%{
26
+ require 'rattler'
27
+ require 'my_language/semantics'
28
+ }).as(:heading).should result_in({
29
+ :requires => ["'rattler'", "'my_language/semantics'"],
30
+ :includes => []
31
+ })
32
+ end
33
+ end
34
+
35
+ context 'given a require_relative statement' do
36
+ it 'translates the require_relative into ruby 1.8' do
37
+ matching("require_relative 'my_semantics'").as(:heading).should result_in({
38
+ :requires => ["File.expand_path('my_semantics', File.dirname(__FILE__))"],
39
+ :includes => []
40
+ })
41
+ end
42
+ end
43
+
44
+ context 'given a parser declaration' do
45
+ it 'parses as a hash with :parser_name and base_name' do
46
+ matching(%{
47
+ parser FooParser < Rattler::Runtime::RecursiveDescentParser
48
+ }).as(:heading).should result_in({
49
+ :parser_name => 'FooParser',
50
+ :base_name => 'Rattler::Runtime::RecursiveDescentParser',
51
+ :requires => [],
52
+ :includes => []
53
+ })
54
+ end
55
+ end
56
+
57
+ context 'given a grammar declaration' do
58
+ it 'parses as a hash with :grammar_name' do
59
+ matching('grammar FooGrammar').as(:heading).should result_in({
60
+ :grammar_name => 'FooGrammar',
61
+ :requires => [],
62
+ :includes => []
63
+ })
64
+ end
65
+ end
66
+
67
+ context 'given include statements' do
68
+ it 'parses as a hash with :includes' do
69
+ matching(%{
70
+ include MyHelpers
71
+ include MyLanguage::Semantics
72
+ }).as(:heading).should result_in({
73
+ :requires => [],
74
+ :includes => ['MyHelpers', 'MyLanguage::Semantics']
75
+ })
76
+ end
77
+ end
78
+
79
+ context 'given a %start directive' do
80
+ it 'parses as a hash with :start_rule' do
81
+ matching(' %start expr ').as(:heading).should result_in({
82
+ :start_rule => 'expr',
83
+ :requires => [],
84
+ :includes => []
85
+ })
86
+ end
87
+ end
88
+ end
89
+
90
+ describe '#match(:rules)' do
91
+
92
+ context 'given a single rule' do
93
+ it 'parses as a RuleSet with a single Rule' do
94
+ matching(%{ int <- DIGIT+ }).as(:rules).should result_in(RuleSet[
95
+ Rule[:int, Match[/[[:digit:]]/].one_or_more, {:inline => false}]
96
+ ])
97
+ end
98
+ end
99
+
100
+ context 'given multiple rules' do
101
+ it 'parses as a RuleSet with multiple Rules' do
102
+ matching(%{
103
+ word <- ALPHA+
104
+ int <- DIGIT+
105
+ }).as(:rules).should result_in(RuleSet[
106
+ Rule[:word, Match[/[[:alpha:]]/].one_or_more, {:inline => false}],
107
+ Rule[:int, Match[/[[:digit:]]/].one_or_more, {:inline => false}]
108
+ ])
109
+ end
110
+ end
111
+ end
112
+
113
+ describe '#match(:expression)' do
114
+
115
+ context 'given a string literal' do
116
+
117
+ context 'delimited by double quotes' do
118
+ it 'parses as a regex match' do
119
+ matching(%{ "a string" }).as(:expression).
120
+ should result_in(Match[/a\ string/]).at(11)
121
+ end
122
+ end
123
+
124
+ context 'delimited by single quotes' do
125
+ it 'parses as a regex match' do
126
+ matching(%{ 'a string' }).as(:expression).
127
+ should result_in(Match[/a\ string/]).at(11)
128
+ end
129
+ end
130
+
131
+ context 'using "general delimited text" syntax' do
132
+
133
+ context 'with "(" and ")"' do
134
+ it 'parses as a regex match' do
135
+ matching(' %(a string) ').as(:expression).
136
+ should result_in(Match[/a\ string/]).at(12)
137
+ end
138
+ end
139
+
140
+ context 'with "{" and "}"' do
141
+ it 'parses as a regex match' do
142
+ matching(' %{a string} ').as(:expression).
143
+ should result_in(Match[/a\ string/]).at(12)
144
+ end
145
+ end
146
+
147
+ context 'with "[" and "]"' do
148
+ it 'parses as a regex match' do
149
+ matching(' %[a string] ').as(:expression).
150
+ should result_in(Match[/a\ string/]).at(12)
151
+ end
152
+ end
153
+
154
+ context 'with "<" and ">"' do
155
+ it 'parses as a regex match' do
156
+ matching(' %<a string> ').as(:expression).
157
+ should result_in(Match[/a\ string/]).at(12)
158
+ end
159
+ end
160
+
161
+ context 'with arbitrary delimiters' do
162
+ it 'parses as a regex match' do
163
+ matching(' %!a string! ').as(:expression).
164
+ should result_in(Match[/a\ string/]).at(12)
165
+ end
166
+ end
167
+ end
168
+
169
+ context 'delimited by backquotes' do
170
+ it 'parses as a word literal' do
171
+ matching(%{ `where` }).as(:expression).should result_in(
172
+ Token[Sequence[Match[/where/], Disallow[Match[/[[:alnum:]_]/]]]]
173
+ ).at(8)
174
+ end
175
+ end
176
+
177
+ context 'with special characters' do
178
+ it 'escapes the special characters' do
179
+ matching(%{ "[...]" }).as(:expression).
180
+ should result_in(Match[/\[\.\.\.\]/]).at(8)
181
+ end
182
+ end
183
+ end
184
+
185
+ context 'given a character class expression' do
186
+
187
+ context 'with a simple list of characters' do
188
+ it 'parses as a regex match' do
189
+ matching(' [abc123] ').as(:expression).
190
+ should result_in(Match[/[abc123]/]).at(9)
191
+ end
192
+ end
193
+
194
+ context 'with octal codes' do
195
+ it 'parses as a regex match' do
196
+ matching(' [\010\012\015] ').as(:expression).
197
+ should result_in(Match[/[\010\012\015]/]).at(15)
198
+ end
199
+ end
200
+
201
+ context 'with hex codes' do
202
+ it 'parses as a regex match' do
203
+ matching(' [\x08\x0A\x0D] ').as(:expression).
204
+ should result_in(Match[/[\x08\x0A\x0D]/]).at(15)
205
+ end
206
+ end
207
+
208
+ context 'with a range of characters' do
209
+ it 'parses as a regex match' do
210
+ matching(' [A-F] ').as(:expression).
211
+ should result_in(Match[/[A-F]/]).at(6)
212
+ end
213
+ end
214
+
215
+ context 'with a range of octal codes' do
216
+ it 'parses as a regex match' do
217
+ matching(' [\000-\177] ').as(:expression).
218
+ should result_in(Match[/[\000-\177]/]).at(12)
219
+ end
220
+ end
221
+
222
+ context 'with a range of hex codes' do
223
+ it 'parses as a regex match' do
224
+ matching(' [\x00-\x7F] ').as(:expression).
225
+ should result_in(Match[/[\x00-\x7F]/]).at(12)
226
+ end
227
+ end
228
+ end
229
+
230
+ context 'given a "."' do
231
+ it 'parses as Match[/./]' do
232
+ matching(' . ').as(:expression).should result_in(Match[/./]).at(2)
233
+ end
234
+ end
235
+
236
+ context 'given a lower-case word' do
237
+ it 'parses as an Apply' do
238
+ matching(' fooBar ').as(:expression).should result_in(Apply[:fooBar]).at(7)
239
+ end
240
+ end
241
+
242
+ context 'given a upper-case word' do
243
+ it 'parses it as an Apply' do
244
+ matching(' FooBar ').as(:expression).should result_in(Apply[:FooBar]).at(7)
245
+ end
246
+ end
247
+
248
+ context 'given the EOF keyword' do
249
+ it 'parses as Eof[]' do
250
+ matching(' EOF ').as(:expression).should result_in(Eof[]).at(4)
251
+ end
252
+ end
253
+
254
+ context 'given the E symbol' do
255
+ it 'parses as ESymbol[]' do
256
+ matching(' E ').as(:expression).should result_in(ESymbol[]).at(2)
257
+ end
258
+ end
259
+
260
+ context 'given "super"' do
261
+ it 'parses as Super[:pending]' do
262
+ matching(' super ').as(:expression).
263
+ should result_in(Super[:pending]).at(6)
264
+ end
265
+ end
266
+
267
+ context 'given an upper-case POSIX class name' do
268
+ it 'parses as a Match of a POSIX character class' do
269
+ for name in posix_names
270
+ matching(" #{name.upcase} ").as(:expression).
271
+ should result_in(Match[Regexp.new("[[:#{name}:]]")]).
272
+ at(name.length + 1)
273
+ end
274
+ end
275
+ end
276
+
277
+ context 'given the non-POSIX WORD class name' do
278
+ it 'parses as syntactic sugar for [[:alnum:]_]' do
279
+ matching(' WORD ').as(:expression).
280
+ should result_in(Match[/[[:alnum:]_]/]).at(5)
281
+ end
282
+ end
283
+
284
+ context 'given a word prefixed with "$"' do
285
+ it 'parses as a back-reference' do
286
+ matching(' $foobar ').as(:expression).
287
+ should result_in(BackReference[:foobar]).at(8)
288
+ end
289
+ end
290
+
291
+ context 'given a term prefixed with "&"' do
292
+ it 'parses as an assert' do
293
+ matching(' &foo ').as(:expression).
294
+ should result_in(Assert[Apply[:foo]]).at(5)
295
+ end
296
+ end
297
+
298
+ context 'given a term prefixed with "!"' do
299
+ it 'parses as a disallow' do
300
+ matching(' !foo ').as(:expression).
301
+ should result_in(Disallow[Apply[:foo]]).at(5)
302
+ end
303
+ end
304
+
305
+ context 'given a term prefixed with "~"' do
306
+ it 'parses as a skip' do
307
+ matching(' ~foo ').as(:expression).
308
+ should result_in(Skip[Apply[:foo]]).at(5)
309
+ end
310
+ end
311
+
312
+ context 'given a term prefixed with "@"' do
313
+ it 'parses as a token' do
314
+ matching(' @foo ').as(:expression).
315
+ should result_in(Token[Apply[:foo]]).at(5)
316
+ end
317
+ end
318
+
319
+ context 'given a term prefixed with "~@"' do
320
+ it 'parses as a skip of a token' do
321
+ matching(' ~@(foo bar) ').as(:expression).
322
+ should result_in(Skip[Token[Apply[:foo] & Apply[:bar]]])
323
+ end
324
+ end
325
+
326
+ context 'given a term prefixed with a name followed by ":"' do
327
+ it 'parses as a labeled expression' do
328
+ matching(' val:foo ').as(:expression).
329
+ should result_in(Label[:val, Apply[:foo]]).at(8)
330
+ end
331
+ end
332
+
333
+ context 'given a fail expression' do
334
+ it 'parses as a Fail of type :expr' do
335
+ matching(' fail("bad!") ').as(:expression).
336
+ should result_in(Fail[:expr, 'bad!']).at(13)
337
+ matching(' fail "bad!" ').as(:expression).
338
+ should result_in(Fail[:expr, 'bad!']).at(12)
339
+ end
340
+ end
341
+
342
+ context 'given a fail_rule expression' do
343
+ it 'parses as a Fail of type :rule' do
344
+ matching(' fail_rule("bad!") ').as(:expression).
345
+ should result_in(Fail[:rule, 'bad!']).at(18)
346
+ matching(' fail_rule "bad!" ').as(:expression).
347
+ should result_in(Fail[:rule, 'bad!']).at(17)
348
+ end
349
+ end
350
+
351
+ context 'given a fail_parse expression' do
352
+ it 'parses as a Fail of type :parse' do
353
+ matching(' fail_parse("bad!") ').as(:expression).
354
+ should result_in(Fail[:parse, 'bad!']).at(19)
355
+ matching(' fail_parse "bad!" ').as(:expression).
356
+ should result_in(Fail[:parse, 'bad!']).at(18)
357
+ end
358
+ end
359
+
360
+ context 'given a semantic result' do
361
+ it 'parses as a SemanticAction' do
362
+ matching(' ^{ 42 } ').as(:expression).
363
+ should result_in(SemanticAction['42']).at(8)
364
+ end
365
+ end
366
+
367
+ context 'given a positive semantic predicate' do
368
+ it 'parses as an Assert of a SemanticAction' do
369
+ matching(' &{ 42 } ').as(:expression).
370
+ should result_in(Assert[SemanticAction['42']]).at(8)
371
+ end
372
+ end
373
+
374
+ context 'given a negative semantic predicate' do
375
+ it 'parses as a Disallow of a SemanticAction' do
376
+ matching(' !{ 42 } ').as(:expression).
377
+ should result_in(Disallow[SemanticAction['42']]).at(8)
378
+ end
379
+ end
380
+
381
+ context 'given a semantic side-effect predicate' do
382
+ it 'parses as a Skip of a SemanticAction' do
383
+ matching(' ~{ 42 } ').as(:expression).
384
+ should result_in(Skip[SemanticAction['42']]).at(8)
385
+ end
386
+ end
387
+
388
+ context 'given an optional expression' do
389
+ it 'parses as a Repeat with optional bounds' do
390
+ matching(' expr? ').as(:expression).
391
+ should result_in(Repeat[Apply[:expr], 0, 1]).at(6)
392
+ end
393
+ end
394
+
395
+ context 'given a zero-or-more expression' do
396
+ it 'parses as a Repeat with zero-or-more bounds' do
397
+ matching(' expr* ').as(:expression).
398
+ should result_in(Repeat[Apply[:expr], 0, nil]).at(6)
399
+ end
400
+ end
401
+
402
+ context 'given a one-or-more expression' do
403
+ it 'parses as a Repeat with one-or-more bounds' do
404
+ matching(' expr+ ').as(:expression).
405
+ should result_in(Repeat[Apply[:expr], 1, nil]).at(6)
406
+ end
407
+ end
408
+
409
+ context 'given a generalized repeat expression' do
410
+ context 'with a single count' do
411
+ it 'parses as a Repeat with the count as both lower and upper bounds' do
412
+ matching(' expr 2 ').as(:expression).
413
+ should result_in(Repeat[Apply[:expr], 2, 2]).at(7)
414
+ end
415
+ end
416
+
417
+ context 'with a range' do
418
+ it 'parses as a Repeat with lower and upper bounds' do
419
+ matching(' expr 2..4 ').as(:expression).
420
+ should result_in(Repeat[Apply[:expr], 2, 4]).at(10)
421
+ end
422
+
423
+ context 'with no upper bound' do
424
+ it 'parses as a Repeat with no upper bound' do
425
+ matching(' expr 2.. ').as(:expression).
426
+ should result_in(Repeat[Apply[:expr], 2, nil]).at(9)
427
+ end
428
+ end
429
+ end
430
+
431
+ context 'with an "?" suffix' do
432
+ it 'parses as an optional Repeat' do
433
+ matching(' expr 3.. ? ').as(:expression).
434
+ should result_in(Repeat[Apply[:expr], 3, nil].optional).at(11)
435
+ end
436
+ end
437
+ end
438
+
439
+ context 'given a zero-or-more list expression' do
440
+ it 'parses as a ListParser with zero-or-more bounds' do
441
+ matching(' expr *, ";" ').as(:expression).
442
+ should result_in(ListParser[Apply[:expr], Match[/;/], 0, nil]).at(12)
443
+ end
444
+ end
445
+
446
+ context 'given a one-or-more list expression' do
447
+ it 'parses as a ListParser with one-or-more bounds' do
448
+ matching(' expr +, ";" ').as(:expression).
449
+ should result_in(ListParser[Apply[:expr], Match[/;/], 1, nil]).at(12)
450
+ end
451
+ end
452
+
453
+ context 'given a generalized list expression' do
454
+ context 'with a single count' do
455
+ it 'parses as a ListParser with the count as both lower and upper bounds' do
456
+ matching(' expr 2, ";" ').as(:expression).
457
+ should result_in(ListParser[Apply[:expr], Match[/;/], 2, 2]).at(12)
458
+ end
459
+ end
460
+
461
+ context 'with a range' do
462
+ it 'parses as a ListParser with lower and upper bounds' do
463
+ matching(' expr 2..4, ";" ').as(:expression).
464
+ should result_in(ListParser[Apply[:expr], Match[/;/], 2, 4]).at(15)
465
+ end
466
+
467
+ context 'with no upper bound' do
468
+ it 'parses as a Repeat with no upper bound' do
469
+ matching(' expr 2.., ";" ').as(:expression).
470
+ should result_in(ListParser[Apply[:expr], Match[/;/], 2, nil]).at(14)
471
+ end
472
+ end
473
+ end
474
+ end
475
+
476
+ context 'given a sequence expression' do
477
+ it 'parses as a Sequence' do
478
+ matching(' name "=" value ').as(:expression).
479
+ should result_in(Sequence[Apply[:name], Match[%r{=}], Apply[:value]]).at(15)
480
+ end
481
+
482
+ context 'with a nested sequence expression' do
483
+ it 'parses as a nested Sequence' do
484
+ matching(' a (b c) d ').as(:expression).
485
+ should result_in(Sequence[
486
+ Apply[:a],
487
+ Sequence[Apply[:b], Apply[:c]],
488
+ Apply[:d]
489
+ ]).at(10)
490
+ end
491
+ end
492
+
493
+ context 'with a semantic result' do
494
+ it 'parses as a Sequence with a SemanticAction' do
495
+ matching(' a b ^{|a,b| a + b } ').as(:expression).
496
+ should result_in(Sequence[
497
+ Apply[:a],
498
+ Apply[:b],
499
+ SemanticAction['|a,b| a + b']
500
+ ]).at(20)
501
+ end
502
+ end
503
+
504
+ context 'with a semantic side-effect' do
505
+ it 'parses as a Sequence with a Skip of a SemanticAction' do
506
+ matching(' a b ~{|a,b| a + b } ').as(:expression).
507
+ should result_in(Sequence[
508
+ Apply[:a],
509
+ Apply[:b],
510
+ Skip[SemanticAction['|a,b| a + b']]
511
+ ]).at(20)
512
+ end
513
+ end
514
+ end
515
+
516
+ context 'given an attributed expression' do
517
+
518
+ context 'with a single term and a semantic action' do
519
+ it 'parses as an AttributedSequence' do
520
+ matching(' digits {|_| _.to_i} ').as(:expression).
521
+ should result_in(AttributedSequence[
522
+ Apply[:digits], SemanticAction['|_| _.to_i']
523
+ ]).at(20)
524
+ end
525
+ end
526
+
527
+ context 'with a single term and a node action' do
528
+
529
+ context 'with just a class name' do
530
+ it 'parses as an AttributedSequence' do
531
+ matching(' expr <Expr> ').as(:expression).
532
+ should result_in(AttributedSequence[
533
+ Apply[:expr], NodeAction['Expr']
534
+ ]).at(12)
535
+ end
536
+ end
537
+
538
+ context 'with a class name and a method name' do
539
+ it 'parses as an AttributedSequence with the method attribute' do
540
+ matching(' expr <Expr.create> ').as(:expression).
541
+ should result_in(AttributedSequence[
542
+ Apply[:expr], NodeAction['Expr', {:method => 'create'}]
543
+ ]).at(19)
544
+ end
545
+ end
546
+
547
+ context 'with a class name and a node name' do
548
+ it 'parses as an AttributedSequence with the node name attribute' do
549
+ matching(' expr <Expr "EXPR"> ').as(:expression).
550
+ should result_in(AttributedSequence[
551
+ Apply[:expr],
552
+ NodeAction['Expr', {:node_attrs => {:name => 'EXPR'}}]
553
+ ]).at(19)
554
+ end
555
+ end
556
+
557
+ context 'with class, method and node names' do
558
+ it 'parses as an AttributedSequence with the method and node name attributes' do
559
+ matching(' expr <Expr.create "EXPR"> ').as(:expression).
560
+ should result_in(AttributedSequence[
561
+ Apply[:expr],
562
+ NodeAction['Expr', { :method => 'create',
563
+ :node_attrs => {:name => 'EXPR'} }]
564
+ ]).at(26)
565
+ end
566
+ end
567
+
568
+ context 'with no names' do
569
+ it 'parses as an AttributedSequence with a default NodeAction' do
570
+ matching(' expr <> ').as(:expression).
571
+ should result_in(AttributedSequence[
572
+ Apply[:expr], NodeAction['Rattler::Runtime::ParseNode']
573
+ ]).at(8)
574
+ end
575
+ end
576
+
577
+ context 'with just a node name' do
578
+ it 'parses as an AttributedSequence with a node name attribute' do
579
+ matching(' expr <"EXPR"> ').as(:expression).
580
+ should result_in(AttributedSequence[
581
+ Apply[:expr],
582
+ NodeAction['Rattler::Runtime::ParseNode',
583
+ {:node_attrs => {:name => 'EXPR'}}]
584
+ ]).at(14)
585
+ end
586
+ end
587
+ end
588
+
589
+ context 'with multiple terms and a semantic action' do
590
+ it 'parses as an AttributedSequence' do
591
+ matching(' name "=" value {|_| _.size }').as(:expression).
592
+ should result_in(AttributedSequence[
593
+ Apply[:name],
594
+ Match[%r{=}],
595
+ Apply[:value],
596
+ SemanticAction['|_| _.size']
597
+ ]).at(29)
598
+ end
599
+ end
600
+
601
+ context 'with multiple terms and a node action' do
602
+ it 'parses as an AttributedSequence' do
603
+ matching(' name "=" value <Assign>').as(:expression).
604
+ should result_in(AttributedSequence[
605
+ Apply[:name],
606
+ Match[%r{=}],
607
+ Apply[:value],
608
+ NodeAction['Assign']
609
+ ]).at(24)
610
+ end
611
+ end
612
+ end
613
+
614
+ context 'given a lone semantic action' do
615
+ it 'parses as a SemanticAction' do
616
+ matching(' { 42 } ').as(:expression).
617
+ should result_in(SemanticAction['42']).at(7)
618
+ end
619
+ end
620
+
621
+ context 'given a lone node action' do
622
+ it 'parses as a NodeAction' do
623
+ matching(' <Foo> ').as(:expression).
624
+ should result_in(NodeAction['Foo']).at(6)
625
+ end
626
+ end
627
+
628
+ context 'given a multiple-semantic-attirbuted expression' do
629
+ it 'parses as nested AttributedSequences' do
630
+ matching(' digits {|_| _.to_i } {|_| _ * 2 } ').as(:expression).
631
+ should result_in(AttributedSequence[
632
+ AttributedSequence[Apply[:digits], SemanticAction['|_| _.to_i']],
633
+ SemanticAction['|_| _ * 2']
634
+ ]).at(34)
635
+ end
636
+ end
637
+
638
+ context 'given a multiple-node-attirbuted expression' do
639
+ it 'parses as nested AttributedSequences' do
640
+ matching(' digits <Int> <Expr> ').as(:expression).
641
+ should result_in(AttributedSequence[
642
+ AttributedSequence[Apply[:digits], NodeAction['Int']],
643
+ NodeAction['Expr']
644
+ ]).at(20)
645
+ end
646
+ end
647
+
648
+ context 'given consecutive semantic-attributed expressions' do
649
+ it 'parses as nested AttributedSequences' do
650
+ matching(' digits {|_| _.to_i } foo {|_| _ * 2 } ').as(:expression).
651
+ should result_in(AttributedSequence[
652
+ AttributedSequence[
653
+ Apply[:digits], SemanticAction['|_| _.to_i']
654
+ ],
655
+ Apply[:foo],
656
+ SemanticAction['|_| _ * 2']
657
+ ]).at(38)
658
+ end
659
+ end
660
+
661
+ context 'given consecutive semantic-attributed expressions' do
662
+ it 'parses as nested AttributedSequences' do
663
+ matching(' digits <Int> foo <Foo> ').as(:expression).
664
+ should result_in(AttributedSequence[
665
+ AttributedSequence[
666
+ Apply[:digits], NodeAction['Int']
667
+ ],
668
+ Apply[:foo],
669
+ NodeAction['Foo']
670
+ ]).at(23)
671
+ end
672
+ end
673
+
674
+ context 'given an ordered choice expression' do
675
+ it 'parses as a Choice' do
676
+ matching(' string / number ').as(:expression).
677
+ should result_in(Choice[Apply[:string], Apply[:number]]).at(16)
678
+ end
679
+
680
+ context 'with sequences' do
681
+ it 'parses as a Choice of Sequences' do
682
+ matching(' foo bar / boo far ').as(:expression).
683
+ should result_in(Choice[
684
+ Sequence[Apply[:foo], Apply[:bar]],
685
+ Sequence[Apply[:boo], Apply[:far]]
686
+ ]).at(18)
687
+ end
688
+ end
689
+ end
690
+
691
+ it 'skips normal whitespace' do
692
+ matching(" \n\t foo").as(:expression).should result_in(Apply[:foo]).at(8)
693
+ end
694
+
695
+ it 'skips comments' do
696
+ matching("\n# a comment\n\t foo").as(:expression).
697
+ should result_in(Apply[:foo]).at(18)
698
+ end
699
+ end
700
+ end