peglite 0.0.1 → 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- data/.gemspec +1 -1
- data/CHANGELOG.yaml +6 -0
- data/ToDo +2 -0
- data/examples/parslet1.rb +23 -0
- data/examples/parslet2.rb +51 -0
- data/lib/peglite.rb +16 -10
- data/test/address.rb +57 -8
- metadata +5 -2
data/.gemspec
CHANGED
data/CHANGELOG.yaml
CHANGED
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'peglite'
|
2
|
+
|
3
|
+
class Mini < PegLite
|
4
|
+
rule integer: (/(\d+)/)
|
5
|
+
end
|
6
|
+
|
7
|
+
p Mini.new.parse "132432" # => "132432"
|
8
|
+
|
9
|
+
__END__
|
10
|
+
This is the PegLite version of the "simplest Parselet" example from here:
|
11
|
+
|
12
|
+
http://kschiess.github.com/parslet/get-started.html
|
13
|
+
|
14
|
+
Here is the original:
|
15
|
+
|
16
|
+
require 'parslet'
|
17
|
+
|
18
|
+
class Mini < Parslet::Parser
|
19
|
+
rule(:integer) { match('[0-9]').repeat(1) }
|
20
|
+
root(:integer)
|
21
|
+
end
|
22
|
+
|
23
|
+
Mini.new.parse("132432") # => "132432"@0
|
@@ -0,0 +1,51 @@
|
|
1
|
+
require 'peglite'
|
2
|
+
|
3
|
+
class Mini < PegLite
|
4
|
+
rule expression: "sum | integer"
|
5
|
+
rule integer: /(\d+)/
|
6
|
+
rule operator: /([+])/
|
7
|
+
rule sum: "integer _ operator _ expression"
|
8
|
+
end
|
9
|
+
|
10
|
+
def parse str
|
11
|
+
mini = Mini.new
|
12
|
+
mini.parse str
|
13
|
+
rescue PegLite::PegexParseError => failure
|
14
|
+
Mini.new(debug: true).parse str
|
15
|
+
end
|
16
|
+
|
17
|
+
p parse "1 + 2 + 3" # => ["1", "+", ["2", "+", "3"]]
|
18
|
+
p parse "a + 2" # => Print debug trace and error analysis
|
19
|
+
|
20
|
+
__END__
|
21
|
+
This is the PegLite version of the "Parselet expression parser" example from
|
22
|
+
here:
|
23
|
+
|
24
|
+
http://kschiess.github.com/parslet/get-started.html
|
25
|
+
|
26
|
+
Here is the original:
|
27
|
+
|
28
|
+
class Mini < Parslet::Parser
|
29
|
+
rule(:integer) { match('[0-9]').repeat(1) >> space? }
|
30
|
+
|
31
|
+
rule(:space) { match('\s').repeat(1) }
|
32
|
+
rule(:space?) { space.maybe }
|
33
|
+
|
34
|
+
rule(:operator) { match('[+]') >> space? }
|
35
|
+
|
36
|
+
rule(:sum) { integer >> operator >> expression }
|
37
|
+
rule(:expression) { sum | integer }
|
38
|
+
|
39
|
+
root :expression
|
40
|
+
end
|
41
|
+
|
42
|
+
def parse(str)
|
43
|
+
mini = Mini.new
|
44
|
+
|
45
|
+
mini.parse(str)
|
46
|
+
rescue Parslet::ParseFailed => failure
|
47
|
+
puts failure.cause.ascii_tree
|
48
|
+
end
|
49
|
+
|
50
|
+
parse "1 + 2 + 3" # => "1 + 2 + 3"@0
|
51
|
+
parse "a + 2" # fails, see below
|
data/lib/peglite.rb
CHANGED
@@ -7,17 +7,18 @@ require 'yaml'; def YYY *args; args.each \
|
|
7
7
|
|
8
8
|
#------------------------------------------------------------------------------
|
9
9
|
class PegLite
|
10
|
-
|
10
|
+
VERSION = '0.0.2'
|
11
|
+
|
12
|
+
$PegLiteRules = {} # TODO get rid of global variable smell
|
11
13
|
def self.rule args
|
12
14
|
name, rule = args.first
|
13
15
|
name = name.to_s
|
14
16
|
$PegLiteTopRule ||= name
|
15
17
|
if rule.kind_of? Regexp
|
16
|
-
|
17
|
-
unless rule.to_s.match /\A\(\?-mix:\\A/
|
18
|
+
regex = Regexp.new(rule.to_s.sub(/:/, ':\\A'))
|
18
19
|
$PegLiteRules[name] = {
|
19
20
|
'type' => 'rgx',
|
20
|
-
'rule' =>
|
21
|
+
'rule' => regex,
|
21
22
|
'min' => 1,
|
22
23
|
'max' => 1,
|
23
24
|
}
|
@@ -28,20 +29,25 @@ class PegLite
|
|
28
29
|
end
|
29
30
|
end
|
30
31
|
|
31
|
-
|
32
|
-
rule
|
33
|
-
rule
|
34
|
-
rule
|
35
|
-
rule
|
32
|
+
# TODO define all the Pegex Atoms here
|
33
|
+
rule _: (/\s*/)
|
34
|
+
rule __: (/\s+/)
|
35
|
+
rule EQUAL: (/=/)
|
36
|
+
rule COMMA: (/,/)
|
37
|
+
rule PLUS: (/\+/)
|
38
|
+
rule NL: (/\n/)
|
39
|
+
rule EOL: (/\r?\n/)
|
36
40
|
$PegLiteTopRule = nil
|
37
41
|
|
38
42
|
attr_accessor :got
|
39
43
|
attr_accessor :wrap
|
40
44
|
attr_accessor :debug
|
45
|
+
attr_accessor :input
|
41
46
|
def initialize attrs={}
|
42
47
|
@got = nil
|
43
48
|
@wrap = false
|
44
49
|
@debug = false
|
50
|
+
@input = nil
|
45
51
|
|
46
52
|
attrs.each { |k,v| self.send "#{k}=", v }
|
47
53
|
|
@@ -51,7 +57,7 @@ class PegLite
|
|
51
57
|
yield self if block_given?
|
52
58
|
end
|
53
59
|
|
54
|
-
def parse input, top=($PegLiteTopRule || 'top')
|
60
|
+
def parse input=@input, top=($PegLiteTopRule || 'top')
|
55
61
|
fail "PegLite parse() method requires an input string" \
|
56
62
|
unless input.kind_of? String
|
57
63
|
@input = input
|
data/test/address.rb
CHANGED
@@ -1,12 +1,18 @@
|
|
1
|
+
# This PegLite test shows an address grammar parsing an street address.
|
2
|
+
# We parse it 3 different ways, to get different desired results.
|
3
|
+
|
4
|
+
|
1
5
|
require 'test/unit'
|
2
6
|
require 'peglite'
|
3
7
|
|
4
|
-
|
8
|
+
# A sample street address
|
9
|
+
$address = <<'...'
|
5
10
|
John Doe
|
6
11
|
123 Main St
|
7
12
|
Los Angeles, CA 90009
|
8
13
|
...
|
9
14
|
|
15
|
+
# Expected result tree for default/plain parsing
|
10
16
|
$parse_plain = <<'...'
|
11
17
|
---
|
12
18
|
- John Doe
|
@@ -16,6 +22,7 @@ $parse_plain = <<'...'
|
|
16
22
|
- '90009'
|
17
23
|
...
|
18
24
|
|
25
|
+
# Expected result tree using the 'wrap' option
|
19
26
|
$parse_wrap = <<'...'
|
20
27
|
---
|
21
28
|
address:
|
@@ -32,25 +39,67 @@ address:
|
|
32
39
|
- '90009'
|
33
40
|
...
|
34
41
|
|
42
|
+
# Expected result tree from our Custom parser extension
|
43
|
+
$parse_custom = <<'...'
|
44
|
+
---
|
45
|
+
name: John Doe
|
46
|
+
street: 123 Main St
|
47
|
+
city: Los Angeles
|
48
|
+
state: CA
|
49
|
+
zipcode: '90008'
|
50
|
+
...
|
51
|
+
|
52
|
+
# Run 3 tests
|
35
53
|
class Test::Unit::TestCase
|
54
|
+
# Parse address to an array of arrays
|
36
55
|
def test_plain
|
37
56
|
parser = AddressParser.new
|
38
|
-
result = parser.parse $
|
57
|
+
result = parser.parse $address
|
39
58
|
assert_equal YAML.dump(result), $parse_plain, "Plain parse works"
|
40
59
|
end
|
60
|
+
# Turn on 'wrap' to add rule name to each result
|
41
61
|
def test_wrap
|
42
62
|
parser = AddressParser.new wrap: true
|
43
|
-
result = parser.parse $
|
63
|
+
result = parser.parse $address
|
44
64
|
assert_equal YAML.dump(result), $parse_wrap, "Wrapping parse works"
|
45
65
|
end
|
66
|
+
# Return a custom AST
|
67
|
+
def test_custom
|
68
|
+
parser = AddressParserCustom.new
|
69
|
+
result = parser.parse $address
|
70
|
+
assert_equal YAML.dump(result), $parse_custom, "Custom parse works"
|
71
|
+
end
|
46
72
|
end
|
47
73
|
|
74
|
+
# This class defines a complete address parser using PegLite
|
48
75
|
class AddressParser < PegLite
|
49
76
|
rule address: "name street place"
|
50
|
-
rule name: (
|
51
|
-
rule street: (
|
77
|
+
rule name: (/(.*?)\n/)
|
78
|
+
rule street: (/(.*?)\n/)
|
52
79
|
rule place: "city COMMA _ state __ zip NL"
|
53
|
-
rule city: (
|
54
|
-
rule state: (
|
55
|
-
rule zip: (
|
80
|
+
rule city: (/(\w+(?: \w+)?)/)
|
81
|
+
rule state: (/(WA|OR|CA)/) # Left Coast Rulez
|
82
|
+
rule zip: (/(\d{5})/)
|
83
|
+
end
|
84
|
+
|
85
|
+
# Extend AddressParser
|
86
|
+
class AddressParserCustom < AddressParser
|
87
|
+
def address
|
88
|
+
name, street, place = match.first
|
89
|
+
city, state, zip = place
|
90
|
+
# Make the final AST from the parts collected.
|
91
|
+
@got = {
|
92
|
+
'name' => name,
|
93
|
+
'street' => street,
|
94
|
+
'city' => city,
|
95
|
+
'state' => state,
|
96
|
+
# Show as 'zipcode' instead of 'zip'
|
97
|
+
'zipcode' => zip,
|
98
|
+
}
|
99
|
+
end
|
100
|
+
|
101
|
+
# Subtract 1 from the zipcode for fun
|
102
|
+
def zip
|
103
|
+
(match.first.to_i - 1).to_s
|
104
|
+
end
|
56
105
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: peglite
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.2
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-01-
|
12
|
+
date: 2013-01-03 00:00:00.000000000 Z
|
13
13
|
dependencies: []
|
14
14
|
description: ! 'PegLite is a very simple framework for creating your own PEG parsers.
|
15
15
|
|
@@ -25,6 +25,9 @@ files:
|
|
25
25
|
- LICENSE
|
26
26
|
- README.rdoc
|
27
27
|
- Rakefile
|
28
|
+
- ToDo
|
29
|
+
- examples/parslet1.rb
|
30
|
+
- examples/parslet2.rb
|
28
31
|
- lib/peglite.rb
|
29
32
|
- lib/peglite/compiler.rb
|
30
33
|
- test/address.rb
|