peglite 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gemspec +18 -0
- data/CHANGELOG.yaml +3 -0
- data/Gemfile +2 -0
- data/LICENSE +21 -0
- data/README.rdoc +38 -0
- data/Rakefile +67 -0
- data/lib/peglite/compiler.rb +125 -0
- data/lib/peglite.rb +202 -0
- data/test/address.rb +56 -0
- metadata +56 -0
data/.gemspec
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
GemSpec = Gem::Specification.new do |gem|
|
4
|
+
gem.name = 'peglite'
|
5
|
+
gem.version = '0.0.1'
|
6
|
+
gem.license = 'MIT'
|
7
|
+
gem.required_ruby_version = '>= 1.9.1'
|
8
|
+
|
9
|
+
gem.authors << 'Ingy döt Net'
|
10
|
+
gem.email = 'ingy@ingy.net'
|
11
|
+
gem.summary = 'Simple PEG Parsing Framework'
|
12
|
+
gem.description = <<-'.'
|
13
|
+
PegLite is a very simple framework for creating your own PEG parsers.
|
14
|
+
.
|
15
|
+
gem.homepage = 'http://pegex.org'
|
16
|
+
|
17
|
+
gem.files = `git ls-files`.lines.map{|l|l.chomp}
|
18
|
+
end
|
data/CHANGELOG.yaml
ADDED
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
(The MIT License)
|
2
|
+
|
3
|
+
Copyright © 2013 Ingy döt Net
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
6
|
+
this software and associated documentation files (the ‘Software’), to deal in
|
7
|
+
the Software without restriction, including without limitation the rights to
|
8
|
+
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
9
|
+
of the Software, and to permit persons to whom the Software is furnished to do
|
10
|
+
so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
13
|
+
copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED ‘AS IS’, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21
|
+
SOFTWARE.
|
data/README.rdoc
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
= PegLite - Simple PEG Parsing Framework
|
2
|
+
|
3
|
+
PegLite is a very easy way to make a PEG parser by simply writing a PegLite
|
4
|
+
subclass and a few regexes.
|
5
|
+
|
6
|
+
= Synopsis
|
7
|
+
|
8
|
+
require 'peglite'
|
9
|
+
class MyParser < PegLite
|
10
|
+
def top
|
11
|
+
match rule "( comment | assignment )*"
|
12
|
+
end
|
13
|
+
token comment: /\s*#.*\s*\n/
|
14
|
+
def assignment
|
15
|
+
m = match "id WS* EQUAL WS* value WS* EOL"
|
16
|
+
return { 'var' => m[0], 'value' => m[1] }
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
puts YAML.dump MyParser.new.parse <<'...'
|
21
|
+
# This is a comment. Below is an assignment statement:
|
22
|
+
foo = 123
|
23
|
+
|
24
|
+
# A string assignment:
|
25
|
+
bar = 'O HAI'
|
26
|
+
...
|
27
|
+
|
28
|
+
The above program, defines a parser, uses it to parse a text into a data tree,
|
29
|
+
and then prints the tree in YAML:
|
30
|
+
|
31
|
+
- var: foo
|
32
|
+
value: 123
|
33
|
+
- var: bar
|
34
|
+
value: O HAI
|
35
|
+
|
36
|
+
Pretty simple, right?
|
37
|
+
|
38
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,67 @@
|
|
1
|
+
# Load Gem constants from the gemspec
|
2
|
+
GemSpecFile = '.gemspec'
|
3
|
+
load GemSpecFile
|
4
|
+
GemName = GemSpec.name
|
5
|
+
GemVersion = GemSpec.version
|
6
|
+
GemDir = "#{GemName}-#{GemVersion}"
|
7
|
+
GemFile = "#{GemDir}.gem"
|
8
|
+
DevNull = '2>/dev/null'
|
9
|
+
|
10
|
+
# Require the Rake libraries
|
11
|
+
require 'rake'
|
12
|
+
require 'rake/testtask'
|
13
|
+
require 'rake/clean'
|
14
|
+
if File.exists? 'test/testml.yaml'
|
15
|
+
require 'rake/testml'
|
16
|
+
end
|
17
|
+
|
18
|
+
task :default => 'help'
|
19
|
+
|
20
|
+
CLEAN.include GemDir, GemFile, 'data.tar.gz', 'metadata.gz'
|
21
|
+
|
22
|
+
desc 'Run the tests'
|
23
|
+
task :test do
|
24
|
+
Rake::TestTask.new do |t|
|
25
|
+
t.verbose = true
|
26
|
+
t.test_files = FileList['test/*.rb']
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
desc 'Build the gem'
|
31
|
+
task :build => [:clean, :test] do
|
32
|
+
sh "gem build #{GemSpecFile}"
|
33
|
+
end
|
34
|
+
|
35
|
+
desc 'Install the gem'
|
36
|
+
task :install => [:build] do
|
37
|
+
sh "gem install #{GemFile}"
|
38
|
+
end
|
39
|
+
|
40
|
+
desc 'Build, unpack and inspect the gem'
|
41
|
+
task :distdir => [:build] do
|
42
|
+
sh "tar xf #{GemFile} #{DevNull}"
|
43
|
+
Dir.mkdir GemDir
|
44
|
+
Dir.chdir GemDir
|
45
|
+
sh "tar xzf ../data.tar.gz #{DevNull}"
|
46
|
+
puts "\n>>> Entering sub-shell for #{GemDir}..."
|
47
|
+
system ENV['SHELL']
|
48
|
+
end
|
49
|
+
|
50
|
+
desc 'Build and push the gem'
|
51
|
+
task :release => [:build] do
|
52
|
+
sh "gem push #{GemFile}"
|
53
|
+
end
|
54
|
+
|
55
|
+
desc 'Print a description of the gem'
|
56
|
+
task :desc do
|
57
|
+
puts "Gem: '#{GemName}' (version #{GemVersion})"
|
58
|
+
puts
|
59
|
+
puts GemSpec.description.gsub /^/, ' '
|
60
|
+
end
|
61
|
+
|
62
|
+
desc 'List the Rakefile tasks'
|
63
|
+
task :help do
|
64
|
+
puts 'The following rake tasks are available:'
|
65
|
+
puts
|
66
|
+
puts `rake -T`.gsub /^/, ' '
|
67
|
+
end
|
@@ -0,0 +1,125 @@
|
|
1
|
+
class PegLite;end
|
2
|
+
|
3
|
+
#------------------------------------------------------------------------------
|
4
|
+
class PegLite::Compiler
|
5
|
+
def initialize peglite_rule
|
6
|
+
tokenize peglite_rule
|
7
|
+
end
|
8
|
+
|
9
|
+
def compile
|
10
|
+
fail if @tokens.empty?
|
11
|
+
if @tokens[0] == '('
|
12
|
+
@tokens.shift
|
13
|
+
got = compile
|
14
|
+
fail if (@tokens.empty? or not @tokens.shift.match /^\)([\?\*\+]?)/)
|
15
|
+
got.merge! compile_limits $1
|
16
|
+
elsif @tokens.size > 1
|
17
|
+
if @tokens[1] == '|'
|
18
|
+
got = compile_any
|
19
|
+
else
|
20
|
+
got = compile_all
|
21
|
+
end
|
22
|
+
else
|
23
|
+
fail @tokens.to_s
|
24
|
+
end
|
25
|
+
return got
|
26
|
+
end
|
27
|
+
|
28
|
+
def compile_all
|
29
|
+
fail if @tokens.empty?
|
30
|
+
all = []
|
31
|
+
until @tokens.empty?
|
32
|
+
if @tokens[0] == '('
|
33
|
+
all.push compile
|
34
|
+
elsif @tokens[0].match /^\)/
|
35
|
+
break
|
36
|
+
elsif @tokens[0].match /^\w/
|
37
|
+
all.push compile_ref
|
38
|
+
else
|
39
|
+
fail
|
40
|
+
end
|
41
|
+
end
|
42
|
+
return {
|
43
|
+
'type' => 'all',
|
44
|
+
'rule' => all,
|
45
|
+
'min' => 1,
|
46
|
+
'max' => 1,
|
47
|
+
}
|
48
|
+
end
|
49
|
+
|
50
|
+
def compile_any
|
51
|
+
fail if @tokens.empty?
|
52
|
+
any = []
|
53
|
+
until @tokens.empty?
|
54
|
+
if @tokens[0] == '('
|
55
|
+
any.push compile
|
56
|
+
elsif @tokens[0].match /^\)/
|
57
|
+
break
|
58
|
+
elsif @tokens[0].match /^\w/
|
59
|
+
any.push compile_ref
|
60
|
+
if not @tokens.empty?
|
61
|
+
if @tokens[0] == '|'
|
62
|
+
@tokens.shift
|
63
|
+
elsif not @tokens[0].match /^\)/
|
64
|
+
fail
|
65
|
+
end
|
66
|
+
end
|
67
|
+
else
|
68
|
+
fail
|
69
|
+
end
|
70
|
+
end
|
71
|
+
return {
|
72
|
+
'type' => 'any',
|
73
|
+
'rule' => any,
|
74
|
+
'min' => 1,
|
75
|
+
'max' => 1,
|
76
|
+
}
|
77
|
+
end
|
78
|
+
|
79
|
+
def compile_ref
|
80
|
+
fail if @tokens.empty?
|
81
|
+
token = @tokens.shift
|
82
|
+
token.match(/^(\w+)([\?\*\+]?)$/) or fail
|
83
|
+
rule, quantifier = $1, $2
|
84
|
+
ref = {
|
85
|
+
'type' => 'ref',
|
86
|
+
'rule' => rule,
|
87
|
+
}
|
88
|
+
return ref.merge! compile_limits(quantifier)
|
89
|
+
end
|
90
|
+
|
91
|
+
def compile_limits quantifier
|
92
|
+
case quantifier
|
93
|
+
when '?'; { 'min' => 0, 'max' => 1 }
|
94
|
+
when '*'; { 'min' => 0, 'max' => 0 }
|
95
|
+
when '+'; { 'min' => 1, 'max' => 0 }
|
96
|
+
else; { 'min' => 1, 'max' => 1 }
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
def tokenize text
|
101
|
+
input = text.clone
|
102
|
+
@tokens = []
|
103
|
+
while (token = get_token input)
|
104
|
+
@tokens.concat token
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
def get_token input
|
109
|
+
return if input.empty?
|
110
|
+
patterns = [
|
111
|
+
/\A\s+/,
|
112
|
+
/\A(\()/,
|
113
|
+
/\A(\w+[\?\*\+]?)/,
|
114
|
+
/\A(\|)/,
|
115
|
+
/\A(\)[\?\*\+]?)/,
|
116
|
+
]
|
117
|
+
patterns.each do |r|
|
118
|
+
if m = input.match(r)
|
119
|
+
input.sub! r, ''
|
120
|
+
return m.captures
|
121
|
+
end
|
122
|
+
end
|
123
|
+
fail "Failed to find next token in '#{input}'"
|
124
|
+
end
|
125
|
+
end
|
data/lib/peglite.rb
ADDED
@@ -0,0 +1,202 @@
|
|
1
|
+
require 'peglite/compiler'
|
2
|
+
|
3
|
+
require 'yaml'; def XXX *args; args.each \
|
4
|
+
{|a|puts YAML.dump a};puts caller.first; exit; end
|
5
|
+
require 'yaml'; def YYY *args; args.each \
|
6
|
+
{|a|puts YAML.dump a};puts caller.first;return args[0]; end
|
7
|
+
|
8
|
+
#------------------------------------------------------------------------------
|
9
|
+
class PegLite
|
10
|
+
$PegLiteRules = {} # XXX global variable smell
|
11
|
+
def self.rule args
|
12
|
+
name, rule = args.first
|
13
|
+
name = name.to_s
|
14
|
+
$PegLiteTopRule ||= name
|
15
|
+
if rule.kind_of? Regexp
|
16
|
+
fail "Regexp for '#{name}' must begin with '\\A'" \
|
17
|
+
unless rule.to_s.match /\A\(\?-mix:\\A/
|
18
|
+
$PegLiteRules[name] = {
|
19
|
+
'type' => 'rgx',
|
20
|
+
'rule' => rule,
|
21
|
+
'min' => 1,
|
22
|
+
'max' => 1,
|
23
|
+
}
|
24
|
+
elsif rule.kind_of? String
|
25
|
+
$PegLiteRules[name] = PegLite::Compiler.new(rule).compile
|
26
|
+
else
|
27
|
+
fail "Don't know how to make rule '#{name}' from '#{rule}'"
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
rule _: (/\A\s*/)
|
32
|
+
rule __: (/\A\s+/)
|
33
|
+
rule EQUAL: (/\A=/)
|
34
|
+
rule COMMA: (/\A,/)
|
35
|
+
rule NL: (/\A\n/)
|
36
|
+
$PegLiteTopRule = nil
|
37
|
+
|
38
|
+
attr_accessor :got
|
39
|
+
attr_accessor :wrap
|
40
|
+
attr_accessor :debug
|
41
|
+
def initialize attrs={}
|
42
|
+
@got = nil
|
43
|
+
@wrap = false
|
44
|
+
@debug = false
|
45
|
+
|
46
|
+
attrs.each { |k,v| self.send "#{k}=", v }
|
47
|
+
|
48
|
+
@pos = 0
|
49
|
+
@far = 0
|
50
|
+
@rules = $PegLiteRules
|
51
|
+
yield self if block_given?
|
52
|
+
end
|
53
|
+
|
54
|
+
def parse input, top=($PegLiteTopRule || 'top')
|
55
|
+
fail "PegLite parse() method requires an input string" \
|
56
|
+
unless input.kind_of? String
|
57
|
+
@input = input
|
58
|
+
got = match_ref top
|
59
|
+
failure if @pos < @input.length
|
60
|
+
return @got || got[0]
|
61
|
+
end
|
62
|
+
|
63
|
+
def match rule=nil
|
64
|
+
if not rule.kind_of? Hash
|
65
|
+
rule ||= caller.first.scan(/(\w+)/).last.first
|
66
|
+
rule_name = rule
|
67
|
+
if rule.kind_of? String
|
68
|
+
rule = @rules[rule]
|
69
|
+
end
|
70
|
+
fail "Can't find rule for '#{rule_name}'" \
|
71
|
+
if not(rule and rule.kind_of? Hash)
|
72
|
+
end
|
73
|
+
|
74
|
+
pos, count, matched, type, child, min, max =
|
75
|
+
@pos, 0, [], *(rule.values_at *%w(type rule min max))
|
76
|
+
|
77
|
+
while (result = self.method("match_#{type}").call(child))
|
78
|
+
pos = @pos
|
79
|
+
count += 1
|
80
|
+
if result.kind_of? Array
|
81
|
+
matched.concat result
|
82
|
+
else
|
83
|
+
matched << result
|
84
|
+
end
|
85
|
+
break if max == 1
|
86
|
+
end
|
87
|
+
|
88
|
+
if count >= min and (max == 0 or count <= max)
|
89
|
+
return matched
|
90
|
+
else
|
91
|
+
@pos = pos
|
92
|
+
return
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
def match_all all
|
97
|
+
pos, set, count = @pos, [], 0
|
98
|
+
all.each do |elem|
|
99
|
+
if (m = match elem)
|
100
|
+
set.concat m
|
101
|
+
count += 1
|
102
|
+
else
|
103
|
+
if (@pos = pos) > @far
|
104
|
+
@far = pos
|
105
|
+
end
|
106
|
+
return
|
107
|
+
end
|
108
|
+
end
|
109
|
+
set = [ set ] if count > 1
|
110
|
+
return set
|
111
|
+
end
|
112
|
+
|
113
|
+
def match_any any
|
114
|
+
any.each do |elem|
|
115
|
+
if (m = match elem)
|
116
|
+
return m
|
117
|
+
end
|
118
|
+
end
|
119
|
+
return
|
120
|
+
end
|
121
|
+
|
122
|
+
# TODO move trace/debug out of default match_ref method
|
123
|
+
def match_ref ref
|
124
|
+
trace "Try #{ref}" if @debug
|
125
|
+
begin
|
126
|
+
m = self.method(ref).call
|
127
|
+
rescue NameError => e
|
128
|
+
if @rules[ref]
|
129
|
+
m = match @rules[ref]
|
130
|
+
else
|
131
|
+
fail "No rule defined for '#{ref}'"
|
132
|
+
end
|
133
|
+
end
|
134
|
+
if m
|
135
|
+
m = (@wrap and not m.empty?) ? [{ref => m}] : m
|
136
|
+
trace "Got #{ref}" if @debug
|
137
|
+
else
|
138
|
+
trace "Not #{ref}" if @debug
|
139
|
+
end
|
140
|
+
return m
|
141
|
+
end
|
142
|
+
|
143
|
+
def match_rgx regex
|
144
|
+
m = @input[@pos..-1].match(regex)
|
145
|
+
return unless m
|
146
|
+
@pos += m[0].length
|
147
|
+
match = m.captures
|
148
|
+
# XXX not sure about this:
|
149
|
+
match = [ match ] if m.length > 2
|
150
|
+
@far = @pos if @pos > @far
|
151
|
+
return match
|
152
|
+
end
|
153
|
+
|
154
|
+
#----------------------------------------------------------------------------
|
155
|
+
# Debugging and error reporting support methods
|
156
|
+
#----------------------------------------------------------------------------
|
157
|
+
def trace action
|
158
|
+
indent = !!action.match(/^Try /)
|
159
|
+
@indent ||= 0
|
160
|
+
@indent -= 1 unless indent
|
161
|
+
$stderr.print ' ' * @indent
|
162
|
+
@indent += 1 if indent
|
163
|
+
snippet = @input[@pos..-1]
|
164
|
+
snippet = snippet[0..30] + '...' if snippet.length > 30;
|
165
|
+
snippet.gsub! /\n/, "\\n"
|
166
|
+
$stderr.printf "%-30s", action
|
167
|
+
$stderr.print indent ? " >#{snippet}<\n" : "\n"
|
168
|
+
end
|
169
|
+
|
170
|
+
def failure
|
171
|
+
msg = "Parse failed for some reason"
|
172
|
+
raise PegexParseError, format_error(msg)
|
173
|
+
end
|
174
|
+
|
175
|
+
class PegexParseError < RuntimeError;end
|
176
|
+
def format_error msg
|
177
|
+
buffer = @input
|
178
|
+
position = @far
|
179
|
+
real_pos = @pos
|
180
|
+
|
181
|
+
line = buffer[0, position].scan(/\n/).size + 1
|
182
|
+
column = position - (buffer.rindex("\n", position) || -1)
|
183
|
+
|
184
|
+
pretext = @input[
|
185
|
+
position < 50 ? 0 : position - 50,
|
186
|
+
position < 50 ? position : 50
|
187
|
+
]
|
188
|
+
context = @input[position, 50]
|
189
|
+
pretext.gsub! /.*\n/m, ''
|
190
|
+
context.gsub! /\n/, "\\n"
|
191
|
+
|
192
|
+
return <<"..."
|
193
|
+
Error parsing Pegex document:
|
194
|
+
message: #{msg}
|
195
|
+
line: #{line}
|
196
|
+
column: #{column}
|
197
|
+
position: #{position}
|
198
|
+
context: #{pretext}#{context}
|
199
|
+
#{' ' * (pretext.length + 10)}^
|
200
|
+
...
|
201
|
+
end
|
202
|
+
end
|
data/test/address.rb
ADDED
@@ -0,0 +1,56 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
require 'peglite'
|
3
|
+
|
4
|
+
$address1 = <<'...'
|
5
|
+
John Doe
|
6
|
+
123 Main St
|
7
|
+
Los Angeles, CA 90009
|
8
|
+
...
|
9
|
+
|
10
|
+
$parse_plain = <<'...'
|
11
|
+
---
|
12
|
+
- John Doe
|
13
|
+
- 123 Main St
|
14
|
+
- - Los Angeles
|
15
|
+
- CA
|
16
|
+
- '90009'
|
17
|
+
...
|
18
|
+
|
19
|
+
$parse_wrap = <<'...'
|
20
|
+
---
|
21
|
+
address:
|
22
|
+
- - name:
|
23
|
+
- John Doe
|
24
|
+
- street:
|
25
|
+
- 123 Main St
|
26
|
+
- place:
|
27
|
+
- - city:
|
28
|
+
- Los Angeles
|
29
|
+
- state:
|
30
|
+
- CA
|
31
|
+
- zip:
|
32
|
+
- '90009'
|
33
|
+
...
|
34
|
+
|
35
|
+
class Test::Unit::TestCase
|
36
|
+
def test_plain
|
37
|
+
parser = AddressParser.new
|
38
|
+
result = parser.parse $address1
|
39
|
+
assert_equal YAML.dump(result), $parse_plain, "Plain parse works"
|
40
|
+
end
|
41
|
+
def test_wrap
|
42
|
+
parser = AddressParser.new wrap: true
|
43
|
+
result = parser.parse $address1
|
44
|
+
assert_equal YAML.dump(result), $parse_wrap, "Wrapping parse works"
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
class AddressParser < PegLite
|
49
|
+
rule address: "name street place"
|
50
|
+
rule name: (/\A(.*?)\n/)
|
51
|
+
rule street: (/\A(.*?)\n/)
|
52
|
+
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})/)
|
56
|
+
end
|
metadata
ADDED
@@ -0,0 +1,56 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: peglite
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Ingy döt Net
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2013-01-02 00:00:00.000000000 Z
|
13
|
+
dependencies: []
|
14
|
+
description: ! 'PegLite is a very simple framework for creating your own PEG parsers.
|
15
|
+
|
16
|
+
'
|
17
|
+
email: ingy@ingy.net
|
18
|
+
executables: []
|
19
|
+
extensions: []
|
20
|
+
extra_rdoc_files: []
|
21
|
+
files:
|
22
|
+
- .gemspec
|
23
|
+
- CHANGELOG.yaml
|
24
|
+
- Gemfile
|
25
|
+
- LICENSE
|
26
|
+
- README.rdoc
|
27
|
+
- Rakefile
|
28
|
+
- lib/peglite.rb
|
29
|
+
- lib/peglite/compiler.rb
|
30
|
+
- test/address.rb
|
31
|
+
homepage: http://pegex.org
|
32
|
+
licenses:
|
33
|
+
- MIT
|
34
|
+
post_install_message:
|
35
|
+
rdoc_options: []
|
36
|
+
require_paths:
|
37
|
+
- lib
|
38
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
39
|
+
none: false
|
40
|
+
requirements:
|
41
|
+
- - ! '>='
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: 1.9.1
|
44
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
45
|
+
none: false
|
46
|
+
requirements:
|
47
|
+
- - ! '>='
|
48
|
+
- !ruby/object:Gem::Version
|
49
|
+
version: '0'
|
50
|
+
requirements: []
|
51
|
+
rubyforge_project:
|
52
|
+
rubygems_version: 1.8.23
|
53
|
+
signing_key:
|
54
|
+
specification_version: 3
|
55
|
+
summary: Simple PEG Parsing Framework
|
56
|
+
test_files: []
|