kpeg 0.8.5 → 0.9.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.autotest +10 -0
- data/.gemtest +0 -0
- data/Gemfile +11 -3
- data/History.txt +21 -0
- data/LICENSE +25 -0
- data/Manifest.txt +47 -0
- data/README.rdoc +222 -0
- data/Rakefile +23 -11
- data/bin/kpeg +4 -2
- data/examples/calculator/calculator.kpeg +17 -0
- data/examples/calculator/calculator.rb +7 -0
- data/examples/foreign_reference/literals.kpeg +5 -0
- data/examples/foreign_reference/matcher.kpeg +9 -0
- data/examples/foreign_reference/matcher.rb +5 -0
- data/examples/lua_string/driver.rb +21 -0
- data/examples/lua_string/lua_string.kpeg +14 -0
- data/examples/lua_string/lua_string.kpeg.rb +460 -0
- data/examples/phone_number/README.md +3 -0
- data/examples/phone_number/phone_number.kpeg +20 -0
- data/examples/phone_number/phone_number.rb +6 -0
- data/examples/upper/README.md +83 -0
- data/examples/upper/upper.kpeg +24 -0
- data/examples/upper/upper.rb +9 -0
- data/kpeg.gemspec +35 -17
- data/lib/hoe/kpeg.rb +94 -0
- data/lib/kpeg.rb +3 -0
- data/lib/kpeg/code_generator.rb +16 -3
- data/lib/kpeg/compiled_parser.rb +18 -28
- data/lib/kpeg/format_parser.kpeg +129 -0
- data/lib/kpeg/format_parser.rb +88 -49
- data/lib/kpeg/grammar.rb +10 -0
- data/lib/kpeg/string_escape.kpeg +20 -0
- data/test/inputs/comments.kpeg +5 -0
- data/test/test_file_parser_roundtrip.rb +3 -3
- data/test/test_gen_calc.rb +2 -2
- data/test/test_kpeg.rb +2 -2
- data/test/test_kpeg_code_generator.rb +65 -2
- data/test/test_kpeg_compiled_parser.rb +2 -2
- data/test/test_kpeg_format.rb +49 -4
- data/test/test_kpeg_grammar_renderer.rb +2 -2
- data/test/test_left_recursion.rb +2 -2
- data/{doc → vim}/syntax_kpeg/ftdetect/kpeg.vim +0 -0
- data/{doc → vim}/syntax_kpeg/syntax/kpeg.vim +0 -0
- metadata +89 -26
- data/README.md +0 -183
- data/lib/kpeg/version.rb +0 -3
@@ -0,0 +1,20 @@
|
|
1
|
+
%% name = PhoneNumber
|
2
|
+
|
3
|
+
%% {
|
4
|
+
attr_accessor :phone_number
|
5
|
+
}
|
6
|
+
digit = [0-9]
|
7
|
+
space = " "
|
8
|
+
dash = "-"
|
9
|
+
LP = "("
|
10
|
+
RP = ")"
|
11
|
+
|
12
|
+
country_code = < digit > { text }
|
13
|
+
area_code = < digit[3] > { text }
|
14
|
+
prefix = < digit[3] > { text }
|
15
|
+
suffix = < digit[4] > { text }
|
16
|
+
|
17
|
+
phone_number = LP? area_code:ac RP? space* prefix:p space* dash? space* suffix:s space* { "(#{ac}) #{p}-#{s}" }
|
18
|
+
|
19
|
+
root = phone_number:pn { @phone_number = pn }
|
20
|
+
| country_code:c space* phone_number:pn { @phone_number = "+#{c} #{pn}" }
|
@@ -0,0 +1,83 @@
|
|
1
|
+
# Upper Parser
|
2
|
+
|
3
|
+
A parser that matches a string with alpha characters, spaces and a period and returns the string in upper case.
|
4
|
+
|
5
|
+
## Grammar
|
6
|
+
|
7
|
+
Name of the class that will be used to do the parsing
|
8
|
+
|
9
|
+
%% name = Upper
|
10
|
+
|
11
|
+
A variable that I want to store the converted text for accessing later
|
12
|
+
|
13
|
+
%% {
|
14
|
+
attr_accessor :output
|
15
|
+
}
|
16
|
+
|
17
|
+
My literals
|
18
|
+
|
19
|
+
period = "."
|
20
|
+
space = " "
|
21
|
+
|
22
|
+
A rule that states that all characters that match the regex [A-Za-z] should be returned uppercase
|
23
|
+
|
24
|
+
alpha = < /[A-Za-z]/ > { text.upcase }
|
25
|
+
|
26
|
+
My rules that defines a word, it consists of three different cases, first that a word is an alpha followed by another word. If this matches return the alpha and the word that follows.
|
27
|
+
|
28
|
+
|
29
|
+
word = alpha:a word:w { "#{a}#{w}" }
|
30
|
+
|
31
|
+
This rule states that a word can be an alpha followed by a space. If this matches return an alpha followed by a space
|
32
|
+
|
33
|
+
| alpha:a space+ { "#{a} "}
|
34
|
+
|
35
|
+
This rule states that a word can consist of just an alpha. If this matches just return the alpha
|
36
|
+
|
37
|
+
| alpha:a { a }
|
38
|
+
|
39
|
+
My rules that defines a sentence. The first states that a sentence consists of a word followed by a sentence. If this matches return the word followed by the sentence.
|
40
|
+
|
41
|
+
sentence = < word:w sentence:s > { "#{w}#{s}" }
|
42
|
+
|
43
|
+
This rule states that a sentence can just be a word. If this matches just return the word.
|
44
|
+
|
45
|
+
| word:w { w }
|
46
|
+
|
47
|
+
My rules that define a document. The first rule states that a document can be a sentence followed by a period that may have space followed by another document. If this matches return the sentence followed by a period with a space followed by the document.
|
48
|
+
|
49
|
+
document = sentence:s period space* document:d { "#{s}. #{d}" }
|
50
|
+
|
51
|
+
This rule states that a document can be a sentence followed by a period. If this matches return the sentence followed by a period.
|
52
|
+
|
53
|
+
| sentence:s period { "#{s}." }
|
54
|
+
|
55
|
+
This rule states that a document can just be a sentence. If this matches just return the sentence.
|
56
|
+
|
57
|
+
| sentence:s { s }
|
58
|
+
|
59
|
+
The root node it the first rule evaluated, is it essentially the starting point for your grammar. If the string provided can successfully be matched by the grammar provided store the returned document in the @output variable.
|
60
|
+
|
61
|
+
root = document:d { @output = d }
|
62
|
+
|
63
|
+
## Generate the parser
|
64
|
+
|
65
|
+
To generate the parser make sure you have kpeg installed and run the following command (you may have to remove upper.kpeg.rb if it was previously generated)
|
66
|
+
|
67
|
+
kpeg upper.kpeg
|
68
|
+
|
69
|
+
## Run the parser
|
70
|
+
|
71
|
+
To run the parser run the following
|
72
|
+
|
73
|
+
ruby upper.rb
|
74
|
+
|
75
|
+
## Accepted Strings
|
76
|
+
|
77
|
+
+ a lower case string. Another lower case string.
|
78
|
+
+ A LOWER CASE STRING. ANOTHER LOWER CASE STRING.
|
79
|
+
+ a string with lots of spaces.
|
80
|
+
|
81
|
+
## Not accepted strings (there are tons)
|
82
|
+
|
83
|
+
Anything that doesn't stick to spaces and periods, very brittle but it is a simple example
|
@@ -0,0 +1,24 @@
|
|
1
|
+
%% name = Upper
|
2
|
+
|
3
|
+
|
4
|
+
%% {
|
5
|
+
attr_accessor :output
|
6
|
+
}
|
7
|
+
|
8
|
+
period = "."
|
9
|
+
space = " "
|
10
|
+
alpha = < /[A-Za-z]/ > { text.upcase }
|
11
|
+
|
12
|
+
word = alpha:a word:w { "#{a}#{w}" }
|
13
|
+
| alpha:a space { "#{a} "}
|
14
|
+
| alpha:a { a }
|
15
|
+
|
16
|
+
sentence = word:w sentence:s { "#{w}#{s}" }
|
17
|
+
| word:w { w }
|
18
|
+
|
19
|
+
document = sentence:s period space* document:d { "#{s}. #{d}" }
|
20
|
+
| sentence:s period { "#{s}." }
|
21
|
+
| sentence:s { "#{s}" }
|
22
|
+
|
23
|
+
root = document:d { @output = d }
|
24
|
+
|
@@ -0,0 +1,9 @@
|
|
1
|
+
# Make sure you have the kpeg gem installed
|
2
|
+
require 'rubygems'
|
3
|
+
# To generate the upper.kpeg file run kpeg upper.kpeg
|
4
|
+
require "./upper.kpeg.rb" # Require the generated parser
|
5
|
+
|
6
|
+
parser = Upper.new("a lower case string. Another lower case string.")
|
7
|
+
if parser.parse
|
8
|
+
puts parser.output
|
9
|
+
end
|
data/kpeg.gemspec
CHANGED
@@ -1,24 +1,42 @@
|
|
1
1
|
# -*- encoding: utf-8 -*-
|
2
|
-
$:.push File.expand_path("../lib", __FILE__)
|
3
|
-
require "kpeg/version"
|
4
2
|
|
5
3
|
Gem::Specification.new do |s|
|
6
|
-
s.name
|
7
|
-
s.version
|
8
|
-
s.platform = Gem::Platform::RUBY
|
9
|
-
s.authors = ["Evan Phoenix"]
|
10
|
-
s.email = ["evan@fallingsnow.net"]
|
11
|
-
s.homepage = "https://github.com/evanphx/kpeg"
|
12
|
-
s.summary = %q{Peg-based Code Generator}
|
13
|
-
s.description = %q{A tool for generating parsers using PEG}
|
4
|
+
s.name = "kpeg"
|
5
|
+
s.version = "0.8.5.20120306163408"
|
14
6
|
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
s.
|
19
|
-
s.
|
20
|
-
s.
|
7
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
8
|
+
s.authors = ["Eric Hodel"]
|
9
|
+
s.cert_chain = ["/Users/drbrain/.gem/gem-public_cert.pem"]
|
10
|
+
s.date = "2012-03-07"
|
11
|
+
s.description = "KPeg is a simple PEG library for Ruby. It provides an API as well as native\ngrammar to build the grammar.\n\nKPeg strives to provide a simple, powerful API without being too exotic.\n\nKPeg supports direct left recursion of rules via the\n{OMeta memoization}[http://www.vpri.org/pdf/tr2008003_experimenting.pdf] trick."
|
12
|
+
s.email = ["drbrain@segment7.net"]
|
21
13
|
s.executables = ["kpeg"]
|
14
|
+
s.extra_rdoc_files = ["History.txt", "Manifest.txt", "README.rdoc"]
|
15
|
+
s.files = [".autotest", "Gemfile", "Gemfile.lock", "History.txt", "LICENSE", "Manifest.txt", "README.rdoc", "Rakefile", "bin/kpeg", "examples/calculator/calculator.kpeg", "examples/calculator/calculator.rb", "examples/foreign_reference/literals.kpeg", "examples/foreign_reference/matcher.kpeg", "examples/foreign_reference/matcher.rb", "examples/lua_string/driver.rb", "examples/lua_string/lua_string.kpeg", "examples/lua_string/lua_string.kpeg.rb", "examples/phone_number/README.md", "examples/phone_number/phone_number.kpeg", "examples/phone_number/phone_number.rb", "examples/upper/README.md", "examples/upper/upper.kpeg", "examples/upper/upper.rb", "kpeg.gemspec", "lib/kpeg.rb", "lib/kpeg/code_generator.rb", "lib/kpeg/compiled_parser.rb", "lib/kpeg/format.kpeg", "lib/kpeg/format_parser.rb", "lib/kpeg/grammar.rb", "lib/kpeg/grammar_renderer.rb", "lib/kpeg/match.rb", "lib/kpeg/parser.rb", "lib/kpeg/position.rb", "lib/kpeg/string_escape.kpeg", "lib/kpeg/string_escape.rb", "lib/kpeg/version.rb", "test/inputs/comments.kpeg", "test/test_file_parser_roundtrip.rb", "test/test_gen_calc.rb", "test/test_kpeg.rb", "test/test_kpeg_code_generator.rb", "test/test_kpeg_compiled_parser.rb", "test/test_kpeg_format.rb", "test/test_kpeg_grammar_renderer.rb", "test/test_left_recursion.rb", "vim/syntax_kpeg/ftdetect/kpeg.vim", "vim/syntax_kpeg/syntax/kpeg.vim", ".gemtest"]
|
16
|
+
s.homepage = "https://github.com/evanphx/kpeg"
|
17
|
+
s.rdoc_options = ["--main", "README.rdoc"]
|
22
18
|
s.require_paths = ["lib"]
|
23
|
-
s.
|
19
|
+
s.rubyforge_project = "kpeg"
|
20
|
+
s.rubygems_version = "1.8.12"
|
21
|
+
s.signing_key = "/Users/drbrain/.gem/gem-private_key.pem"
|
22
|
+
s.summary = "KPeg is a simple PEG library for Ruby"
|
23
|
+
s.test_files = ["test/test_file_parser_roundtrip.rb", "test/test_gen_calc.rb", "test/test_kpeg.rb", "test/test_kpeg_code_generator.rb", "test/test_kpeg_compiled_parser.rb", "test/test_kpeg_format.rb", "test/test_kpeg_grammar_renderer.rb", "test/test_left_recursion.rb"]
|
24
|
+
|
25
|
+
if s.respond_to? :specification_version then
|
26
|
+
s.specification_version = 3
|
27
|
+
|
28
|
+
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
29
|
+
s.add_development_dependency(%q<minitest>, ["~> 2.11"])
|
30
|
+
s.add_development_dependency(%q<rdoc>, ["~> 3.10"])
|
31
|
+
s.add_development_dependency(%q<hoe>, ["~> 2.15"])
|
32
|
+
else
|
33
|
+
s.add_dependency(%q<minitest>, ["~> 2.11"])
|
34
|
+
s.add_dependency(%q<rdoc>, ["~> 3.10"])
|
35
|
+
s.add_dependency(%q<hoe>, ["~> 2.15"])
|
36
|
+
end
|
37
|
+
else
|
38
|
+
s.add_dependency(%q<minitest>, ["~> 2.11"])
|
39
|
+
s.add_dependency(%q<rdoc>, ["~> 3.10"])
|
40
|
+
s.add_dependency(%q<hoe>, ["~> 2.15"])
|
41
|
+
end
|
24
42
|
end
|
data/lib/hoe/kpeg.rb
ADDED
@@ -0,0 +1,94 @@
|
|
1
|
+
##
|
2
|
+
# Kpeg plugin for hoe.
|
3
|
+
#
|
4
|
+
# === Tasks Provided:
|
5
|
+
#
|
6
|
+
# parser :: Generate parsers for all .kpeg files in your manifest
|
7
|
+
# .kpeg -> .rb rule :: Generate a parser using kpeg.
|
8
|
+
#
|
9
|
+
# NOTE: This plugin is derived from the Hoe::Racc and used under the MIT
|
10
|
+
# license:
|
11
|
+
#
|
12
|
+
# Copyright (c) Ryan Davis, seattle.rb
|
13
|
+
#
|
14
|
+
# Permission is hereby granted, free of charge, to any person obtaining
|
15
|
+
# a copy of this software and associated documentation files (the
|
16
|
+
# "Software"), to deal in the Software without restriction, including
|
17
|
+
# without limitation the rights to use, copy, modify, merge, publish,
|
18
|
+
# distribute, sublicense, and/or sell copies of the Software, and to
|
19
|
+
# permit persons to whom the Software is furnished to do so, subject to
|
20
|
+
# the following conditions:
|
21
|
+
#
|
22
|
+
# The above copyright notice and this permission notice shall be
|
23
|
+
# included in all copies or substantial portions of the Software.
|
24
|
+
#
|
25
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
26
|
+
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
27
|
+
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
28
|
+
# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
29
|
+
# CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
30
|
+
# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
31
|
+
# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
32
|
+
|
33
|
+
module Hoe::Kpeg
|
34
|
+
|
35
|
+
##
|
36
|
+
# Optional: Defines what tasks need to generate parsers first.
|
37
|
+
#
|
38
|
+
# Defaults to [:multi, :test, :check_manifest]
|
39
|
+
#
|
40
|
+
# If you have extra tasks that require your parser to be built, add their
|
41
|
+
# names here in your hoe spec. eg:
|
42
|
+
#
|
43
|
+
# kpeg_tasks << :debug
|
44
|
+
|
45
|
+
attr_accessor :kpeg_tasks
|
46
|
+
|
47
|
+
##
|
48
|
+
# Optional: Defines what flags to use for kpeg. default: "-s -v"
|
49
|
+
|
50
|
+
attr_accessor :kpeg_flags
|
51
|
+
|
52
|
+
##
|
53
|
+
# Initialize variables for kpeg plugin.
|
54
|
+
|
55
|
+
def initialize_kpeg
|
56
|
+
self.kpeg_tasks = [:multi, :test, :check_manifest]
|
57
|
+
|
58
|
+
# -v = verbose
|
59
|
+
# -s = parser does not require runtime
|
60
|
+
self.kpeg_flags ||= "-s -v"
|
61
|
+
|
62
|
+
dependency 'kpeg', '~> 0.9', :development
|
63
|
+
end
|
64
|
+
|
65
|
+
##
|
66
|
+
# Define tasks for kpeg plugin
|
67
|
+
|
68
|
+
def define_kpeg_tasks
|
69
|
+
kpeg_files = self.spec.files.find_all { |f| f =~ /\.kpeg$/ }
|
70
|
+
|
71
|
+
parser_files = kpeg_files.map { |f| f.sub(/\.kpeg$/, ".rb") }
|
72
|
+
|
73
|
+
self.clean_globs += parser_files
|
74
|
+
|
75
|
+
rule ".rb" => ".kpeg" do |t|
|
76
|
+
kpeg = Gem.bin_path "kpeg", "kpeg"
|
77
|
+
|
78
|
+
begin
|
79
|
+
ruby "-rubygems #{kpeg} #{kpeg_flags} -o #{t.name} #{t.source}"
|
80
|
+
rescue
|
81
|
+
abort "need kpeg, please run rake check_extra_deps"
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
desc "build the parser" unless parser_files.empty?
|
86
|
+
task :parser
|
87
|
+
|
88
|
+
task :parser => parser_files
|
89
|
+
|
90
|
+
kpeg_tasks.each do |t|
|
91
|
+
task t => :parser
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
data/lib/kpeg.rb
CHANGED
data/lib/kpeg/code_generator.rb
CHANGED
@@ -323,8 +323,16 @@ module KPeg
|
|
323
323
|
|
324
324
|
def output
|
325
325
|
return @output if @output
|
326
|
+
|
327
|
+
code = []
|
328
|
+
|
329
|
+
if header = @grammar.directives['header']
|
330
|
+
code << header.action.strip
|
331
|
+
code << "\n"
|
332
|
+
end
|
333
|
+
|
326
334
|
if @standalone
|
327
|
-
code
|
335
|
+
code << "class #{@name}\n"
|
328
336
|
|
329
337
|
unless cp = standalone_region(
|
330
338
|
File.expand_path("../compiled_parser.rb", __FILE__))
|
@@ -341,7 +349,7 @@ module KPeg
|
|
341
349
|
cp.gsub!(/include Position/, pp)
|
342
350
|
code << cp << "\n"
|
343
351
|
else
|
344
|
-
code
|
352
|
+
code << "require 'kpeg/compiled_parser'\n\n"
|
345
353
|
code << "class #{@name} < KPeg::CompiledParser\n"
|
346
354
|
end
|
347
355
|
|
@@ -417,7 +425,12 @@ module KPeg
|
|
417
425
|
end
|
418
426
|
|
419
427
|
code << "end\n"
|
420
|
-
|
428
|
+
|
429
|
+
if footer = @grammar.directives['footer']
|
430
|
+
code << footer.action
|
431
|
+
end
|
432
|
+
|
433
|
+
@output = code.join
|
421
434
|
end
|
422
435
|
|
423
436
|
def make(str)
|
data/lib/kpeg/compiled_parser.rb
CHANGED
@@ -183,32 +183,24 @@ module KPeg
|
|
183
183
|
end
|
184
184
|
end
|
185
185
|
|
186
|
-
class LeftRecursive
|
187
|
-
def initialize(detected=false)
|
188
|
-
@detected = detected
|
189
|
-
end
|
190
|
-
|
191
|
-
attr_accessor :detected
|
192
|
-
end
|
193
|
-
|
194
186
|
class MemoEntry
|
195
187
|
def initialize(ans, pos)
|
196
188
|
@ans = ans
|
197
189
|
@pos = pos
|
198
|
-
@uses = 1
|
199
190
|
@result = nil
|
191
|
+
@set = false
|
192
|
+
@left_rec = false
|
200
193
|
end
|
201
194
|
|
202
|
-
attr_reader :ans, :pos, :
|
203
|
-
|
204
|
-
def inc!
|
205
|
-
@uses += 1
|
206
|
-
end
|
195
|
+
attr_reader :ans, :pos, :result, :set
|
196
|
+
attr_accessor :left_rec
|
207
197
|
|
208
198
|
def move!(ans, pos, result)
|
209
199
|
@ans = ans
|
210
200
|
@pos = pos
|
211
201
|
@result = result
|
202
|
+
@set = true
|
203
|
+
@left_rec = false
|
212
204
|
end
|
213
205
|
end
|
214
206
|
|
@@ -236,12 +228,10 @@ module KPeg
|
|
236
228
|
def apply_with_args(rule, *args)
|
237
229
|
memo_key = [rule, args]
|
238
230
|
if m = @memoizations[memo_key][@pos]
|
239
|
-
m.inc!
|
240
|
-
|
241
231
|
prev = @pos
|
242
232
|
@pos = m.pos
|
243
|
-
if m.
|
244
|
-
m.
|
233
|
+
if !m.set
|
234
|
+
m.left_rec = true
|
245
235
|
return nil
|
246
236
|
end
|
247
237
|
|
@@ -249,18 +239,19 @@ module KPeg
|
|
249
239
|
|
250
240
|
return m.ans
|
251
241
|
else
|
252
|
-
|
253
|
-
m = MemoEntry.new(lr, @pos)
|
242
|
+
m = MemoEntry.new(nil, @pos)
|
254
243
|
@memoizations[memo_key][@pos] = m
|
255
244
|
start_pos = @pos
|
256
245
|
|
257
246
|
ans = __send__ rule, *args
|
258
247
|
|
248
|
+
lr = m.left_rec
|
249
|
+
|
259
250
|
m.move! ans, @pos, @result
|
260
251
|
|
261
252
|
# Don't bother trying to grow the left recursion
|
262
253
|
# if it's failing straight away (thus there is no seed)
|
263
|
-
if ans and lr
|
254
|
+
if ans and lr
|
264
255
|
return grow_lr(rule, args, start_pos, m)
|
265
256
|
else
|
266
257
|
return ans
|
@@ -272,12 +263,10 @@ module KPeg
|
|
272
263
|
|
273
264
|
def apply(rule)
|
274
265
|
if m = @memoizations[rule][@pos]
|
275
|
-
m.inc!
|
276
|
-
|
277
266
|
prev = @pos
|
278
267
|
@pos = m.pos
|
279
|
-
if m.
|
280
|
-
m.
|
268
|
+
if !m.set
|
269
|
+
m.left_rec = true
|
281
270
|
return nil
|
282
271
|
end
|
283
272
|
|
@@ -285,18 +274,19 @@ module KPeg
|
|
285
274
|
|
286
275
|
return m.ans
|
287
276
|
else
|
288
|
-
|
289
|
-
m = MemoEntry.new(lr, @pos)
|
277
|
+
m = MemoEntry.new(nil, @pos)
|
290
278
|
@memoizations[rule][@pos] = m
|
291
279
|
start_pos = @pos
|
292
280
|
|
293
281
|
ans = __send__ rule
|
294
282
|
|
283
|
+
lr = m.left_rec
|
284
|
+
|
295
285
|
m.move! ans, @pos, @result
|
296
286
|
|
297
287
|
# Don't bother trying to grow the left recursion
|
298
288
|
# if it's failing straight away (thus there is no seed)
|
299
|
-
if ans and lr
|
289
|
+
if ans and lr
|
300
290
|
return grow_lr(rule, nil, start_pos, m)
|
301
291
|
else
|
302
292
|
return ans
|