parslet 1.5.0 → 1.6.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/HISTORY.txt +22 -1
- data/LICENSE +1 -2
- data/README +12 -9
- data/example/big.erb +73 -0
- data/example/email_parser.rb +5 -3
- data/example/optimized_erb.rb +42 -0
- data/example/output/optimized_erb.out +1 -0
- data/example/output/prec_calc.out +5 -0
- data/example/prec_calc.rb +71 -0
- data/lib/parslet.rb +33 -1
- data/lib/parslet/accelerator.rb +161 -0
- data/lib/parslet/accelerator/application.rb +62 -0
- data/lib/parslet/accelerator/engine.rb +112 -0
- data/lib/parslet/atoms.rb +1 -0
- data/lib/parslet/atoms/infix.rb +121 -0
- data/lib/parslet/atoms/re.rb +1 -1
- data/lib/parslet/atoms/repetition.rb +6 -1
- data/lib/parslet/atoms/str.rb +2 -1
- data/lib/parslet/{transform/context.rb → context.rb} +2 -1
- data/lib/parslet/graphviz.rb +97 -0
- data/lib/parslet/pattern.rb +1 -1
- data/lib/parslet/rig/rspec.rb +10 -2
- data/lib/parslet/source.rb +41 -16
- data/lib/parslet/source/line_cache.rb +11 -10
- data/lib/parslet/transform.rb +3 -3
- metadata +21 -143
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: a03d43eaaf0b663727e308d79395c84019d63d0b
|
4
|
+
data.tar.gz: 2d39731312fe20e6640077b1cfb3b4a9c4ff34fd
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 5aacc9ac06b08230c6301ededf169dba75ea056c082531d62120a380a536df66e4bd310fd8ae609578cd0da8c74989c4c2d71d50ffa4acd394074e36166fd305
|
7
|
+
data.tar.gz: 8b7151423f165f532c24b6f5a3b3a0ce88e990c95749a7b5c918451ad5d2ed59368b528f66f5a39312495b7d33bb3ff1e3da69aadcc135a968881de0b84754ce
|
data/HISTORY.txt
CHANGED
@@ -2,8 +2,29 @@
|
|
2
2
|
|
3
3
|
- prsnt? and absnt? are now finally banned into oblivion. Wasting vocals for
|
4
4
|
the win.
|
5
|
+
|
6
|
+
= 1.6 / ??
|
7
|
+
|
8
|
+
+ EXPERIMENTAL: Parslet accelerators permit replacing parts of your parser
|
9
|
+
with optimized atoms using pattern matching. Look at
|
10
|
+
examples/optimized_erb.rb or the introduction to the feature in
|
11
|
+
qed/accelerators.md.
|
12
|
+
|
13
|
+
+ infix_expression permits to declare an infix expression parser (think
|
14
|
+
calculator) directly. This will solve many of the problems we have
|
15
|
+
more elegantly.
|
16
|
+
|
17
|
+
+ Rspec 3 syntax, though hideous, should now work.
|
18
|
+
|
19
|
+
- Drops 1.8.7 compatibility.
|
20
|
+
|
21
|
+
! A performance anomaly when parsing multibyte characters has been detected
|
22
|
+
and fixed with the help of Zach Moazeni (@zmoazeni).
|
23
|
+
|
24
|
+
! A few small bug fixes and optimisations have been introduced. API should
|
25
|
+
remain unchanged.
|
5
26
|
|
6
|
-
= 1.5 /
|
27
|
+
= 1.5 / 27Dec2012
|
7
28
|
|
8
29
|
+ Handles unconsumed input at end of parse completely differently. Instead
|
9
30
|
of generating a toplevel error, it now raises an error in every branch
|
data/LICENSE
CHANGED
data/README
CHANGED
@@ -51,20 +51,23 @@ SYNOPSIS
|
|
51
51
|
# and then
|
52
52
|
Smalltalk.new.parse('smalltalk')
|
53
53
|
|
54
|
-
|
54
|
+
FEATURES
|
55
55
|
|
56
|
-
|
57
|
-
|
58
|
-
|
56
|
+
* Tools for every part of the parser chain
|
57
|
+
* Transformers generate Abstract Syntax Trees
|
58
|
+
* Accelerators transform parsers, making them quite a bit faster
|
59
|
+
* Pluggable error reporters
|
60
|
+
* Graphviz export for your parser
|
61
|
+
* Rspec testing support rig
|
62
|
+
* Simply Ruby, composable and hackable
|
59
63
|
|
60
|
-
|
61
|
-
version.
|
64
|
+
COMPATIBILITY
|
62
65
|
|
63
|
-
|
64
|
-
|
66
|
+
This library is intended to work with Ruby variants >= 1.9. I've tested it on
|
67
|
+
MRI 1.9, rbx-head, jruby. Please report as a bug if you encounter issues.
|
65
68
|
|
66
69
|
STATUS
|
67
70
|
|
68
71
|
Production worthy.
|
69
72
|
|
70
|
-
(c) 2010
|
73
|
+
(c) 2010-2014 Kaspar Schiess
|
data/example/big.erb
ADDED
@@ -0,0 +1,73 @@
|
|
1
|
+
Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
|
2
|
+
tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
|
3
|
+
quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
|
4
|
+
consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse
|
5
|
+
cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non
|
6
|
+
proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
|
7
|
+
Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
|
8
|
+
tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
|
9
|
+
quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
|
10
|
+
consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse
|
11
|
+
cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non
|
12
|
+
proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
|
13
|
+
Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
|
14
|
+
tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
|
15
|
+
quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
|
16
|
+
consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse
|
17
|
+
cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non
|
18
|
+
proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
|
19
|
+
Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
|
20
|
+
tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
|
21
|
+
quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
|
22
|
+
consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse
|
23
|
+
cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non
|
24
|
+
proident, sunt in culpa qui officia deserunt mollit anim id est laborum.Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
|
25
|
+
tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
|
26
|
+
quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
|
27
|
+
consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse
|
28
|
+
cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non
|
29
|
+
proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
|
30
|
+
Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
|
31
|
+
tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
|
32
|
+
quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
|
33
|
+
consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse
|
34
|
+
cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non
|
35
|
+
proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
|
36
|
+
|
37
|
+
<%= erb tag %>
|
38
|
+
|
39
|
+
Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
|
40
|
+
tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
|
41
|
+
quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
|
42
|
+
consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse
|
43
|
+
cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non
|
44
|
+
proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
|
45
|
+
Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
|
46
|
+
tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
|
47
|
+
quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
|
48
|
+
consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse
|
49
|
+
cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non
|
50
|
+
proident, sunt in culpa qui officia deserunt mollit anim id est laborum.Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
|
51
|
+
tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
|
52
|
+
quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
|
53
|
+
consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse
|
54
|
+
cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non
|
55
|
+
proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
|
56
|
+
Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
|
57
|
+
tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
|
58
|
+
quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
|
59
|
+
consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse
|
60
|
+
cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non
|
61
|
+
proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
|
62
|
+
Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
|
63
|
+
tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
|
64
|
+
quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
|
65
|
+
consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse
|
66
|
+
cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non
|
67
|
+
proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
|
68
|
+
Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
|
69
|
+
tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
|
70
|
+
quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
|
71
|
+
consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse
|
72
|
+
cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non
|
73
|
+
proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
|
data/example/email_parser.rb
CHANGED
@@ -44,9 +44,11 @@ end
|
|
44
44
|
parser = EmailParser.new
|
45
45
|
sanitizer = EmailSanitizer.new
|
46
46
|
|
47
|
-
|
47
|
+
input = ARGV[0] || begin
|
48
|
+
default = "a.b.c.d@gmail.com"
|
48
49
|
STDERR.puts "usage: #{$0} \"EMAIL_ADDR\""
|
49
|
-
STDOUT.puts "since you haven't specified any EMAIL_ADDR, for testing purposes we're using
|
50
|
+
STDOUT.puts "since you haven't specified any EMAIL_ADDR, for testing purposes we're using #{default}"
|
51
|
+
default
|
50
52
|
end
|
51
53
|
|
52
|
-
p sanitizer.apply(parser.parse_with_debug(
|
54
|
+
p sanitizer.apply(parser.parse_with_debug(input))
|
@@ -0,0 +1,42 @@
|
|
1
|
+
# Please also look at the more naive 'erb.rb'. This shows how to optimize an
|
2
|
+
# ERB like parser using parslet.
|
3
|
+
|
4
|
+
$:.unshift File.join(File.dirname(__FILE__), "/../lib")
|
5
|
+
|
6
|
+
require 'parslet'
|
7
|
+
require './qed/applique/gobbleup'
|
8
|
+
require 'parslet/accelerator'
|
9
|
+
|
10
|
+
class ErbParser < Parslet::Parser
|
11
|
+
rule(:ruby) { (str('%>').absent? >> any).repeat.as(:ruby) }
|
12
|
+
|
13
|
+
rule(:expression) { (str('=') >> ruby).as(:expression) }
|
14
|
+
rule(:comment) { (str('#') >> ruby).as(:comment) }
|
15
|
+
rule(:code) { ruby.as(:code) }
|
16
|
+
rule(:erb) { expression | comment | code }
|
17
|
+
|
18
|
+
rule(:erb_with_tags) { str('<%') >> erb >> str('%>') }
|
19
|
+
rule(:text) { (str('<%').absent? >> any).repeat(1) }
|
20
|
+
|
21
|
+
rule(:text_with_ruby) { (text.as(:text) | erb_with_tags).repeat.as(:text) }
|
22
|
+
root(:text_with_ruby)
|
23
|
+
end
|
24
|
+
|
25
|
+
parser = ErbParser.new
|
26
|
+
|
27
|
+
A = Parslet::Accelerator
|
28
|
+
optimized = A.apply(parser,
|
29
|
+
A.rule((A.str(:x).absent? >> A.any).repeat(1)) { GobbleUp.new(x, 1) },
|
30
|
+
A.rule((A.str(:x).absent? >> A.any).repeat(0)) { GobbleUp.new(x, 0) })
|
31
|
+
|
32
|
+
input = File.read(File.dirname(__FILE__) + "/big.erb")
|
33
|
+
|
34
|
+
# Remove the comment marks here to see what difference the optimisation makes.
|
35
|
+
# Commented out for the acceptance tests to run.
|
36
|
+
#
|
37
|
+
# require 'benchmark'
|
38
|
+
# Benchmark.bm(7) do |bm|
|
39
|
+
# bm.report('original') { parser.parse(input) }
|
40
|
+
# bm.report('gobble') { optimized.parse(input) }
|
41
|
+
# end
|
42
|
+
p optimized.parse(input)
|
@@ -0,0 +1 @@
|
|
1
|
+
{:text=>[{:text=>"Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod\ntempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,\nquis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo\nconsequat. Duis aute irure dolor in reprehenderit in voluptate velit esse\ncillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non\nproident, sunt in culpa qui officia deserunt mollit anim id est laborum.\nLorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod\ntempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,\nquis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo\nconsequat. Duis aute irure dolor in reprehenderit in voluptate velit esse\ncillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non\nproident, sunt in culpa qui officia deserunt mollit anim id est laborum.\nLorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod\ntempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,\nquis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo\nconsequat. Duis aute irure dolor in reprehenderit in voluptate velit esse\ncillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non\nproident, sunt in culpa qui officia deserunt mollit anim id est laborum.\nLorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod\ntempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,\nquis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo\nconsequat. Duis aute irure dolor in reprehenderit in voluptate velit esse\ncillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non\nproident, sunt in culpa qui officia deserunt mollit anim id est laborum.Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod\ntempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,\nquis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo\nconsequat. Duis aute irure dolor in reprehenderit in voluptate velit esse\ncillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non\nproident, sunt in culpa qui officia deserunt mollit anim id est laborum.\nLorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod\ntempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,\nquis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo\nconsequat. Duis aute irure dolor in reprehenderit in voluptate velit esse\ncillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non\nproident, sunt in culpa qui officia deserunt mollit anim id est laborum.\n\n"@0}, {:expression=>{:ruby=>" erb tag "@2685}}, {:text=>"\n\nLorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod\ntempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,\nquis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo\nconsequat. Duis aute irure dolor in reprehenderit in voluptate velit esse\ncillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non\nproident, sunt in culpa qui officia deserunt mollit anim id est laborum.\nLorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod\ntempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,\nquis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo\nconsequat. Duis aute irure dolor in reprehenderit in voluptate velit esse\ncillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non\nproident, sunt in culpa qui officia deserunt mollit anim id est laborum.Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod\ntempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,\nquis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo\nconsequat. Duis aute irure dolor in reprehenderit in voluptate velit esse\ncillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non\nproident, sunt in culpa qui officia deserunt mollit anim id est laborum.\nLorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod\ntempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,\nquis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo\nconsequat. Duis aute irure dolor in reprehenderit in voluptate velit esse\ncillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non\nproident, sunt in culpa qui officia deserunt mollit anim id est laborum.\nLorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod\ntempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,\nquis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo\nconsequat. Duis aute irure dolor in reprehenderit in voluptate velit esse\ncillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non\nproident, sunt in culpa qui officia deserunt mollit anim id est laborum.\nLorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod\ntempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,\nquis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo\nconsequat. Duis aute irure dolor in reprehenderit in voluptate velit esse\ncillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non\nproident, sunt in culpa qui officia deserunt mollit anim id est laborum.\n"@2696}]}
|
@@ -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
|
data/lib/parslet.rb
CHANGED
@@ -199,6 +199,38 @@ module Parslet
|
|
199
199
|
Parslet::Atoms::Dynamic.new(block)
|
200
200
|
end
|
201
201
|
module_function :dynamic
|
202
|
+
|
203
|
+
# Returns a parslet atom that parses infix expressions. Operations are
|
204
|
+
# specified as a list of <atom, precedence, associativity> tuples, where
|
205
|
+
# atom is simply the parslet atom that matches an operator, precedence is
|
206
|
+
# a number and associativity is either :left or :right.
|
207
|
+
#
|
208
|
+
# Higher precedence indicates that the operation should bind tighter than
|
209
|
+
# other operations with lower precedence. In common algebra, '+' has
|
210
|
+
# lower precedence than '*'. So you would have a precedence of 1 for '+' and
|
211
|
+
# a precedence of 2 for '*'. Only the order relation between these two
|
212
|
+
# counts, so any number would work.
|
213
|
+
#
|
214
|
+
# Associativity is what decides what interpretation to take for strings that
|
215
|
+
# are ambiguous like '1 + 2 + 3'. If '+' is specified as left associative,
|
216
|
+
# the expression would be interpreted as '(1 + 2) + 3'. If right
|
217
|
+
# associativity is chosen, it would be interpreted as '1 + (2 + 3)'. Note
|
218
|
+
# that the hash trees output reflect that choice as well.
|
219
|
+
#
|
220
|
+
# Example:
|
221
|
+
# infix_expression(integer, [add_op, 1, :left])
|
222
|
+
# # would parse things like '1 + 2'
|
223
|
+
#
|
224
|
+
# @param element [Parslet::Atoms::Base] elements that take the NUMBER position
|
225
|
+
# in the expression
|
226
|
+
# @param operations [Array<(Parslet::Atoms::Base, Integer, {:left, :right})>]
|
227
|
+
#
|
228
|
+
# @see Parslet::Atoms::Infix
|
229
|
+
#
|
230
|
+
def infix_expression(element, *operations)
|
231
|
+
Parslet::Atoms::Infix.new(element, operations)
|
232
|
+
end
|
233
|
+
module_function :infix_expression
|
202
234
|
|
203
235
|
# A special kind of atom that allows embedding whole treetop expressions
|
204
236
|
# into parslet construction.
|
@@ -254,7 +286,7 @@ module Parslet
|
|
254
286
|
Pattern::SubtreeBind.new(symbol)
|
255
287
|
end
|
256
288
|
module_function :subtree
|
257
|
-
|
289
|
+
|
258
290
|
autoload :Expression, 'parslet/expression'
|
259
291
|
end
|
260
292
|
|
@@ -0,0 +1,161 @@
|
|
1
|
+
|
2
|
+
|
3
|
+
# Optimizes the parsers by pattern matching on the parser atoms and replacing
|
4
|
+
# matches with better versions. See the file qed/accelerators.md for a more
|
5
|
+
# in-depth description.
|
6
|
+
#
|
7
|
+
# Example:
|
8
|
+
# quote = str('"')
|
9
|
+
# parser = quote >> (quote.absent? >> any).repeat >> quote
|
10
|
+
#
|
11
|
+
# A = Accelerator # for making what follows a bit shorter
|
12
|
+
# optimized_parser = A.apply(parser,
|
13
|
+
# A.rule( (A.str(:x).absent? >> A.any).repeat ) { GobbleUp.new(x) })
|
14
|
+
#
|
15
|
+
# optimized_parser.parse('"Parsing is now fully optimized! (tm)"')
|
16
|
+
#
|
17
|
+
module Parslet::Accelerator
|
18
|
+
|
19
|
+
# An expression to match against a tree of parser atoms. Normally, an
|
20
|
+
# expression is produced by Parslet::Accelerator.any,
|
21
|
+
# Parslet::Accelerator.str or Parslet::Accelerator.re.
|
22
|
+
#
|
23
|
+
# Expressions can be chained much like parslet atoms can be:
|
24
|
+
#
|
25
|
+
# expr.repeat(1) # matching repetition
|
26
|
+
# expr.absent? # matching absent?
|
27
|
+
# expr.present? # matching present?
|
28
|
+
# expr1 >> expr2 # matching a sequence
|
29
|
+
# expr1 | expr2 # matching an alternation
|
30
|
+
#
|
31
|
+
# @see Parslet::Accelerator.str
|
32
|
+
# @see Parslet::Accelerator.re
|
33
|
+
# @see Parslet::Accelerator.any
|
34
|
+
#
|
35
|
+
# @see Parslet::Accelerator
|
36
|
+
#
|
37
|
+
class Expression
|
38
|
+
attr_reader :type
|
39
|
+
attr_reader :args
|
40
|
+
|
41
|
+
def initialize(type, *args)
|
42
|
+
@type = type
|
43
|
+
@args = args
|
44
|
+
end
|
45
|
+
|
46
|
+
# @return [Expression]
|
47
|
+
def >> other_expr
|
48
|
+
join_or_new :seq, other_expr
|
49
|
+
end
|
50
|
+
|
51
|
+
# @return [Expression]
|
52
|
+
def | other_expr
|
53
|
+
join_or_new :alt, other_expr
|
54
|
+
end
|
55
|
+
|
56
|
+
# @return [Expression]
|
57
|
+
def absent?
|
58
|
+
Expression.new(:absent, self)
|
59
|
+
end
|
60
|
+
# @return [Expression]
|
61
|
+
def present?
|
62
|
+
Expression.new(:present, self)
|
63
|
+
end
|
64
|
+
|
65
|
+
# @return [Expression]
|
66
|
+
def repeat min=0, max=nil
|
67
|
+
Expression.new(:rep, min, max, self)
|
68
|
+
end
|
69
|
+
|
70
|
+
# @return [Expression]
|
71
|
+
def as name
|
72
|
+
Expression.new(:as, name)
|
73
|
+
end
|
74
|
+
|
75
|
+
# @api private
|
76
|
+
# @return [Expression]
|
77
|
+
def join_or_new tag, other_expr
|
78
|
+
if type == tag
|
79
|
+
@args << other_expr
|
80
|
+
else
|
81
|
+
Expression.new(tag, self, other_expr)
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
module_function
|
87
|
+
# Returns a match expression that will match `str` parslet atoms.
|
88
|
+
#
|
89
|
+
# @return [Parslet::Accelerator::Expression]
|
90
|
+
#
|
91
|
+
def str variable, *constraints
|
92
|
+
Expression.new(:str, variable, *constraints)
|
93
|
+
end
|
94
|
+
|
95
|
+
# Returns a match expression that will match `match` parslet atoms.
|
96
|
+
#
|
97
|
+
# @return [Parslet::Accelerator::Expression]
|
98
|
+
#
|
99
|
+
def re variable, *constraints
|
100
|
+
Expression.new(:re, variable, *constraints)
|
101
|
+
end
|
102
|
+
|
103
|
+
# Returns a match expression that will match `any` parslet atoms.
|
104
|
+
#
|
105
|
+
# @return [Parslet::Accelerator::Expression]
|
106
|
+
#
|
107
|
+
def any
|
108
|
+
Expression.new(:re, ".")
|
109
|
+
end
|
110
|
+
|
111
|
+
# Given a parslet atom and an expression, will determine if the expression
|
112
|
+
# matches the atom. If successful, returns the bindings into the pattern
|
113
|
+
# that were made. If no bindings had to be made to make the match successful,
|
114
|
+
# the empty hash is returned.
|
115
|
+
#
|
116
|
+
# @param atom [Parslet::Atoms::Base] parslet atom to match against
|
117
|
+
# @param expr [Parslet::Accelerator::Expression] expression to match
|
118
|
+
# @return [nil, Hash] bindings for the match, nil on failure
|
119
|
+
#
|
120
|
+
def match atom, expr
|
121
|
+
engine = Engine.new
|
122
|
+
|
123
|
+
return engine.bindings if engine.match(atom, expr)
|
124
|
+
end
|
125
|
+
|
126
|
+
# Constructs an accelerator rule. A rule is a matching expression and the
|
127
|
+
# code that should be executed once the expression could be bound to a
|
128
|
+
# parser.
|
129
|
+
#
|
130
|
+
# Example:
|
131
|
+
# Accelerator.rule(Accelerator.any) { Parslet.match('.') }
|
132
|
+
#
|
133
|
+
def rule expression, &action
|
134
|
+
[expression, action]
|
135
|
+
end
|
136
|
+
|
137
|
+
# Given a parslet atom and a set of rules, tries to match the rules
|
138
|
+
# recursively through the parslet atom. Once a rule could be matched,
|
139
|
+
# its action block will be called.
|
140
|
+
#
|
141
|
+
# Example:
|
142
|
+
# quote = str('"')
|
143
|
+
# parser = quote >> (quote.absent? >> any).repeat >> quote
|
144
|
+
#
|
145
|
+
# A = Accelerator # for making what follows a bit shorter
|
146
|
+
# optimized_parser = A.apply(parser,
|
147
|
+
# A.rule( (A.str(:x).absent? >> A.any).repeat ) { GobbleUp.new(x) })
|
148
|
+
#
|
149
|
+
# optimized_parser.parse('"Parsing is now fully optimized! (tm)"')
|
150
|
+
#
|
151
|
+
# @param atom [Parslet::Atoms::Base] a parser to optimize
|
152
|
+
# @param *rules [Parslet::Accelerator::Rule] rules produced by .rule
|
153
|
+
# @return [Parslet::Atoms::Base] optimized parser
|
154
|
+
#
|
155
|
+
def apply atom, *rules
|
156
|
+
Application.new(atom, rules).call
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
require 'parslet/accelerator/engine'
|
161
|
+
require 'parslet/accelerator/application'
|