From c9ec72a783cb3e0f26ad57978fed977dc0ddadf4 Mon Sep 17 00:00:00 2001 From: yui-knk Date: Sun, 5 Nov 2023 09:29:14 +0900 Subject: [PATCH 1/2] Specify error object class --- spec/lrama/parser_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/lrama/parser_spec.rb b/spec/lrama/parser_spec.rb index 594123f8..26d2d5fa 100644 --- a/spec/lrama/parser_spec.rb +++ b/spec/lrama/parser_spec.rb @@ -1510,7 +1510,7 @@ class : keyword_class tSTRING keyword_end { code 1 } program: /* empty */ ; INPUT - expect { Lrama::Parser.new(y, "error_messages/parse.y").parse }.to raise_error(<<~ERROR) + expect { Lrama::Parser.new(y, "error_messages/parse.y").parse }.to raise_error(ParseError, <<~ERROR) error_messages/parse.y:5:7: parse error on value # (IDENTIFIER) %expect invalid ^^^^^^^ From 7c172150f4ae5e5e8d9920e990bc85fce9911176 Mon Sep 17 00:00:00 2001 From: yui-knk Date: Sun, 5 Nov 2023 09:33:12 +0900 Subject: [PATCH 2/2] Use lexer's location when error_value has no location information --- lib/lrama/lexer.rb | 1 + lib/lrama/parser.rb | 18 +++++++++++++----- parser.y | 18 +++++++++++++----- spec/lrama/parser_spec.rb | 40 +++++++++++++++++++++++++++++++-------- 4 files changed, 59 insertions(+), 18 deletions(-) diff --git a/lib/lrama/lexer.rb b/lib/lrama/lexer.rb index 1aa5e297..870d087b 100644 --- a/lib/lrama/lexer.rb +++ b/lib/lrama/lexer.rb @@ -3,6 +3,7 @@ module Lrama class Lexer + attr_reader :head_line, :head_column attr_accessor :status attr_accessor :end_symbol diff --git a/lib/lrama/parser.rb b/lib/lrama/parser.rb index a1713a0a..3afe3725 100644 --- a/lib/lrama/parser.rb +++ b/lib/lrama/parser.rb @@ -688,10 +688,18 @@ def next_token end def on_error(error_token_id, error_value, value_stack) + if error_value.respond_to?(:line) && error_value.respond_to?(:column) + line = error_value.line + first_column = error_value.column + else + line = @lexer.line + first_column = @lexer.head_column + end + raise ParseError, <<~ERROR - #{@path}:#{@lexer.line}:#{error_value.column}: parse error on value #{error_value.inspect} (#{token_to_str(error_token_id) || '?'}) - #{@text.split("\n")[error_value.line - 1]} - #{carrets(error_value)} + #{@path}:#{line}:#{first_column}: parse error on value #{error_value.inspect} (#{token_to_str(error_token_id) || '?'}) + #{@text.split("\n")[line - 1]} + #{carrets(first_column)} ERROR end @@ -712,8 +720,8 @@ def end_c_declaration @lexer.end_symbol = nil end -def carrets(error_value) - ' ' * (error_value.column + 1) + '^' * (@lexer.column - error_value.column) +def carrets(first_column) + ' ' * (first_column + 1) + '^' * (@lexer.column - first_column) end ...end parser.y/module_eval... ##### State transition tables begin ### diff --git a/parser.y b/parser.y index 0218bca3..c2c8a312 100644 --- a/parser.y +++ b/parser.y @@ -409,10 +409,18 @@ def next_token end def on_error(error_token_id, error_value, value_stack) + if error_value.respond_to?(:line) && error_value.respond_to?(:column) + line = error_value.line + first_column = error_value.column + else + line = @lexer.line + first_column = @lexer.head_column + end + raise ParseError, <<~ERROR - #{@path}:#{@lexer.line}:#{error_value.column}: parse error on value #{error_value.inspect} (#{token_to_str(error_token_id) || '?'}) - #{@text.split("\n")[error_value.line - 1]} - #{carrets(error_value)} + #{@path}:#{line}:#{first_column}: parse error on value #{error_value.inspect} (#{token_to_str(error_token_id) || '?'}) + #{@text.split("\n")[line - 1]} + #{carrets(first_column)} ERROR end @@ -433,6 +441,6 @@ def end_c_declaration @lexer.end_symbol = nil end -def carrets(error_value) - ' ' * (error_value.column + 1) + '^' * (@lexer.column - error_value.column) +def carrets(first_column) + ' ' * (first_column + 1) + '^' * (@lexer.column - first_column) end diff --git a/spec/lrama/parser_spec.rb b/spec/lrama/parser_spec.rb index 26d2d5fa..3db880bf 100644 --- a/spec/lrama/parser_spec.rb +++ b/spec/lrama/parser_spec.rb @@ -1497,8 +1497,9 @@ class : keyword_class tSTRING keyword_end { code 1 } end describe "error messages" do - it "contains line number and column" do - y = <<~INPUT + context "error_value has line number and column" do + it "contains line number and column" do + y = <<~INPUT %{ // Prologue %} @@ -1509,12 +1510,35 @@ class : keyword_class tSTRING keyword_end { code 1 } program: /* empty */ ; - INPUT - expect { Lrama::Parser.new(y, "error_messages/parse.y").parse }.to raise_error(ParseError, <<~ERROR) - error_messages/parse.y:5:7: parse error on value # (IDENTIFIER) - %expect invalid - ^^^^^^^ - ERROR + INPUT + expect { Lrama::Parser.new(y, "error_messages/parse.y").parse }.to raise_error(ParseError, <<~ERROR) + error_messages/parse.y:5:7: parse error on value # (IDENTIFIER) + %expect invalid + ^^^^^^^ + ERROR + end + end + + context "error_value doesn't have line number and column" do + it "contains line number and column" do + y = <<~INPUT +%{ +// Prologue +%} + +%expect 0 10 + +%% + +program: /* empty */ + ; + INPUT + expect { Lrama::Parser.new(y, "error_messages/parse.y").parse }.to raise_error(ParseError, <<~ERROR) + error_messages/parse.y:5:9: parse error on value 10 (INTEGER) + %expect 0 10 + ^^ + ERROR + end end end end