Skip to content

Commit

Permalink
Merge pull request #155 from ydah/improve-error-message
Browse files Browse the repository at this point in the history
Improve an error message for ParseError
  • Loading branch information
yui-knk authored Oct 24, 2023
2 parents 5072479 + cc8e4b0 commit d0595b0
Show file tree
Hide file tree
Showing 8 changed files with 77 additions and 56 deletions.
2 changes: 1 addition & 1 deletion lib/lrama/command.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ def run(argv)
warning = Lrama::Warning.new
text = options.y.read
options.y.close if options.y != STDIN
grammar = Lrama::Parser.new(text).parse
grammar = Lrama::Parser.new(text, options.grammar_file).parse
states = Lrama::States.new(grammar, warning, trace_state: (options.trace_opts[:automaton] || options.trace_opts[:closure]))
states.compute
context = Lrama::Context.new(states)
Expand Down
11 changes: 8 additions & 3 deletions lib/lrama/parser.rb

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

11 changes: 8 additions & 3 deletions parser.y
Original file line number Diff line number Diff line change
Expand Up @@ -387,8 +387,9 @@ end

include Lrama::Report::Duration

def initialize(text)
def initialize(text, path)
@text = text
@path = path
end

def parse
Expand All @@ -411,6 +412,10 @@ def next_token
end

def on_error(error_token_id, error_value, value_stack)
raise ParseError, sprintf("\n%d:%d: parse error on value %s (%s)",
@lexer.line, @lexer.column, error_value.inspect, token_to_str(error_token_id) || '?')
source = @text.split("\n")[error_value.line - 1]
raise ParseError, <<~ERROR
#{@path}:#{@lexer.line}:#{@lexer.column}: parse error on value #{error_value.inspect} (#{token_to_str(error_token_id) || '?'})
#{source}
#{' ' * @lexer.column}^
ERROR
end
9 changes: 5 additions & 4 deletions spec/lrama/context_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@

describe "basic" do
it do
y = File.read(fixture_path("context/basic.y"))
grammar = Lrama::Parser.new(y).parse
path = "context/basic.y"
y = File.read(fixture_path(path))
grammar = Lrama::Parser.new(y, path).parse
states = Lrama::States.new(grammar, warning)
states.compute
context = Lrama::Context.new(states)
Expand Down Expand Up @@ -181,7 +182,7 @@
%%
INPUT

grammar = Lrama::Parser.new(y).parse
grammar = Lrama::Parser.new(y, "parse.y").parse
states = Lrama::States.new(grammar, warning)
states.compute
context = Lrama::Context.new(states)
Expand Down Expand Up @@ -230,7 +231,7 @@
%%
INPUT

grammar = Lrama::Parser.new(y).parse
grammar = Lrama::Parser.new(y, "parse.y").parse
states = Lrama::States.new(grammar, warning)
states.compute
context = Lrama::Context.new(states)
Expand Down
8 changes: 4 additions & 4 deletions spec/lrama/counterexamples_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@
end

it "build counterexamples of S/R conflicts" do
grammar = Lrama::Parser.new(y).parse
grammar = Lrama::Parser.new(y, "parse.y").parse
states = Lrama::States.new(grammar, warning)
states.compute
counterexamples = Lrama::Counterexamples.new(states)
Expand Down Expand Up @@ -249,7 +249,7 @@
end

it "build counterexamples of R/R conflicts" do
grammar = Lrama::Parser.new(y).parse
grammar = Lrama::Parser.new(y, "parse.y").parse
states = Lrama::States.new(grammar, warning)
states.compute
counterexamples = Lrama::Counterexamples.new(states)
Expand Down Expand Up @@ -326,7 +326,7 @@
end

it "build counterexamples of S/R conflicts" do
grammar = Lrama::Parser.new(y).parse
grammar = Lrama::Parser.new(y, "parse.y").parse
states = Lrama::States.new(grammar, warning)
states.compute
counterexamples = Lrama::Counterexamples.new(states)
Expand Down Expand Up @@ -407,7 +407,7 @@
end

it "build counterexamples of S/R and R/R conflicts" do
grammar = Lrama::Parser.new(y).parse
grammar = Lrama::Parser.new(y, "parse.y").parse
states = Lrama::States.new(grammar, warning)
states.compute
counterexamples = Lrama::Counterexamples.new(states)
Expand Down
2 changes: 1 addition & 1 deletion spec/lrama/output_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
let(:header_out) { StringIO.new }
let(:warning) { Lrama::Warning.new(StringIO.new) } # suppress warnings
let(:text) { File.read(grammar_file_path) }
let(:grammar) { Lrama::Parser.new(text).parse }
let(:grammar) { Lrama::Parser.new(text, grammar_file_path).parse }
let(:states) { s = Lrama::States.new(grammar, warning); s.compute; s }
let(:context) { Lrama::Context.new(states) }
let(:grammar_file_path) { fixture_path("common/basic.y") }
Expand Down
50 changes: 28 additions & 22 deletions spec/lrama/parser_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,9 @@

describe '#parse' do
it "basic" do
y = File.read(fixture_path("common/basic.y"))
grammar = Lrama::Parser.new(y).parse
path = "common/basic.y"
y = File.read(fixture_path(path))
grammar = Lrama::Parser.new(y, path).parse

expect(grammar.union.code.s_value).to eq(<<-CODE.chomp)
Expand Down Expand Up @@ -407,8 +408,9 @@
end

it "nullable" do
y = File.read(fixture_path("common/nullable.y"))
grammar = Lrama::Parser.new(y).parse
path = "common/nullable.y"
y = File.read(fixture_path(path))
grammar = Lrama::Parser.new(y, path).parse

expect(grammar.nterms.sort_by(&:number)).to eq([
Sym.new(id: T.new(type: T::Ident, s_value: "$accept"), alias_name: nil, number: 6, tag: nil, term: false, token_id: 0, nullable: false),
Expand Down Expand Up @@ -562,7 +564,7 @@ class : keyword_class tSTRING keyword_end { code 1 }
%%
INPUT

grammar = Lrama::Parser.new(y).parse
grammar = Lrama::Parser.new(y, "parse.y").parse

expect(grammar._rules).to eq([
[
Expand Down Expand Up @@ -605,7 +607,7 @@ class : keyword_class tSTRING keyword_end { code 1 }
%%
INPUT
grammar = Lrama::Parser.new(y).parse
grammar = Lrama::Parser.new(y, "parse.y").parse

expect(grammar.terms.sort_by(&:number)).to eq([
Sym.new(id: T.new(type: T::Ident, s_value: "EOI"), alias_name: "\"EOI\"", number: 0, tag: nil, term: true, token_id: 0, nullable: false, precedence: nil),
Expand Down Expand Up @@ -661,7 +663,7 @@ class : keyword_class { code 1 } tSTRING { code 2 } keyword_end { code 3 }
%%
INPUT
grammar = Lrama::Parser.new(y).parse
grammar = Lrama::Parser.new(y, "parse.y").parse

expect(grammar.nterms.sort_by(&:number)).to eq([
Sym.new(id: T.new(type: T::Ident, s_value: "$accept"), alias_name: nil, number: 11, tag: nil, term: false, token_id: 0, nullable: false),
Expand Down Expand Up @@ -756,7 +758,7 @@ class : keyword_class tSTRING %prec tPLUS keyword_end { code 1 }
%%
INPUT
parser = Lrama::Parser.new(y)
parser = Lrama::Parser.new(y, "parse.y")

expect { parser.parse }.to raise_error("Ident after %prec")
end
Expand All @@ -773,7 +775,7 @@ class : keyword_class { code 2 } tSTRING %prec "=" '!' keyword_end { code 3 }
%%
INPUT
parser = Lrama::Parser.new(y)
parser = Lrama::Parser.new(y, "parse.y")

expect { parser.parse }.to raise_error("Char after %prec")
end
Expand All @@ -790,7 +792,7 @@ class : keyword_class { code 4 } tSTRING '?' keyword_end %prec tEQ { code 5 } {
%%
INPUT
parser = Lrama::Parser.new(y)
parser = Lrama::Parser.new(y, "parse.y")

expect { parser.parse }.to raise_error("Multiple User_code after %prec")
end
Expand All @@ -811,7 +813,7 @@ class : keyword_class
%%
INPUT
grammar = Lrama::Parser.new(y).parse
grammar = Lrama::Parser.new(y, "parse.y").parse
codes = grammar.rules.map(&:code).compact

expect(codes.count).to eq(1)
Expand All @@ -838,7 +840,7 @@ class : keyword_class
%%
INPUT
grammar = Lrama::Parser.new(y).parse
grammar = Lrama::Parser.new(y, "parse.y").parse
codes = grammar.rules.map(&:code).compact

expect(codes.count).to eq(1)
Expand Down Expand Up @@ -883,7 +885,7 @@ class : keyword_class tSTRING keyword_end { code 1 }
%%
INPUT
grammar = Lrama::Parser.new(y).parse
grammar = Lrama::Parser.new(y, "parse.y").parse

expect(grammar.terms.sort_by(&:number)).to eq([
Sym.new(id: T.new(type: T::Ident, s_value: "EOI"), alias_name: "\"EOI\"", number: 0, tag: nil, term: true, token_id: 0, nullable: false),
Expand Down Expand Up @@ -932,7 +934,7 @@ class : keyword_class tSTRING keyword_end { code 1 }
%%
INPUT
grammar = Lrama::Parser.new(y).parse
grammar = Lrama::Parser.new(y, "parse.y").parse

expect(grammar.terms.sort_by(&:number)).to eq([
Sym.new(id: T.new(type: T::Ident, s_value: "EOI"), alias_name: "\"EOI\"", number: 0, tag: nil, term: true, token_id: 0, nullable: false, precedence: nil),
Expand Down Expand Up @@ -978,7 +980,7 @@ class : keyword_class tSTRING keyword_end { code 1 }
;
%%
INPUT
grammar = Lrama::Parser.new(y).parse
grammar = Lrama::Parser.new(y, "parse.y").parse

expect(grammar.rules).to eq([
Rule.new(
Expand Down Expand Up @@ -1086,7 +1088,7 @@ class : keyword_class tSTRING keyword_end { code 1 }
;
%%
INPUT
grammar = Lrama::Parser.new(y).parse
grammar = Lrama::Parser.new(y, "parse.y").parse

expect(grammar.rules).to eq([
Rule.new(
Expand Down Expand Up @@ -1177,7 +1179,7 @@ class : keyword_class tSTRING keyword_end { code 1 }
{ $$ = $1 - $2; }
;
INPUT
grammar = Lrama::Parser.new(y).parse
grammar = Lrama::Parser.new(y, "parse.y").parse

expect(grammar.rules).to eq([
Rule.new(
Expand Down Expand Up @@ -1311,7 +1313,7 @@ class : keyword_class tSTRING keyword_end { code 1 }
;
INPUT

expect { Lrama::Parser.new(y).parse }.to raise_error("'results' is invalid name.")
expect { Lrama::Parser.new(y, "parse.y").parse }.to raise_error("'results' is invalid name.")
end
end
end
Expand All @@ -1332,7 +1334,11 @@ class : keyword_class tSTRING keyword_end { code 1 }
;
INPUT

expect { Lrama::Parser.new(y).parse }.to raise_error(/5:14: parse error/)
expect { Lrama::Parser.new(y, "error_messages/parse.y").parse }.to raise_error(<<~ERROR)
error_messages/parse.y:5:14: parse error on value #<struct Lrama::Lexer::Token type=#<struct Lrama::Lexer::Token::Type id=19, name="Ident">, s_value="invalid", alias=nil> (IDENTIFIER)
%expect invalid
^
ERROR
end
end
end
Expand Down Expand Up @@ -1367,7 +1373,7 @@ class : keyword_class tSTRING keyword_end ;
%%
INPUT
grammar = Lrama::Parser.new(y).parse
grammar = Lrama::Parser.new(y, "parse.y").parse
terms = grammar.terms.sort_by(&:number).map do |term|
[term.id.s_value, term.token_id]
end
Expand Down Expand Up @@ -1416,7 +1422,7 @@ class : keyword_class tSTRING keyword_end
%%
INPUT
grammar = Lrama::Parser.new(y).parse
grammar = Lrama::Parser.new(y, "parse.y").parse
codes = grammar.rules.map(&:code)

expect(codes.count).to eq(3)
Expand Down Expand Up @@ -1463,7 +1469,7 @@ class : keyword_class tSTRING keyword_end
%%
INPUT

expect { Lrama::Parser.new(y).parse }.to raise_error(RuntimeError) do |e|
expect { Lrama::Parser.new(y, "parse.y").parse }.to raise_error(RuntimeError) do |e|
expect(e.message).to eq(<<~MSG.chomp)
$$ of 'stmt' has no declared type
$1 of 'stmt' has no declared type
Expand Down
Loading

0 comments on commit d0595b0

Please sign in to comment.