50 lines
1.3 KiB
Ruby
50 lines
1.3 KiB
Ruby
# Either positive or negative lookahead, doesn't consume its input.
|
|
#
|
|
# Example:
|
|
#
|
|
# str('foo').present? # matches when the input contains 'foo', but leaves it
|
|
#
|
|
class Parslet::Atoms::Lookahead < Parslet::Atoms::Base
|
|
attr_reader :positive
|
|
attr_reader :bound_parslet
|
|
|
|
def initialize(bound_parslet, positive=true)
|
|
super()
|
|
|
|
# Model positive and negative lookahead by testing this flag.
|
|
@positive = positive
|
|
@bound_parslet = bound_parslet
|
|
|
|
@error_msgs = {
|
|
:positive => ["Input should start with ", bound_parslet],
|
|
:negative => ["Input should not start with ", bound_parslet]
|
|
}
|
|
end
|
|
|
|
def try(source, context, consume_all)
|
|
pos = source.pos
|
|
|
|
success, value = bound_parslet.apply(source, context, consume_all)
|
|
|
|
if positive
|
|
return succ(nil) if success
|
|
return context.err_at(self, source, @error_msgs[:positive], pos)
|
|
else
|
|
return succ(nil) unless success
|
|
return context.err_at(self, source, @error_msgs[:negative], pos)
|
|
end
|
|
|
|
# This is probably the only parslet that rewinds its input in #try.
|
|
# Lookaheads NEVER consume their input, even on success, that's why.
|
|
ensure
|
|
source.pos = pos
|
|
end
|
|
|
|
precedence LOOKAHEAD
|
|
def to_s_inner(prec)
|
|
char = positive ? '&' : '!'
|
|
|
|
"#{char}#{bound_parslet.to_s(prec)}"
|
|
end
|
|
end
|