Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
+ Reenables the cache - now Context has a spec
- Loading branch information
Showing
5 changed files
with
107 additions
and
63 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
|
||
# Helper class that implements a transient cache that maps position and | ||
# parslet object to results. | ||
# | ||
class Parslet::Atoms::Context | ||
def initialize | ||
@cache = Hash.new | ||
end | ||
|
||
# Caches a parse answer for obj at source.pos. Applying the same parslet | ||
# at one position of input always yields the same result, unless the input | ||
# has changed. | ||
# | ||
# We need the entire source here so we can ask for how many characters | ||
# were consumed by a successful parse. Imitation of such a parse must | ||
# advance the input pos by the same amount of bytes. | ||
# | ||
def cache(obj, source, &block) | ||
beg = source.pos | ||
|
||
# Not in cache yet? Return early. | ||
unless entry = lookup(obj, beg) | ||
message = catch(:error) { | ||
result = yield | ||
set obj, beg, [true, result, source.pos-beg] | ||
return result | ||
} | ||
|
||
set obj, beg, [false, message, source.pos-beg] | ||
throw :error, message | ||
end | ||
|
||
# the condition in unless has returned true, so entry is not nil. | ||
success, obj, advance = entry | ||
|
||
source.read(advance) | ||
|
||
throw :error, obj unless success | ||
return obj | ||
end | ||
|
||
class Item | ||
attr_reader :obj, :pos | ||
def initialize(obj, pos) | ||
@obj, @pos = obj, pos | ||
end | ||
def hash | ||
@obj.hash - @pos | ||
end | ||
def eql?(o) | ||
o.obj == self.obj && o.pos == self.pos | ||
end | ||
end | ||
|
||
private | ||
def lookup(obj, pos) | ||
i = Item.new(obj, pos) | ||
@cache[i] | ||
end | ||
def set(obj, pos, val) | ||
i = Item.new(obj, pos) | ||
@cache[i] = val | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
require 'spec_helper' | ||
|
||
require 'stringio' | ||
|
||
describe Parslet::Atoms::Context do | ||
let(:source) { StringIO.new('foobar') } | ||
|
||
context "when clean" do | ||
it "should return whatever the block returns" do | ||
subject.cache(self, source) { 1 }.should == 1 | ||
end | ||
it "should rethrow :error" do | ||
lambda { | ||
subject.cache(self, source) { throw :error, 'foo' } | ||
}.should throw_symbol(:error, 'foo') | ||
end | ||
end | ||
context "when already called for obj and input position" do | ||
context "(storing success, 1)" do | ||
before(:each) { subject.cache(self, source) { 1 } } | ||
|
||
it "should return cached result" do | ||
subject.cache(self, source) { 2 }.should == 1 | ||
end | ||
end | ||
context "(storing error, 'foo')" do | ||
before(:each) { catch(:error) { | ||
subject.cache(self, source) { throw :error, 'foo' }} } | ||
|
||
it "should return cached result" do | ||
lambda { | ||
subject.cache(self, source) { 2 } | ||
}.should throw_symbol(:error, 'foo') | ||
end | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters