peglite 0.0.1 → 0.0.2
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/.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
|