Skip to content

Commit

Permalink
Raise error when referred nterm, term and action type is not declared
Browse files Browse the repository at this point in the history
  • Loading branch information
yui-knk committed Jul 31, 2023
1 parent d23b6f8 commit 927aff7
Show file tree
Hide file tree
Showing 4 changed files with 91 additions and 15 deletions.
19 changes: 19 additions & 0 deletions lib/lrama/grammar.rb
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,7 @@ def prepare
# TODO: More validation methods
def validate!
validate_symbol_number_uniqueness!
validate_no_declared_type_reference!
end

def compute_nullable
Expand Down Expand Up @@ -609,5 +610,23 @@ def validate_symbol_number_uniqueness!

raise "Symbol number is duplicated. #{invalid}"
end

def validate_no_declared_type_reference!
errors = []

rules.each do |rule|
next unless rule.code

rule.code.references.select do |ref|
ref.type == :dollar && !ref.tag
end.each do |ref|
errors << "$#{ref.value} of '#{rule.lhs.id.s_value}' has no declared type"
end
end

return if errors.empty?

raise errors.join("\n")
end
end
end
8 changes: 7 additions & 1 deletion lib/lrama/grammar/reference.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,13 @@ def tag
if ex_tag
ex_tag
else
referring_symbol.tag
# FIXME: Remove this class check
if referring_symbol.is_a?(Symbol)
referring_symbol.tag
else
# Lrama::Lexer::Token (User_code) case
nil
end
end
end
end
Expand Down
2 changes: 1 addition & 1 deletion spec/lrama/grammar_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -55,4 +55,4 @@
end
end
end
end
end
77 changes: 64 additions & 13 deletions spec/lrama/parser_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -968,13 +968,13 @@ class : keyword_class tSTRING keyword_end { code 1 }
program: lambda ;
lambda: tLAMBDA
{ $<int>1 = 1; $<int>$ = 2; }
{ $<int>$ = 3; }
{ $<int>$ = 4; }
{ $<i>1 = 1; $<i>$ = 2; }
{ $<i>$ = 3; }
{ $<i>$ = 4; }
tARGS
{ 5; }
tBODY
{ $2; $3; $5; $7; $$ = 1; }
{ $<i>2; $<i>3; $<i>5; $<i>7; $<i>$ = 1; }
;
%%
INPUT
Expand Down Expand Up @@ -1008,7 +1008,7 @@ class : keyword_class tSTRING keyword_end { code 1 }
id: 2,
lhs: grammar.find_symbol_by_s_value!("@1"),
rhs: [],
code: Code.new(type: :user_code, token_code: T.new(type: T::User_code, s_value: "{ $<int>1 = 1; $<int>$ = 2; }")),
code: Code.new(type: :user_code, token_code: T.new(type: T::User_code, s_value: "{ $<i>1 = 1; $<i>$ = 2; }")),
nullable: true,
precedence_sym: nil,
lineno: 17,
Expand All @@ -1017,7 +1017,7 @@ class : keyword_class tSTRING keyword_end { code 1 }
id: 3,
lhs: grammar.find_symbol_by_s_value!("@2"),
rhs: [],
code: Code.new(type: :user_code, token_code: T.new(type: T::User_code, s_value: "{ $<int>$ = 3; }")),
code: Code.new(type: :user_code, token_code: T.new(type: T::User_code, s_value: "{ $<i>$ = 3; }")),
nullable: true,
precedence_sym: nil,
lineno: 18,
Expand All @@ -1026,7 +1026,7 @@ class : keyword_class tSTRING keyword_end { code 1 }
id: 4,
lhs: grammar.find_symbol_by_s_value!("$@3"),
rhs: [],
code: Code.new(type: :user_code, token_code: T.new(type: T::User_code, s_value: "{ $<int>$ = 4; }")),
code: Code.new(type: :user_code, token_code: T.new(type: T::User_code, s_value: "{ $<i>$ = 4; }")),
nullable: true,
precedence_sym: nil,
lineno: 19,
Expand All @@ -1052,7 +1052,7 @@ class : keyword_class tSTRING keyword_end { code 1 }
grammar.find_symbol_by_s_value!("$@4"),
grammar.find_symbol_by_s_value!("tBODY"),
],
code: Code.new(type: :user_code, token_code: T.new(type: T::User_code, s_value: "{ $2; $3; $5; $7; $$ = 1; }")),
code: Code.new(type: :user_code, token_code: T.new(type: T::User_code, s_value: "{ $<i>2; $<i>3; $<i>5; $<i>7; $<i>$ = 1; }")),
nullable: false,
precedence_sym: grammar.find_symbol_by_s_value!("tBODY"),
lineno: 16,
Expand All @@ -1071,6 +1071,7 @@ class : keyword_class tSTRING keyword_end { code 1 }
}
%token EOI 0 "EOI"
%type <int> emp
%%
Expand Down Expand Up @@ -1098,7 +1099,7 @@ class : keyword_class tSTRING keyword_end { code 1 }
code: nil,
nullable: false,
precedence_sym: grammar.find_symbol_by_s_value!("EOI"),
lineno: 13,
lineno: 14,
),
Rule.new(
id: 1,
Expand All @@ -1109,7 +1110,7 @@ class : keyword_class tSTRING keyword_end { code 1 }
code: nil,
nullable: true,
precedence_sym: nil,
lineno: 13,
lineno: 14,
),
Rule.new(
id: 2,
Expand All @@ -1119,7 +1120,7 @@ class : keyword_class tSTRING keyword_end { code 1 }
code: Code.new(type: :user_code, token_code: T.new(type: T::User_code, s_value: "{ $$; }")),
nullable: true,
precedence_sym: nil,
lineno: 16,
lineno: 17,
),
Rule.new(
id: 3,
Expand All @@ -1129,7 +1130,7 @@ class : keyword_class tSTRING keyword_end { code 1 }
code: Code.new(type: :user_code, token_code: T.new(type: T::User_code, s_value: "{ @$; }")),
nullable: true,
precedence_sym: nil,
lineno: 18,
lineno: 19,
),
Rule.new(
id: 4,
Expand All @@ -1139,7 +1140,7 @@ class : keyword_class tSTRING keyword_end { code 1 }
code: Code.new(type: :user_code, token_code: T.new(type: T::User_code, s_value: "{ @0; }")),
nullable: true,
precedence_sym: nil,
lineno: 20,
lineno: 21,
),
])
end
Expand Down Expand Up @@ -1370,4 +1371,54 @@ class : keyword_class tSTRING keyword_end
end
end
end

describe "Grammar#validate!" do
describe "#validate_no_declared_type_reference!" do
it "raises error when referred nterm, term and action have no tag so that type is not declared" do
y = <<~INPUT
%{
// Prologue
%}
%union {
int val;
}
%token NUM
%%
program : stmt
;
stmt : {} {} expr { $$ = $1 + $<val>2; }
;
expr : expr1
| expr2
;
expr1 : NUM { $$ = $1; }
;
expr2 : expr '+' expr { $$ = $1 + $3; }
;
%%
INPUT

expect { Lrama::Parser.new(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
$$ of 'expr1' has no declared type
$1 of 'expr1' has no declared type
$$ of 'expr2' has no declared type
$1 of 'expr2' has no declared type
$3 of 'expr2' has no declared type
MSG
end
end
end
end
end

0 comments on commit 927aff7

Please sign in to comment.