diff --git a/lib/lrama/grammar/parameterizing_rule/rhs.rb b/lib/lrama/grammar/parameterizing_rule/rhs.rb index 7f50be87..3eb92f8e 100644 --- a/lib/lrama/grammar/parameterizing_rule/rhs.rb +++ b/lib/lrama/grammar/parameterizing_rule/rhs.rb @@ -9,6 +9,28 @@ def initialize @user_code = nil @precedence_sym = nil end + + def resolve_user_code(bindings) + return unless user_code + + var_to_arg = {} + symbols.each do |sym| + resolved_sym = bindings.resolve_symbol(sym) + if resolved_sym != sym + var_to_arg[sym.s_value] = resolved_sym.s_value + end + end + + var_to_arg.each do |var, arg| + user_code.references.each do |ref| + if ref.name == var + ref.name = arg + end + end + end + + return user_code + end end end end diff --git a/lib/lrama/grammar/rule_builder.rb b/lib/lrama/grammar/rule_builder.rb index 71431682..ccb41e67 100644 --- a/lib/lrama/grammar/rule_builder.rb +++ b/lib/lrama/grammar/rule_builder.rb @@ -135,7 +135,7 @@ def process_rhs(parameterizing_rule_resolver) r.symbols.each { |sym| rule_builder.add_rhs(bindings.resolve_symbol(sym)) } rule_builder.line = line rule_builder.precedence_sym = r.precedence_sym - rule_builder.user_code = r.user_code + rule_builder.user_code = r.resolve_user_code(bindings) rule_builder.complete_input rule_builder.setup_rules(parameterizing_rule_resolver) @rule_builders_for_parameterizing_rules << rule_builder diff --git a/sig/lrama/grammar/parameterizing_rule/rhs.rbs b/sig/lrama/grammar/parameterizing_rule/rhs.rbs index 724a42ea..a9da56e3 100644 --- a/sig/lrama/grammar/parameterizing_rule/rhs.rbs +++ b/sig/lrama/grammar/parameterizing_rule/rhs.rbs @@ -7,6 +7,7 @@ module Lrama attr_reader precedence_sym: Lexer::Token? def initialize: () -> void + def resolve_user_code: (Grammar::Binding bindings) -> Lexer::Token::UserCode? end end end diff --git a/spec/fixtures/parameterizing_rules/user_defined/with_action_and_named_references.y b/spec/fixtures/parameterizing_rules/user_defined/with_action_and_named_references.y new file mode 100644 index 00000000..85ae0d5c --- /dev/null +++ b/spec/fixtures/parameterizing_rules/user_defined/with_action_and_named_references.y @@ -0,0 +1,41 @@ +/* + * This is comment for this file. + */ + +%{ +// Prologue +static int yylex(YYSTYPE *val, YYLTYPE *loc); +static int yyerror(YYLTYPE *loc, const char *str); +%} + +%union { + int i; + char *s; +} + +%token number +%token string + +%rule pair(X, Y): X ',' Y { printf("(%d, %d)\n", $X, $3); } + ; + +%% + +program : pair(number, string) { printf("pair odd even\n"); } + ; + +%% + +static int yylex(YYSTYPE *yylval, YYLTYPE *loc) +{ + return 0; +} + +static int yyerror(YYLTYPE *loc, const char *str) +{ + return 0; +} + +int main(int argc, char *argv[]) +{ +} diff --git a/spec/lrama/parser_spec.rb b/spec/lrama/parser_spec.rb index 3a17994f..2fddc68b 100644 --- a/spec/lrama/parser_spec.rb +++ b/spec/lrama/parser_spec.rb @@ -1686,6 +1686,59 @@ ), ]) end + + context "with named references" do + let(:path) { "parameterizing_rules/user_defined/with_action_and_named_references.y" } + + it "expands parameterizing rules" do + expect(grammar.nterms.sort_by(&:number)).to match_symbols([ + Sym.new(id: T::Ident.new(s_value: "$accept"), alias_name: nil, number: 6, tag: nil, term: false, token_id: 0, nullable: false), + Sym.new(id: T::Ident.new(s_value: "pair_number_string"), alias_name: nil, number: 7, tag: nil, term: false, token_id: 1, nullable: false), + Sym.new(id: T::Ident.new(s_value: "program"), alias_name: nil, number: 8, tag: nil, term: false, token_id: 2, nullable: false), + ]) + + expect(grammar.rules).to eq([ + Rule.new( + id: 0, + lhs: grammar.find_symbol_by_s_value!("$accept"), + rhs: [ + grammar.find_symbol_by_s_value!("program"), + grammar.find_symbol_by_s_value!("YYEOF"), + ], + token_code: nil, + nullable: false, + precedence_sym: grammar.find_symbol_by_s_value!("YYEOF"), + lineno: 24, + ), + Rule.new( + id: 1, + lhs: grammar.find_symbol_by_s_value!("pair_number_string"), + rhs: [ + grammar.find_symbol_by_s_value!("number"), + grammar.find_symbol_by_number!(5), + grammar.find_symbol_by_s_value!("string") + ], + lhs_tag: nil, + token_code: T::UserCode.new(s_value: " printf(\"(%d, %d)\\n\", $X, $3); "), + nullable: false, + precedence_sym: grammar.find_symbol_by_s_value!("string"), + lineno: 24, + ), + Rule.new( + id: 2, + lhs: grammar.find_symbol_by_s_value!("program"), + rhs: [ + grammar.find_symbol_by_s_value!("pair_number_string"), + ], + lhs_tag: nil, + token_code: T::UserCode.new(s_value: " printf(\"pair odd even\\n\"); "), + nullable: false, + precedence_sym: nil, + lineno: 24, + ), + ]) + end + end end context "when nested rules" do