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 CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  GemSpec = Gem::Specification.new do |gem|
4
4
  gem.name = 'peglite'
5
- gem.version = '0.0.1'
5
+ gem.version = '0.0.2'
6
6
  gem.license = 'MIT'
7
7
  gem.required_ruby_version = '>= 1.9.1'
8
8
 
data/CHANGELOG.yaml CHANGED
@@ -1,3 +1,9 @@
1
+ - version: 0.0.2
2
+ date: Wed Jan 2 18:05:30 PST 2013
3
+ changes:
4
+ - Add examples
5
+ - Add \A to regexes automatically
6
+ - Test an extended grammar
1
7
  - version: 0.0.1
2
8
  date: Wed Jan 2 14:51:35 PST 2013
3
9
  changes: Ported from Pegex.pm CPAN module.
data/ToDo ADDED
@@ -0,0 +1,2 @@
1
+ + Add \A automatically
2
+ + Add accessor for @input
@@ -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
- $PegLiteRules = {} # XXX global variable smell
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
- fail "Regexp for '#{name}' must begin with '\\A'" \
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' => 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
- rule _: (/\A\s*/)
32
- rule __: (/\A\s+/)
33
- rule EQUAL: (/\A=/)
34
- rule COMMA: (/\A,/)
35
- rule NL: (/\A\n/)
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
- $address1 = <<'...'
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 $address1
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 $address1
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: (/\A(.*?)\n/)
51
- rule street: (/\A(.*?)\n/)
77
+ rule name: (/(.*?)\n/)
78
+ rule street: (/(.*?)\n/)
52
79
  rule place: "city COMMA _ state __ zip NL"
53
- rule city: (/\A(\w+(?: \w+)?)/)
54
- rule state: (/\A(WA|OR|CA)/) # Left Coast Rulez
55
- rule zip: (/\A(\d{5})/)
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.1
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-02 00:00:00.000000000 Z
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