Class: Parslet::ErrorReporter::Contextual
- Defined in:
- lib/parslet/error_reporter/contextual.rb
Overview
A reporter that tries to improve on the deepest error reporter by using heuristics to find the most relevant error and provide more context. The heuristic chooses the deepest error when parsing a sequence for which no alternative parsed successfully.
Given the following parser:
root(:call)
rule(:call, label: ‘call’)
identifier >> str('.') >> method
rule(:method, label: ‘method call’)
identifier >> str('(') >> arguments.maybe >> str(')')
rule(:identifier, label: ‘identifier’)
match['[:alnum:]'].repeat(1)
rule(:arguments, label: ‘method call arguments’)
argument >> str(',') >> arguments | argument
rule(:argument)
call | identifier
and the following source:
foo.(a,goo.baz(),c,)
The contextual reporter returns the following causes:
0: Failed to match sequence (identifier ‘.’ method call) at line 1 char 5
when parsing method call arguments.
1: Failed to match sequence (identifier ‘(’ method call arguments? ‘)’) at
line 1 char 22 when parsing method call arguments.
2: Failed to match [[:alnum:]] at line 1 char 23 when parsing method call
arguments.
(where 2 is a child cause of 1 and 1 a child cause of 0)
The last piece used by the reporter is the (newly introduced) ability to attach a label to rules that describe a sequence in the grammar. The labels are used in two places:
- In the "to_s" of Atom::Base so that any error message uses labels to
refer to atoms
- In the cause error messages to give information about which expression
failed to parse
Instance Attribute Summary
Attributes inherited from Deepest
Instance Method Summary collapse
-
#err(atom, source, message, children = nil) ⇒ Cause
Produces an error cause that combines the message at the current level with the errors that happened at a level below (children).
-
#initialize ⇒ Contextual
constructor
A new instance of Contextual.
-
#reset ⇒ Object
Reset deepest error and its position and sequence index.
-
#succ(source) ⇒ Object
A sequence expression successfully parsed, reset all errors reported for previous expressions in the sequence (an alternative matched) Only reset errors if the position of the source that matched is higher than the position of the source that was last successful (so we keep errors that are the “deepest” but for which no alternative succeeded).
-
#update_label(label, bytepos) ⇒ Object
Update error message label if given label is more relevant.
Methods inherited from Deepest
Constructor Details
#initialize ⇒ Contextual
Returns a new instance of Contextual.
59 60 61 62 |
# File 'lib/parslet/error_reporter/contextual.rb', line 59 def initialize @last_reset_pos = 0 reset end |
Instance Method Details
#err(atom, source, message, children = nil) ⇒ Cause
Produces an error cause that combines the message at the current level with the errors that happened at a level below (children). Compute and set label used by Cause to produce error message.
95 96 97 98 99 100 101 102 |
# File 'lib/parslet/error_reporter/contextual.rb', line 95 def err(atom, source, , children=nil) cause = super(atom, source, , children) if (label = atom.respond_to?(:label) && atom.label) update_label(label, source.pos.bytepos) cause.set_label(@label) end cause end |
#reset ⇒ Object
Reset deepest error and its position and sequence index
79 80 81 82 |
# File 'lib/parslet/error_reporter/contextual.rb', line 79 def reset @deepest_cause = nil @label_pos = -1 end |
#succ(source) ⇒ Object
A sequence expression successfully parsed, reset all errors reported for previous expressions in the sequence (an alternative matched) Only reset errors if the position of the source that matched is higher than the position of the source that was last successful (so we keep errors that are the “deepest” but for which no alternative succeeded)
70 71 72 73 74 75 |
# File 'lib/parslet/error_reporter/contextual.rb', line 70 def succ(source) source_pos = source.pos.bytepos return if source_pos < @last_reset_pos @last_reset_pos = source_pos reset end |
#update_label(label, bytepos) ⇒ Object
Update error message label if given label is more relevant. A label is more relevant if the position of the matched source is bigger.
111 112 113 114 115 116 |
# File 'lib/parslet/error_reporter/contextual.rb', line 111 def update_label(label, bytepos) if bytepos >= @label_pos @label_pos = bytepos @label = label end end |