plurimath-parslet 3.0.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 (148) hide show
  1. checksums.yaml +7 -0
  2. data/HISTORY.txt +284 -0
  3. data/LICENSE +23 -0
  4. data/README.adoc +454 -0
  5. data/Rakefile +71 -0
  6. data/lib/parslet/accelerator/application.rb +62 -0
  7. data/lib/parslet/accelerator/engine.rb +112 -0
  8. data/lib/parslet/accelerator.rb +162 -0
  9. data/lib/parslet/atoms/alternative.rb +53 -0
  10. data/lib/parslet/atoms/base.rb +157 -0
  11. data/lib/parslet/atoms/can_flatten.rb +137 -0
  12. data/lib/parslet/atoms/capture.rb +38 -0
  13. data/lib/parslet/atoms/context.rb +103 -0
  14. data/lib/parslet/atoms/dsl.rb +112 -0
  15. data/lib/parslet/atoms/dynamic.rb +32 -0
  16. data/lib/parslet/atoms/entity.rb +45 -0
  17. data/lib/parslet/atoms/ignored.rb +26 -0
  18. data/lib/parslet/atoms/infix.rb +115 -0
  19. data/lib/parslet/atoms/lookahead.rb +52 -0
  20. data/lib/parslet/atoms/named.rb +32 -0
  21. data/lib/parslet/atoms/re.rb +41 -0
  22. data/lib/parslet/atoms/repetition.rb +87 -0
  23. data/lib/parslet/atoms/scope.rb +26 -0
  24. data/lib/parslet/atoms/sequence.rb +48 -0
  25. data/lib/parslet/atoms/str.rb +42 -0
  26. data/lib/parslet/atoms/visitor.rb +89 -0
  27. data/lib/parslet/atoms.rb +34 -0
  28. data/lib/parslet/cause.rb +101 -0
  29. data/lib/parslet/context.rb +21 -0
  30. data/lib/parslet/convenience.rb +33 -0
  31. data/lib/parslet/error_reporter/contextual.rb +120 -0
  32. data/lib/parslet/error_reporter/deepest.rb +100 -0
  33. data/lib/parslet/error_reporter/tree.rb +63 -0
  34. data/lib/parslet/error_reporter.rb +8 -0
  35. data/lib/parslet/export.rb +163 -0
  36. data/lib/parslet/expression/treetop.rb +92 -0
  37. data/lib/parslet/expression.rb +51 -0
  38. data/lib/parslet/graphviz.rb +97 -0
  39. data/lib/parslet/parser.rb +68 -0
  40. data/lib/parslet/pattern/binding.rb +49 -0
  41. data/lib/parslet/pattern.rb +113 -0
  42. data/lib/parslet/position.rb +21 -0
  43. data/lib/parslet/rig/rspec.rb +52 -0
  44. data/lib/parslet/scope.rb +42 -0
  45. data/lib/parslet/slice.rb +105 -0
  46. data/lib/parslet/source/line_cache.rb +99 -0
  47. data/lib/parslet/source.rb +96 -0
  48. data/lib/parslet/transform.rb +265 -0
  49. data/lib/parslet/version.rb +5 -0
  50. data/lib/parslet.rb +314 -0
  51. data/plurimath-parslet.gemspec +42 -0
  52. data/spec/acceptance/infix_parser_spec.rb +145 -0
  53. data/spec/acceptance/mixing_parsers_spec.rb +74 -0
  54. data/spec/acceptance/regression_spec.rb +329 -0
  55. data/spec/acceptance/repetition_and_maybe_spec.rb +44 -0
  56. data/spec/acceptance/unconsumed_input_spec.rb +21 -0
  57. data/spec/examples/boolean_algebra_spec.rb +257 -0
  58. data/spec/examples/calc_spec.rb +278 -0
  59. data/spec/examples/capture_spec.rb +137 -0
  60. data/spec/examples/comments_spec.rb +186 -0
  61. data/spec/examples/deepest_errors_spec.rb +420 -0
  62. data/spec/examples/documentation_spec.rb +205 -0
  63. data/spec/examples/email_parser_spec.rb +275 -0
  64. data/spec/examples/empty_spec.rb +37 -0
  65. data/spec/examples/erb_spec.rb +482 -0
  66. data/spec/examples/ip_address_spec.rb +153 -0
  67. data/spec/examples/json_spec.rb +413 -0
  68. data/spec/examples/local_spec.rb +302 -0
  69. data/spec/examples/mathn_spec.rb +151 -0
  70. data/spec/examples/minilisp_spec.rb +492 -0
  71. data/spec/examples/modularity_spec.rb +340 -0
  72. data/spec/examples/nested_errors_spec.rb +322 -0
  73. data/spec/examples/optimized_erb_spec.rb +299 -0
  74. data/spec/examples/parens_spec.rb +239 -0
  75. data/spec/examples/prec_calc_spec.rb +525 -0
  76. data/spec/examples/readme_spec.rb +228 -0
  77. data/spec/examples/scopes_spec.rb +187 -0
  78. data/spec/examples/seasons_spec.rb +196 -0
  79. data/spec/examples/sentence_spec.rb +119 -0
  80. data/spec/examples/simple_xml_spec.rb +250 -0
  81. data/spec/examples/string_parser_spec.rb +407 -0
  82. data/spec/fixtures/examples/boolean_algebra.rb +62 -0
  83. data/spec/fixtures/examples/calc.rb +86 -0
  84. data/spec/fixtures/examples/capture.rb +36 -0
  85. data/spec/fixtures/examples/comments.rb +22 -0
  86. data/spec/fixtures/examples/deepest_errors.rb +99 -0
  87. data/spec/fixtures/examples/documentation.rb +32 -0
  88. data/spec/fixtures/examples/email_parser.rb +42 -0
  89. data/spec/fixtures/examples/empty.rb +10 -0
  90. data/spec/fixtures/examples/erb.rb +39 -0
  91. data/spec/fixtures/examples/ip_address.rb +103 -0
  92. data/spec/fixtures/examples/json.rb +107 -0
  93. data/spec/fixtures/examples/local.rb +60 -0
  94. data/spec/fixtures/examples/mathn.rb +47 -0
  95. data/spec/fixtures/examples/minilisp.rb +75 -0
  96. data/spec/fixtures/examples/modularity.rb +60 -0
  97. data/spec/fixtures/examples/nested_errors.rb +95 -0
  98. data/spec/fixtures/examples/optimized_erb.rb +105 -0
  99. data/spec/fixtures/examples/parens.rb +25 -0
  100. data/spec/fixtures/examples/prec_calc.rb +71 -0
  101. data/spec/fixtures/examples/readme.rb +59 -0
  102. data/spec/fixtures/examples/scopes.rb +43 -0
  103. data/spec/fixtures/examples/seasons.rb +40 -0
  104. data/spec/fixtures/examples/sentence.rb +18 -0
  105. data/spec/fixtures/examples/simple_xml.rb +51 -0
  106. data/spec/fixtures/examples/string_parser.rb +77 -0
  107. data/spec/parslet/atom_results_spec.rb +39 -0
  108. data/spec/parslet/atoms/alternative_spec.rb +26 -0
  109. data/spec/parslet/atoms/base_spec.rb +127 -0
  110. data/spec/parslet/atoms/capture_spec.rb +21 -0
  111. data/spec/parslet/atoms/combinations_spec.rb +5 -0
  112. data/spec/parslet/atoms/dsl_spec.rb +7 -0
  113. data/spec/parslet/atoms/entity_spec.rb +77 -0
  114. data/spec/parslet/atoms/ignored_spec.rb +15 -0
  115. data/spec/parslet/atoms/infix_spec.rb +5 -0
  116. data/spec/parslet/atoms/lookahead_spec.rb +22 -0
  117. data/spec/parslet/atoms/named_spec.rb +4 -0
  118. data/spec/parslet/atoms/re_spec.rb +14 -0
  119. data/spec/parslet/atoms/repetition_spec.rb +24 -0
  120. data/spec/parslet/atoms/scope_spec.rb +26 -0
  121. data/spec/parslet/atoms/sequence_spec.rb +28 -0
  122. data/spec/parslet/atoms/str_spec.rb +15 -0
  123. data/spec/parslet/atoms/visitor_spec.rb +101 -0
  124. data/spec/parslet/atoms_spec.rb +488 -0
  125. data/spec/parslet/convenience_spec.rb +54 -0
  126. data/spec/parslet/error_reporter/contextual_spec.rb +118 -0
  127. data/spec/parslet/error_reporter/deepest_spec.rb +82 -0
  128. data/spec/parslet/error_reporter/tree_spec.rb +7 -0
  129. data/spec/parslet/export_spec.rb +40 -0
  130. data/spec/parslet/expression/treetop_spec.rb +74 -0
  131. data/spec/parslet/minilisp.citrus +29 -0
  132. data/spec/parslet/minilisp.tt +29 -0
  133. data/spec/parslet/parser_spec.rb +36 -0
  134. data/spec/parslet/parslet_spec.rb +38 -0
  135. data/spec/parslet/pattern_spec.rb +272 -0
  136. data/spec/parslet/position_spec.rb +14 -0
  137. data/spec/parslet/rig/rspec_spec.rb +54 -0
  138. data/spec/parslet/scope_spec.rb +45 -0
  139. data/spec/parslet/slice_spec.rb +186 -0
  140. data/spec/parslet/source/line_cache_spec.rb +74 -0
  141. data/spec/parslet/source_spec.rb +210 -0
  142. data/spec/parslet/transform/context_spec.rb +56 -0
  143. data/spec/parslet/transform_spec.rb +183 -0
  144. data/spec/spec_helper.rb +74 -0
  145. data/spec/support/opal.rb +8 -0
  146. data/spec/support/opal.rb.erb +14 -0
  147. data/spec/support/parslet_matchers.rb +96 -0
  148. metadata +240 -0
@@ -0,0 +1,95 @@
1
+ require 'parslet'
2
+ require 'parslet/convenience'
3
+
4
+ # This example demonstrates tree error reporting in a real life example.
5
+ # The parser code has been contributed by John Mettraux.
6
+
7
+ module NestedErrorsExample
8
+ def self.prettify(str)
9
+ lines = []
10
+ lines << " "*3 + " "*4 + "." + " "*4 + "10" + " "*3 + "." + " "*4 + "20"
11
+ str.lines.each_with_index do |line, index|
12
+ lines << sprintf("%02d %s", index+1, line.chomp)
13
+ end
14
+ lines.join("\n")
15
+ end
16
+
17
+ class Parser < Parslet::Parser
18
+ # commons
19
+ rule(:space) { match('[ \t]').repeat(1) }
20
+ rule(:space?) { space.maybe }
21
+
22
+ rule(:newline) { match('[\r\n]') }
23
+
24
+ rule(:comment) { str('#') >> match('[^\r\n]').repeat }
25
+
26
+ rule(:line_separator) {
27
+ (space? >> ((comment.maybe >> newline) | str(';')) >> space?).repeat(1)
28
+ }
29
+
30
+ rule(:blank) { line_separator | space }
31
+ rule(:blank?) { blank.maybe }
32
+
33
+ rule(:identifier) { match('[a-zA-Z0-9_]').repeat(1) }
34
+
35
+ # res_statement
36
+ rule(:reference) {
37
+ (str('@').repeat(1,2) >> identifier).as(:reference)
38
+ }
39
+
40
+ rule(:res_action_or_link) {
41
+ str('.').as(:dot) >> (identifier >> str('?').maybe ).as(:name) >> str('()')
42
+ }
43
+
44
+ rule(:res_actions) {
45
+ (
46
+ reference
47
+ ).as(:resources) >>
48
+ (
49
+ res_action_or_link.as(:res_action)
50
+ ).repeat(0).as(:res_actions)
51
+ }
52
+
53
+ rule(:res_statement) {
54
+ res_actions >>
55
+ (str(':') >> identifier.as(:name)).maybe.as(:res_field)
56
+ }
57
+
58
+ # expression
59
+ rule(:expression) {
60
+ res_statement
61
+ }
62
+
63
+ # body
64
+ rule(:body) {
65
+ (line_separator >> (block | expression)).repeat(1).as(:body) >>
66
+ line_separator
67
+ }
68
+
69
+ # blocks
70
+ rule(:begin_block) {
71
+ (str('concurrent').as(:type) >> space).maybe.as(:pre) >>
72
+ str('begin').as(:begin) >>
73
+ body >>
74
+ str('end')
75
+ }
76
+
77
+ rule(:define_block) {
78
+ str('define').as(:define) >> space >>
79
+ identifier.as(:name) >> str('()') >>
80
+ body >>
81
+ str('end')
82
+ }
83
+
84
+ rule(:block) {
85
+ define_block | begin_block
86
+ }
87
+
88
+ # root
89
+ rule(:radix) {
90
+ line_separator.maybe >> block >> line_separator.maybe
91
+ }
92
+
93
+ root(:radix)
94
+ end
95
+ end
@@ -0,0 +1,105 @@
1
+ require 'parslet'
2
+
3
+ # This example shows how to optimize an ERB like parser using parslet.
4
+ # Please also look at the more naive 'erb.rb' for comparison.
5
+
6
+ module OptimizedErbExample
7
+ class ErbParser < Parslet::Parser
8
+ rule(:ruby) { (str('%>').absent? >> any).repeat.as(:ruby) }
9
+
10
+ rule(:expression) { (str('=') >> ruby).as(:expression) }
11
+ rule(:comment) { (str('#') >> ruby).as(:comment) }
12
+ rule(:code) { ruby.as(:code) }
13
+ rule(:erb) { expression | comment | code }
14
+
15
+ rule(:erb_with_tags) { str('<%') >> erb >> str('%>') }
16
+ rule(:text) { (str('<%').absent? >> any).repeat(1) }
17
+
18
+ rule(:text_with_ruby) { (text.as(:text) | erb_with_tags).repeat.as(:text) }
19
+ root(:text_with_ruby)
20
+ end
21
+
22
+ def self.parse_erb_content(content)
23
+ parser = ErbParser.new
24
+ parser.parse(content)
25
+ end
26
+
27
+ def self.parse_big_erb_file
28
+ content = <<~ERB_CONTENT
29
+ Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
30
+ tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
31
+ quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
32
+ consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse
33
+ cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non
34
+ proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
35
+ Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
36
+ tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
37
+ quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
38
+ consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse
39
+ cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non
40
+ proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
41
+ Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
42
+ tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
43
+ quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
44
+ consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse
45
+ cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non
46
+ proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
47
+ Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
48
+ tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
49
+ quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
50
+ consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse
51
+ cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non
52
+ proident, sunt in culpa qui officia deserunt mollit anim id est laborum.Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
53
+ tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
54
+ quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
55
+ consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse
56
+ cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non
57
+ proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
58
+ Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
59
+ tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
60
+ quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
61
+ consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse
62
+ cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non
63
+ proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
64
+
65
+ <%= erb tag %>
66
+
67
+ Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
68
+ tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
69
+ quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
70
+ consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse
71
+ cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non
72
+ proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
73
+ Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
74
+ tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
75
+ quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
76
+ consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse
77
+ cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non
78
+ proident, sunt in culpa qui officia deserunt mollit anim id est laborum.Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
79
+ tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
80
+ quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
81
+ consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse
82
+ cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non
83
+ proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
84
+ Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
85
+ tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
86
+ quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
87
+ consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse
88
+ cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non
89
+ proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
90
+ Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
91
+ tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
92
+ quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
93
+ consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse
94
+ cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non
95
+ proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
96
+ Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
97
+ tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
98
+ quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
99
+ consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse
100
+ cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non
101
+ proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
102
+ ERB_CONTENT
103
+ parse_erb_content(content)
104
+ end
105
+ end
@@ -0,0 +1,25 @@
1
+ # A small example that demonstrates the power of tree pattern matching. Also
2
+ # uses '.as(:name)' to construct a tree that can reliably be matched
3
+ # afterwards.
4
+
5
+ $:.unshift File.dirname(__FILE__) + "/../lib"
6
+
7
+ require 'pp'
8
+ require 'parslet'
9
+
10
+ module LISP # as in 'lots of insipid and stupid parenthesis'
11
+ class Parser < Parslet::Parser
12
+ rule(:balanced) {
13
+ str('(').as(:l) >> balanced.maybe.as(:m) >> str(')').as(:r)
14
+ }
15
+
16
+ root(:balanced)
17
+ end
18
+
19
+ class Transform < Parslet::Transform
20
+ rule(:l => '(', :m => simple(:x), :r => ')') {
21
+ # innermost :m will contain nil
22
+ x.nil? ? 1 : x+1
23
+ }
24
+ end
25
+ end
@@ -0,0 +1,71 @@
1
+
2
+ # A demonstration of the new precedence climbing infix expression parser.
3
+
4
+ $:.unshift File.dirname(__FILE__) + "/../lib"
5
+
6
+ require 'pp'
7
+ require 'rspec'
8
+ require 'parslet'
9
+ require 'parslet/rig/rspec'
10
+ require 'parslet/convenience'
11
+
12
+ class InfixExpressionParser < Parslet::Parser
13
+ root :variable_assignment_list
14
+
15
+ rule(:space) { match[' '] }
16
+
17
+ def cts atom
18
+ atom >> space.repeat
19
+ end
20
+ def infix *args
21
+ Infix.new(*args)
22
+ end
23
+
24
+ # This is the heart of the infix expression parser: real simple definitions
25
+ # for all the pieces we need.
26
+ rule(:mul_op) { cts match['*/'] }
27
+ rule(:add_op) { cts match['+-'] }
28
+ rule(:digit) { match['0-9'] }
29
+ rule(:integer) { cts digit.repeat(1).as(:int) }
30
+
31
+ rule(:expression) { infix_expression(integer,
32
+ [mul_op, 2, :left],
33
+ [add_op, 1, :right]) }
34
+
35
+ # And now adding variable assignments to that, just to a) demonstrate this
36
+ # embedded in a bigger parser, and b) make the example interesting.
37
+ rule(:variable_assignment_list) {
38
+ variable_assignment.repeat(1) }
39
+ rule(:variable_assignment) {
40
+ identifier.as(:ident) >> equal_sign >> expression.as(:exp) >> eol }
41
+ rule(:identifier) {
42
+ cts (match['a-z'] >> match['a-zA-Z0-9'].repeat) }
43
+ rule(:equal_sign) {
44
+ cts str('=') }
45
+ rule(:eol) {
46
+ cts(str("\n")) | any.absent? }
47
+ end
48
+
49
+ class InfixInterpreter < Parslet::Transform
50
+ rule(int: simple(:int)) { Integer(int) }
51
+ rule(ident: simple(:ident), exp: simple(:result)) { |d|
52
+ d[:doc][d[:ident].to_s.strip.to_sym] = d[:result] }
53
+
54
+ rule(l: simple(:l), o: /^\*/, r: simple(:r)) { l * r }
55
+ rule(l: simple(:l), o: /^\+/, r: simple(:r)) { l + r }
56
+ end
57
+
58
+ input = <<ASSIGNMENTS
59
+ a = 1
60
+ b = 2
61
+ c = 3 * 25
62
+ d = 100 + 3*4
63
+ ASSIGNMENTS
64
+
65
+ puts input
66
+
67
+ int_tree = InfixExpressionParser.new.parse_with_debug(input)
68
+ bindings = {}
69
+ result = InfixInterpreter.new.apply(int_tree, doc: bindings)
70
+
71
+ pp bindings
@@ -0,0 +1,59 @@
1
+ require 'parslet'
2
+
3
+ module ReadmeExample
4
+ include Parslet
5
+
6
+ # Basic parslet examples from the readme
7
+ class SimpleStringParser < Parslet::Parser
8
+ root :simple_string
9
+
10
+ rule(:simple_string) { quote >> content >> quote }
11
+ rule(:quote) { str('"') }
12
+ rule(:content) { (quote.absent? >> any).repeat }
13
+ end
14
+
15
+ class SmalltalkParser < Parslet::Parser
16
+ root :smalltalk
17
+
18
+ rule(:smalltalk) { statements }
19
+ rule(:statements) {
20
+ # Simple implementation for demo purposes
21
+ str('smalltalk')
22
+ }
23
+ end
24
+
25
+ # Demonstrate basic parslet functionality
26
+ def self.demo_basic_parsing
27
+ # String parsing
28
+ foo_parser = Parslet.str('foo')
29
+ foo_result = foo_parser.parse('foo')
30
+
31
+ # Character set matching
32
+ abc_parser = Parslet.match('[abc]')
33
+ a_result = abc_parser.parse('a')
34
+ b_result = abc_parser.parse('b')
35
+ c_result = abc_parser.parse('c')
36
+
37
+ # Annotation
38
+ annotated_parser = Parslet.str('foo').as(:important_bit)
39
+ annotated_result = annotated_parser.parse('foo')
40
+
41
+ {
42
+ foo: foo_result,
43
+ a: a_result,
44
+ b: b_result,
45
+ c: c_result,
46
+ annotated: annotated_result
47
+ }
48
+ end
49
+
50
+ def self.demo_simple_string
51
+ quote = Parslet.str('"')
52
+ simple_string = quote >> (quote.absent? >> Parslet.any).repeat >> quote
53
+ simple_string.parse('"Simple Simple Simple"')
54
+ end
55
+
56
+ def self.demo_smalltalk
57
+ SmalltalkParser.new.parse('smalltalk')
58
+ end
59
+ end
@@ -0,0 +1,43 @@
1
+ require 'parslet'
2
+
3
+ # Demonstrates scope handling in parslet - how captures can be scoped
4
+ # and how dynamic parsing can access captured values.
5
+
6
+ module ScopesExample
7
+ def self.create_parser
8
+ Parslet.str('a').capture(:a) >> Parslet.scope { Parslet.str('b').capture(:a) } >>
9
+ Parslet.dynamic { |s,c| Parslet.str(c.captures[:a]) }
10
+ end
11
+
12
+ def self.parse_scoped_input(input = 'aba')
13
+ parser = create_parser
14
+ parser.parse(input)
15
+ end
16
+
17
+ def self.demonstrate_scope_success
18
+ parse_scoped_input('aba')
19
+ end
20
+
21
+ def self.demonstrate_scope_failure
22
+ begin
23
+ parse_scoped_input('abc')
24
+ rescue Parslet::ParseFailed => e
25
+ e
26
+ end
27
+ end
28
+
29
+ # Simpler nested scope example that actually works
30
+ def self.create_nested_scope_parser
31
+ Parslet.str('x').capture(:outer) >>
32
+ Parslet.scope {
33
+ Parslet.str('y').capture(:outer) >>
34
+ Parslet.dynamic { |s,c| Parslet.str(c.captures[:outer]) }
35
+ } >>
36
+ Parslet.dynamic { |s,c| Parslet.str(c.captures[:outer]) }
37
+ end
38
+
39
+ def self.parse_nested_scoped_input(input = 'xyyx')
40
+ parser = create_nested_scope_parser
41
+ parser.parse(input)
42
+ end
43
+ end
@@ -0,0 +1,40 @@
1
+ require 'parslet'
2
+
3
+ module SeasonsExample
4
+ class Spring < Parslet::Transform
5
+ rule(:stem => sequence(:branches)) {
6
+ {:stem => (branches + [{:branch => :leaf}])}
7
+ }
8
+ end
9
+
10
+ class Summer < Parslet::Transform
11
+ rule(:stem => subtree(:branches)) {
12
+ new_branches = branches.map { |b| {:branch => [:leaf, :flower]} }
13
+ {:stem => new_branches}
14
+ }
15
+ end
16
+
17
+ class Fall < Parslet::Transform
18
+ rule(:branch => sequence(:x)) {
19
+ x.each { |e| puts "Fruit!" if e==:flower }
20
+ x.each { |e| puts "Falling Leaves!" if e==:leaf }
21
+ {:branch => []}
22
+ }
23
+ end
24
+
25
+ class Winter < Parslet::Transform
26
+ rule(:stem => subtree(:x)) {
27
+ {:stem => []}
28
+ }
29
+ end
30
+
31
+ def self.do_seasons(tree)
32
+ [Spring, Summer, Fall, Winter].each do |season|
33
+ p "And when #{season} comes"
34
+ tree = season.new.apply(tree)
35
+ pp tree
36
+ puts
37
+ end
38
+ tree
39
+ end
40
+ end
@@ -0,0 +1,18 @@
1
+ # encoding: UTF-8
2
+
3
+ # A small example contributed by John Mettraux (jmettraux) that demonstrates
4
+ # working with Unicode. This only works on Ruby 1.9.
5
+
6
+ require 'parslet'
7
+
8
+ module SentenceExample
9
+ class MyParser < Parslet::Parser
10
+ rule(:sentence) { (match('[^。]').repeat(1) >> str("。")).as(:sentence) }
11
+ rule(:sentences) { sentence.repeat }
12
+ root(:sentences)
13
+ end
14
+
15
+ class Transformer < Parslet::Transform
16
+ rule(:sentence => simple(:sen)) { sen.to_s }
17
+ end
18
+ end
@@ -0,0 +1,51 @@
1
+ # A simple xml parser. It is simple in the respect as that it doesn't address
2
+ # any of the complexities of XML. This is ruby 1.9.
3
+
4
+ $:.unshift File.dirname(__FILE__) + "/../lib"
5
+
6
+ require 'pp'
7
+ require 'parslet'
8
+
9
+ class XML < Parslet::Parser
10
+ root :document
11
+
12
+ rule(:document) {
13
+ tag(close: false).as(:o) >> document.as(:i) >> tag(close: true).as(:c) |
14
+ text
15
+ }
16
+
17
+ # Perhaps we could have some syntax sugar to make this more easy?
18
+ #
19
+ def tag(opts={})
20
+ close = opts[:close] || false
21
+
22
+ parslet = str('<')
23
+ parslet = parslet >> str('/') if close
24
+ parslet = parslet >> (str('>').absent? >> match("[a-zA-Z]")).repeat(1).as(:name)
25
+ parslet = parslet >> str('>')
26
+
27
+ parslet
28
+ end
29
+
30
+ rule(:text) {
31
+ match('[^<>]').repeat(0)
32
+ }
33
+ end
34
+
35
+ def check(xml)
36
+ r = XML.new.parse(xml)
37
+
38
+ # We'll validate the tree by reducing valid pairs of tags into simply the
39
+ # string "verified". If the transformation ends on a string, then the
40
+ # document was 'valid'.
41
+ #
42
+ t = Parslet::Transform.new do
43
+ rule(
44
+ o: {name: simple(:tag)},
45
+ c: {name: simple(:tag)},
46
+ i: simple(:t)
47
+ ) { 'verified' }
48
+ end
49
+
50
+ t.apply(r)
51
+ end
@@ -0,0 +1,77 @@
1
+ # A more complex parser that illustrates how a compiler might be constructed.
2
+ # The parser recognizes strings and integer literals and constructs almost a
3
+ # useful AST from the file contents.
4
+
5
+ require 'pp'
6
+
7
+ $:.unshift File.dirname(__FILE__) + "/../lib"
8
+ require 'parslet'
9
+
10
+ include Parslet
11
+
12
+ class LiteralsParser < Parslet::Parser
13
+ rule :space do
14
+ (match '[ ]').repeat(1)
15
+ end
16
+
17
+ rule :literals do
18
+ (literal >> eol).repeat
19
+ end
20
+
21
+ rule :literal do
22
+ (integer | string).as(:literal) >> space.maybe
23
+ end
24
+
25
+ rule :string do
26
+ str('"') >>
27
+ (
28
+ (str('\\') >> any) |
29
+ (str('"').absent? >> any)
30
+ ).repeat.as(:string) >>
31
+ str('"')
32
+ end
33
+
34
+ rule :integer do
35
+ match('[0-9]').repeat(1).as(:integer)
36
+ end
37
+
38
+ rule :eol do
39
+ line_end.repeat(1)
40
+ end
41
+
42
+ rule :line_end do
43
+ crlf >> space.maybe
44
+ end
45
+
46
+ rule :crlf do
47
+ match('[\r\n]').repeat(1)
48
+ end
49
+
50
+ root :literals
51
+ end
52
+
53
+ input_name = File.join(File.dirname(__FILE__), 'simple.lit')
54
+ file = File.read(input_name)
55
+
56
+ parsetree = LiteralsParser.new.parse(file)
57
+
58
+ class Lit < Struct.new(:text)
59
+ def to_s
60
+ text.inspect
61
+ end
62
+ end
63
+ class StringLit < Lit
64
+ end
65
+ class IntLit < Lit
66
+ def to_s
67
+ text
68
+ end
69
+ end
70
+
71
+ transform = Parslet::Transform.new do
72
+ rule(:literal => {:integer => simple(:x)}) { IntLit.new(x) }
73
+ rule(:literal => {:string => simple(:s)}) { StringLit.new(s) }
74
+ end
75
+
76
+ ast = transform.apply(parsetree)
77
+ pp ast
@@ -0,0 +1,39 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'Result of a Parslet#parse' do
4
+ include Parslet; extend Parslet
5
+
6
+ describe 'regression' do
7
+ [
8
+ # Behaviour with maybe-nil
9
+ [str('foo').maybe >> str('bar'), 'bar', 'bar'],
10
+ [str('bar') >> str('foo').maybe, 'bar', 'bar'],
11
+
12
+ # These might be hard to understand; look at the result of
13
+ # str.maybe >> str
14
+ # and
15
+ # str.maybe >> str first.
16
+ [(str('f').maybe >> str('b')).repeat, 'bb', 'bb'],
17
+ [(str('b') >> str('f').maybe).repeat, 'bb', 'bb'],
18
+
19
+ [str('a').as(:a) >> (str('b') >> str('c').as(:a)).repeat, 'abc',
20
+ [{ a: 'a' }, { a: 'c' }]],
21
+
22
+ [str('a').as(:a).repeat >> str('b').as(:b).repeat, 'ab', [{ a: 'a' }, { b: 'b' }]],
23
+
24
+ # Repetition behaviour / named vs. unnamed
25
+ [str('f').repeat, '', ''],
26
+ [str('f').repeat.as(:f), '', { f: [] }],
27
+
28
+ # Maybe behaviour / named vs. unnamed
29
+ [str('f').maybe, '', ''],
30
+ [str('f').maybe.as(:f), '', { f: nil }],
31
+ ].each do |parslet, input, result|
32
+ context parslet.inspect.to_s do
33
+ it "parses \"#{input}\" into \"#{result}\"" do
34
+ expect(parslet.parse(input)).to eq(result)
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,26 @@
1
+ require 'spec_helper'
2
+
3
+ describe Parslet::Atoms::Alternative do
4
+ include Parslet
5
+
6
+ describe '| shortcut' do
7
+ let(:alternative) { str('a') | str('b') }
8
+
9
+ context "when chained with different atoms" do
10
+ before(:each) {
11
+ # Chain something else to the alternative parslet. If it modifies the
12
+ # parslet atom in place, we'll notice:
13
+
14
+ alternative | str('d')
15
+ }
16
+ let!(:chained) { alternative | str('c') }
17
+
18
+
19
+ it "is side-effect free" do
20
+ chained.should parse('c')
21
+ chained.should parse('a')
22
+ chained.should_not parse('d')
23
+ end
24
+ end
25
+ end
26
+ end