raabro 1.0.3 → 1.0.4
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.
- data/CHANGELOG.txt +5 -0
- data/README.md +89 -1
- data/lib/raabro.rb +17 -9
- data/spec/sample_xel_spec.rb +9 -14
- metadata +1 -1
data/CHANGELOG.txt
CHANGED
data/README.md
CHANGED
@@ -6,7 +6,95 @@
|
|
6
6
|
|
7
7
|
A very dumb PEG parser library.
|
8
8
|
|
9
|
-
Son to [aabro](https://github.com/flon-io/aabro), grandson to [neg](https://github.com/jmettraux/neg).
|
9
|
+
Son to [aabro](https://github.com/flon-io/aabro), grandson to [neg](https://github.com/jmettraux/neg), grand-grandson to [parslet](https://github.com/kschiess/parslet).
|
10
|
+
|
11
|
+
|
12
|
+
## a sample parser/rewriter
|
13
|
+
|
14
|
+
You use raabro by providing the parsing rules, then some rewrite rules.
|
15
|
+
|
16
|
+
The parsing rules make use of the raabro basic parsers `seq`, `alt`, `str`, `rex`, `eseq`, ...
|
17
|
+
|
18
|
+
The rewrite rules match names passed as first argument to the basic parsers to rewrite the resulting parse trees.
|
19
|
+
|
20
|
+
```ruby
|
21
|
+
require 'raabro'
|
22
|
+
|
23
|
+
|
24
|
+
module Fun include Raabro
|
25
|
+
|
26
|
+
# parse
|
27
|
+
#
|
28
|
+
# Last function is the root, "i" stands for "input".
|
29
|
+
|
30
|
+
def pa(i); rex(nil, i, /\(\s*/); end
|
31
|
+
def pz(i); rex(nil, i, /\)\s*/); end
|
32
|
+
def com(i); rex(nil, i, /,\s*/); end
|
33
|
+
|
34
|
+
def num(i); rex(:num, i, /-?[0-9]+\s*/); end
|
35
|
+
|
36
|
+
def args(i); eseq(:args, i, :pa, :exp, :com, :pz); end
|
37
|
+
def funame(i); rex(:funame, i, /[a-z][a-z0-9]*/); end
|
38
|
+
def fun(i); seq(:fun, i, :funame, :args); end
|
39
|
+
|
40
|
+
def exp(i); alt(:exp, i, :fun, :num); end
|
41
|
+
|
42
|
+
# rewrite
|
43
|
+
#
|
44
|
+
# Names above (:num, :fun, ...) get a rewrite_xxx function.
|
45
|
+
# "t" stands for "tree".
|
46
|
+
|
47
|
+
def rewrite_exp(t); rewrite(t.children[0]); end
|
48
|
+
def rewrite_num(t); t.string.to_i; end
|
49
|
+
|
50
|
+
def rewrite_fun(t)
|
51
|
+
[ t.children[0].string ] +
|
52
|
+
t.children[1].children.inject([]) { |a, e| a << rewrite(e) if e.name; a }
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
|
57
|
+
p Fun.parse('mul(1, 2)')
|
58
|
+
# => ["mul", 1, 2]
|
59
|
+
|
60
|
+
p Fun.parse('mul(1, add(-2, 3))')
|
61
|
+
# => ["mul", 1, ["add", -2, 3]]
|
62
|
+
|
63
|
+
p Fun.parse('mul (1, 2)')
|
64
|
+
# => nil (doesn't accept a space after the function name)
|
65
|
+
```
|
66
|
+
|
67
|
+
This sample is available at: [doc/readme0.rb](doc/readme0.rb).
|
68
|
+
|
69
|
+
|
70
|
+
## basic parsers
|
71
|
+
|
72
|
+
The first parameter is the name used by rewrite rules.
|
73
|
+
The second parameter is a `Raabro::Input` instance, mostly a wrapped string.
|
74
|
+
|
75
|
+
```ruby
|
76
|
+
def seq(name, input, *parsers)
|
77
|
+
# a sequence of parsers
|
78
|
+
|
79
|
+
def alt(name, input, *parsers)
|
80
|
+
# tries the parsers returns as soon as one succeeds
|
81
|
+
|
82
|
+
def altg(name, input, *parsers)
|
83
|
+
# tries all the parsers, returns with the longest match
|
84
|
+
|
85
|
+
def rep(name, input, parser, min, max=0)
|
86
|
+
# repeats the the wrapped parser
|
87
|
+
|
88
|
+
def ren(name, input, parser)
|
89
|
+
# renames the output of the wrapped parser
|
90
|
+
|
91
|
+
def jseq(name, input, eltpa, seppa)
|
92
|
+
# seq(name, input, eltpa, seppa, eltpa, seppa, eltpaa, seppa, ...)
|
93
|
+
|
94
|
+
def eseq(name, input, startpa, eltpa, seppa, endpa)
|
95
|
+
# seq(name, input, startpa, eltpa, seppa, eltpa, seppa, ..., endpa)
|
96
|
+
```
|
97
|
+
|
10
98
|
|
11
99
|
## LICENSE
|
12
100
|
|
data/lib/raabro.rb
CHANGED
@@ -26,7 +26,7 @@
|
|
26
26
|
|
27
27
|
module Raabro
|
28
28
|
|
29
|
-
VERSION = '1.0.
|
29
|
+
VERSION = '1.0.4'
|
30
30
|
|
31
31
|
class Input
|
32
32
|
|
@@ -388,6 +388,17 @@ module Raabro
|
|
388
388
|
end
|
389
389
|
alias jseq eseq
|
390
390
|
|
391
|
+
attr_accessor :last
|
392
|
+
|
393
|
+
def method_added(name)
|
394
|
+
|
395
|
+
m = method(name)
|
396
|
+
return unless m.arity == 1
|
397
|
+
return unless m.parameters[0][1] == :i || m.parameters[0][1] == :input
|
398
|
+
|
399
|
+
@last = name.to_sym
|
400
|
+
end
|
401
|
+
|
391
402
|
def parse(input, opts={})
|
392
403
|
|
393
404
|
opts[:prune] = true unless opts.has_key?(:prune)
|
@@ -405,20 +416,17 @@ module Raabro
|
|
405
416
|
|
406
417
|
t = t.children.first if t.parter == :all
|
407
418
|
|
408
|
-
return rewrite(t) if opts[:rewrite] != false &&
|
419
|
+
return rewrite(t) if opts[:rewrite] != false && rewrite(0) == true
|
409
420
|
|
410
421
|
t
|
411
422
|
end
|
412
423
|
|
413
|
-
|
424
|
+
def rewrite(tree)
|
414
425
|
|
415
|
-
|
426
|
+
return !! methods.find { |m| m.to_s.match(/^rewrite_/) } if tree == 0
|
427
|
+
# return true when "rewrite_xxx" methods seem to have been provided
|
416
428
|
|
417
|
-
|
418
|
-
return unless m.arity == 1
|
419
|
-
return unless m.parameters[0][1] == :i || m.parameters[0][1] == :input
|
420
|
-
|
421
|
-
@last = name.to_sym
|
429
|
+
send("rewrite_#{tree.name}", tree)
|
422
430
|
end
|
423
431
|
end
|
424
432
|
extend ModuleMethods
|
data/spec/sample_xel_spec.rb
CHANGED
@@ -10,7 +10,7 @@ require 'spec_helper'
|
|
10
10
|
|
11
11
|
module Sample::Xel include Raabro
|
12
12
|
|
13
|
-
#
|
13
|
+
# parse
|
14
14
|
|
15
15
|
def pa(i); str(nil, i, '('); end
|
16
16
|
def pz(i); str(nil, i, ')'); end
|
@@ -27,19 +27,14 @@ module Sample::Xel include Raabro
|
|
27
27
|
#alias root exp
|
28
28
|
# not necessary since Raabro takes the last defined parser as the root
|
29
29
|
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
[ tree.children[0].string ] +
|
39
|
-
tree.children[1].children.select(&:name).collect { |e| rewrite(e) }
|
40
|
-
else
|
41
|
-
fail ArgumentError.new("cannot rewrite #{tree.to_a.inspect}")
|
42
|
-
end
|
30
|
+
# rewrite
|
31
|
+
|
32
|
+
def rewrite_exp(t); rewrite(t.children[0]); end
|
33
|
+
def rewrite_num(t); t.string.to_i; end
|
34
|
+
|
35
|
+
def rewrite_fun(t)
|
36
|
+
[ t.children[0].string ] +
|
37
|
+
t.children[1].children.inject([]) { |a, e| a << rewrite(e) if e.name; a }
|
43
38
|
end
|
44
39
|
end
|
45
40
|
|