Class: Parslet::Atoms::Base
- Inherits:
-
Object
- Object
- Parslet::Atoms::Base
- Includes:
- CanFlatten, DSL, Precedence
- Defined in:
- lib/parslet/atoms/base.rb,
lib/parslet/convenience.rb,
lib/parslet/atoms/visitor.rb
Overview
Base class for all parslets, handles orchestration of calls and implements a lot of the operator and chaining methods.
Also see Parslet::Atoms::DSL chaining parslet atoms together.
Direct Known Subclasses
Alternative, Capture, Dynamic, Entity, Ignored, Infix, Lookahead, Named, Re, Repetition, Scope, Sequence, Str, Parser
Constant Summary
Constants included from Precedence
Precedence::ALTERNATE, Precedence::BASE, Precedence::LOOKAHEAD, Precedence::OUTER, Precedence::REPETITION, Precedence::SEQUENCE
Instance Attribute Summary collapse
-
#label ⇒ Object
Parslet label as provided in grammar.
Class Method Summary collapse
-
.precedence(prec) ⇒ Object
Debug printing - in Treetop syntax.
Instance Method Summary collapse
- #accept(visitor) ⇒ Object
-
#apply(source, context, consume_all = false) ⇒ Object
Calls the #try method of this parslet.
-
#cached? ⇒ Boolean
Returns true if this atom can be cached in the packrat cache.
- #inspect ⇒ Object
-
#parse(io, options = {}) ⇒ Hash, ...
Given a string or an IO object, this will attempt a parse of its contents and return a result.
-
#parse_with_debug(str, opts = {}) ⇒ Object
Packages the common idiom begin tree = parser.parse(‘something’) rescue Parslet::ParseFailed => error puts parser.parse_failure_cause.ascii_tree end.
-
#setup_and_apply(source, error_reporter, consume_all) ⇒ <Boolean, Object>
Creates a context for parsing and applies the current atom to the input.
- #to_s(outer_prec = OUTER) ⇒ Object
-
#try(source, context, consume_all) ⇒ Object
Override this in your Atoms::Base subclasses to implement parsing behaviour.
Methods included from CanFlatten
#flatten, #flatten_repetition, #flatten_sequence, #foldl, #merge_fold, #warn_about_duplicate_keys
Methods included from DSL
#>>, #absent?, #as, #capture, #ignore, #maybe, #present?, #repeat, #|
Instance Attribute Details
#label ⇒ Object
Parslet label as provided in grammar
12 13 14 |
# File 'lib/parslet/atoms/base.rb', line 12 def label @label end |
Class Method Details
.precedence(prec) ⇒ Object
Debug printing - in Treetop syntax.
135 136 137 |
# File 'lib/parslet/atoms/base.rb', line 135 def self.precedence(prec) define_method(:precedence) { prec } end |
Instance Method Details
#accept(visitor) ⇒ Object
7 8 9 |
# File 'lib/parslet/atoms/visitor.rb', line 7 def accept(visitor) raise NotImplementedError, "No #accept method on #{self.class.name}." end |
#apply(source, context, consume_all = false) ⇒ Object
Calls the #try method of this parslet. Success consumes input, error will rewind the input.
@param context [Parslet::Atoms::Context] context to use for the parsing
83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 |
# File 'lib/parslet/atoms/base.rb', line 83 def apply(source, context, consume_all=false) old_pos = source.bytepos success, _ = result = context.try_with_cache(self, source, consume_all) if success # Notify context context.succ(source) # If a consume_all parse was made and doesn't result in the consumption # of all the input, that is considered an error. if consume_all && source.chars_left>0 # Read 10 characters ahead. Why ten? I don't know. offending_pos = source.pos offending_input = source.consume(10) # Rewind input (as happens always in error case) source.bytepos = old_pos return context.err_at( self, source, "Don't know what to do with #{offending_input.to_s.inspect}", offending_pos ) end # Looks like the parse was successful after all. Don't rewind the input. return result end # We only reach this point if the parse has failed. Rewind the input. source.bytepos = old_pos return result end |
#cached? ⇒ Boolean
Returns true if this atom can be cached in the packrat cache. Most parslet atoms are cached, so this always returns true, unless overridden.
129 130 131 |
# File 'lib/parslet/atoms/base.rb', line 129 def cached? true end |
#inspect ⇒ Object
147 148 149 |
# File 'lib/parslet/atoms/base.rb', line 147 def inspect to_s(OUTER) end |
#parse(io, options = {}) ⇒ Hash, ...
Given a string or an IO object, this will attempt a parse of its contents and return a result. If the parse fails, a Parslet::ParseFailed exception will be thrown.
26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 |
# File 'lib/parslet/atoms/base.rb', line 26 def parse(io, ={}) source = io.respond_to?(:line_and_column) ? io : Parslet::Source.new(io) # Try to cheat. Assuming that we'll be able to parse the input, don't # run error reporting code. success, value = setup_and_apply(source, nil, ![:prefix]) # 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 # it failed. unless success # Cheating has not paid off. Now pay the cost: Rerun the parse, # gathering error information in the process. reporter = [:reporter] || Parslet::ErrorReporter::Tree.new source.bytepos = 0 success, value = setup_and_apply(source, reporter, ![:prefix]) fail "Assertion failed: success was true when parsing with reporter" \ if success # Value is a Parslet::Cause, which can be turned into an exception: value.raise fail "NEVER REACHED" end # assert: success is true # Extra input is now handled inline with the rest of the parsing. If # really we have success == true, prefix: false and still some input # is left dangling, that is a BUG. if ![:prefix] && source.chars_left > 0 fail "BUG: New error strategy should not reach this point." end return flatten(value) end |
#parse_with_debug(str, opts = {}) ⇒ Object
Packages the common idiom
begin
tree = parser.parse('something')
rescue Parslet::ParseFailed => error
puts parser.parse_failure_cause.ascii_tree
end
into a convenient method.
Usage:
require 'parslet'
require 'parslet/convenience'
class FooParser < Parslet::Parser
rule(:foo) { str('foo') }
root(:foo)
end
FooParser.new.parse_with_debug('bar')
27 28 29 30 31 |
# File 'lib/parslet/convenience.rb', line 27 def parse_with_debug str, opts={} parse str, opts rescue Parslet::ParseFailed => error puts error.parse_failure_cause.ascii_tree end |
#setup_and_apply(source, error_reporter, consume_all) ⇒ <Boolean, Object>
Creates a context for parsing and applies the current atom to the input. Returns the parse result.
71 72 73 74 |
# File 'lib/parslet/atoms/base.rb', line 71 def setup_and_apply(source, error_reporter, consume_all) context = Parslet::Atoms::Context.new(error_reporter) apply(source, context, consume_all) end |
#to_s(outer_prec = OUTER) ⇒ Object
139 140 141 142 143 144 145 146 |
# File 'lib/parslet/atoms/base.rb', line 139 def to_s(outer_prec=OUTER) str = label || to_s_inner(precedence) if outer_prec < precedence "(#{str})" else str end end |
#try(source, context, consume_all) ⇒ Object
Override this in your Atoms::Base subclasses to implement parsing behaviour.
121 122 123 124 |
# File 'lib/parslet/atoms/base.rb', line 121 def try(source, context, consume_all) raise NotImplementedError, \ "Atoms::Base doesn't have behaviour, please implement #try(source, context)." end |