Skip to content

Commit

Permalink
get rid of Context
Browse files Browse the repository at this point in the history
Since the source is already getting passed around, let's put the memoization cache into it.

Planning to store more in the source.
  • Loading branch information
jmettraux committed Apr 15, 2012
1 parent 569d43f commit dc279b4
Show file tree
Hide file tree
Showing 17 changed files with 94 additions and 124 deletions.
4 changes: 2 additions & 2 deletions example/ignore.rb
Expand Up @@ -10,8 +10,8 @@ def initialize(parslet)
def to_s_inner(prec)
@parslet.to_s(prec)
end
def try(source, context)
result = @parslet.try(source, context)
def try(source)
result = @parslet.try(source)

return success(nil) unless result.error?
return result
Expand Down
24 changes: 12 additions & 12 deletions experiments/heredoc.rb
Expand Up @@ -29,18 +29,18 @@ def initialize(parslet, name)
@parslet, @name = parslet, name
end

def try(source, context) # :nodoc:
parslet.try(source, context).tap { |result|
set_binding(context, name,
def try(source) # :nodoc:
parslet.try(source).tap { |result|
set_binding(source, name,
flatten(result.result))
}
end

def set_binding(context, name, value)
b = context.instance_variable_get('@bindings') || {}
def set_binding(source, name, value)
b = source.instance_variable_get('@bindings') || {}
b.store name, value
p b
context.instance_variable_set('@bindings', b)
source.instance_variable_set('@bindings', b)
end

def to_s_inner(prec) # :nodoc:
Expand All @@ -55,22 +55,22 @@ def initialize(parslet, name)
@parslet, @name = parslet, name
end

def try(source, context) # :nodoc:
parslet.try(source, context).tap { |result|
def try(source) # :nodoc:
parslet.try(source).tap { |result|
unless result.error?
value = flatten(result.result)

p [value, bound_value(context, name), value == bound_value(context, name)]
unless value == bound_value(context, name)
p [value, bound_value(source, name), value == bound_value(source, name)]
unless value == bound_value(source, name)
p :error_return
return error(source, "Bound value doesn't match.")
end
end
}
end

def bound_value(context, name)
b = context.instance_variable_get('@bindings') || {}
def bound_value(source, name)
b = source.instance_variable_get('@bindings') || {}
b[name]
end

Expand Down
1 change: 0 additions & 1 deletion lib/parslet/atoms.rb
Expand Up @@ -16,7 +16,6 @@ module Precedence # :nodoc:
end

require 'parslet/atoms/can_flatten'
require 'parslet/atoms/context'
require 'parslet/atoms/dsl'
require 'parslet/atoms/base'
require 'parslet/atoms/named'
Expand Down
4 changes: 2 additions & 2 deletions lib/parslet/atoms/alternative.rb
Expand Up @@ -30,9 +30,9 @@ def |(parslet) # :nodoc:
self.class.new(*@alternatives + [parslet])
end

def try(source, context) # :nodoc:
def try(source) # :nodoc:
alternatives.each { |a|
value = a.apply(source, context)
value = a.apply(source)
return value unless value.error?
}
# If we reach this point, all alternatives have failed.
Expand Down
15 changes: 5 additions & 10 deletions lib/parslet/atoms/base.rb
Expand Up @@ -31,10 +31,8 @@ def parse(io, prefix_parse=false)
io :
Parslet::Source.new(io)

context = Parslet::Atoms::Context.new

result = nil
value = apply(source, context)
value = apply(source)

# If we didn't succeed the parse, raise an exception for the user.
# Stack trace will be off, but the error tree should explain the reason
Expand Down Expand Up @@ -72,12 +70,10 @@ def parse(io, prefix_parse=false)
# Calls the #try method of this parslet. In case of a parse error, apply
# leaves the source in the state it was before the attempt.
#+++
def apply(source, context) # :nodoc:
def apply(source) # :nodoc:
old_pos = source.pos

result = context.cache(self, source) {
try(source, context)
}
result = source.try(self)

# This has just succeeded, so last_cause must be empty
unless result.error?
Expand All @@ -93,12 +89,11 @@ def apply(source, context) # :nodoc:
# Override this in your Atoms::Base subclasses to implement parsing
# behaviour.
#
def try(source, context)
def try(source)
raise NotImplementedError, \
"Atoms::Base doesn't have behaviour, please implement #try(source, context)."
"Atoms::Base doesn't have behaviour, please implement #try(source)."
end


# Debug printing - in Treetop syntax.
#
def self.precedence(prec) # :nodoc:
Expand Down
48 changes: 0 additions & 48 deletions lib/parslet/atoms/context.rb

This file was deleted.

4 changes: 2 additions & 2 deletions lib/parslet/atoms/entity.rb
Expand Up @@ -17,8 +17,8 @@ def initialize(name, &block) # :nodoc:
@block = block
end

def try(source, context) # :nodoc:
parslet.apply(source, context)
def try(source) # :nodoc:
parslet.apply(source)
end

def parslet
Expand Down
4 changes: 2 additions & 2 deletions lib/parslet/atoms/lookahead.rb
Expand Up @@ -21,10 +21,10 @@ def initialize(bound_parslet, positive=true) # :nodoc:
}
end

def try(source, context) # :nodoc:
def try(source) # :nodoc:
pos = source.pos

value = bound_parslet.apply(source, context)
value = bound_parslet.apply(source)
return success(nil) if positive ^ value.error?

return error(source, @error_msgs[:positive], pos) if positive
Expand Down
4 changes: 2 additions & 2 deletions lib/parslet/atoms/named.rb
Expand Up @@ -13,8 +13,8 @@ def initialize(parslet, name) # :nodoc:
@parslet, @name = parslet, name
end

def apply(source, context) # :nodoc:
value = parslet.apply(source, context)
def apply(source) # :nodoc:
value = parslet.apply(source)

return value if value.error?
success(
Expand Down
2 changes: 1 addition & 1 deletion lib/parslet/atoms/re.rb
Expand Up @@ -20,7 +20,7 @@ def initialize(match) # :nodoc:
}
end

def try(source, context) # :nodoc:
def try(source) # :nodoc:
error_pos = source.pos
s = source.read(1)

Expand Down
4 changes: 2 additions & 2 deletions lib/parslet/atoms/repetition.rb
Expand Up @@ -19,12 +19,12 @@ def initialize(parslet, min, max, tag=:repetition)
}
end

def try(source, context) # :nodoc:
def try(source) # :nodoc:
occ = 0
result = [@tag] # initialize the result array with the tag (for flattening)
start_pos = source.pos
loop do
value = parslet.apply(source, context)
value = parslet.apply(source)
break if value.error?

occ += 1
Expand Down
4 changes: 2 additions & 2 deletions lib/parslet/atoms/sequence.rb
Expand Up @@ -19,12 +19,12 @@ def >>(parslet) # :nodoc:
self.class.new(* @parslets+[parslet])
end

def try(source, context) # :nodoc:
def try(source) # :nodoc:
success([:sequence]+parslets.map { |p|
# Save each parslet as potentially offending (raising an error).
@offending_parslet = p

value = p.apply(source, context)
value = p.apply(source)

return error(source, @error_msgs[:failed]) if value.error?

Expand Down
2 changes: 1 addition & 1 deletion lib/parslet/atoms/str.rb
Expand Up @@ -16,7 +16,7 @@ def initialize(str)
}
end

def try(source, context) # :nodoc:
def try(source) # :nodoc:
# NOTE: Even though it doesn't look that way, this is the hotspot, the
# contents of parslets inner loop. Changes here affect parslets speed
# enormously.
Expand Down
4 changes: 2 additions & 2 deletions lib/parslet/parser.rb
Expand Up @@ -57,8 +57,8 @@ def root(name)
end
end

def try(source, context) # :nodoc:
root.try(source, context)
def try(source) # :nodoc:
root.try(source)
end

def error_tree # :nodoc:
Expand Down
26 changes: 26 additions & 0 deletions lib/parslet/source.rb
Expand Up @@ -16,6 +16,32 @@ def initialize(io)

@io = io
@line_cache = LineCache.new

@memo_cache = Hash.new { |h, k| h[k] = {} }
end

# Wrapping atom.try(source) in a memoizing embrace.
#
def try(atom)
beg = self.pos

# Not in cache yet? Return early.
unless entry = @memo_cache[beg][atom]
result = atom.try(self)

@memo_cache[beg][atom] = [result, self.pos - beg]
return result
end

# the condition in unless has returned true, so entry is not nil.
result, advance = entry

# The data we're skipping here has been read before. (since it is in
# the cache) PLUS the actual contents are not interesting anymore since
# we know atom matches at beg. So skip reading.
self.pos = beg + advance

result
end

# Reads n bytes from the input and returns a Range instance. If the n
Expand Down

0 comments on commit dc279b4

Please sign in to comment.