Field aliases for AST node fields could alias incorrect field when multiple rule alternatives present for one rule set - close #33
This commit is contained in:
parent
b02c9205c0
commit
1b4ca59158
@ -119,6 +119,8 @@ class Propane
|
||||
def build_ast_fields(grammar)
|
||||
field_ast_node_indexes = {}
|
||||
field_indexes_across_all_rules = {}
|
||||
# Stores the index into @ast_fields by field alias name.
|
||||
field_aliases = {}
|
||||
@ast_fields = []
|
||||
@rules.each do |rule|
|
||||
rule.components.each_with_index do |component, i|
|
||||
@ -136,6 +138,16 @@ class Propane
|
||||
field_ast_node_indexes[field_name] = @ast_fields.size
|
||||
@ast_fields << {field_name => struct_name}
|
||||
end
|
||||
rule.aliases.each do |alias_name, index|
|
||||
if index == i
|
||||
alias_ast_fields_index = field_ast_node_indexes[field_name]
|
||||
if field_aliases[alias_name] && field_aliases[alias_name] != alias_ast_fields_index
|
||||
raise Error.new("Error: conflicting AST node field positions for alias `#{alias_name}` in rule #{rule.name} defined on line #{rule.line_number}")
|
||||
end
|
||||
field_aliases[alias_name] = alias_ast_fields_index
|
||||
@ast_fields[alias_ast_fields_index][alias_name] = @ast_fields[alias_ast_fields_index].first[1]
|
||||
end
|
||||
end
|
||||
field_indexes_across_all_rules[node_name] ||= Set.new
|
||||
field_indexes_across_all_rules[node_name] << field_ast_node_indexes[field_name]
|
||||
rule.rule_set_node_field_index_map[i] = field_ast_node_indexes[field_name]
|
||||
@ -150,18 +162,6 @@ class Propane
|
||||
"#{grammar.ast_prefix}#{node_name}#{grammar.ast_suffix}"
|
||||
end
|
||||
end
|
||||
# Now merge in the field aliases as given by the user in the
|
||||
# grammar.
|
||||
field_aliases = {}
|
||||
@rules.each do |rule|
|
||||
rule.aliases.each do |alias_name, index|
|
||||
if field_aliases[alias_name] && field_aliases[alias_name] != index
|
||||
raise Error.new("Error: conflicting AST node field positions for alias `#{alias_name}` in rule #{rule.name} defined on line #{rule.line_number}")
|
||||
end
|
||||
field_aliases[alias_name] = index
|
||||
@ast_fields[index][alias_name] = @ast_fields[index].first[1]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
@ -1219,6 +1219,29 @@ EOF
|
||||
expect(results.status).to eq 0
|
||||
end
|
||||
|
||||
it "aliases the correct field when multiple rules are in a rule set in AST mode" do
|
||||
write_grammar <<EOF
|
||||
ast;
|
||||
|
||||
token a;
|
||||
token b;
|
||||
token c;
|
||||
drop /\\s+/;
|
||||
Start -> a;
|
||||
Start -> Foo;
|
||||
Start -> T:first T:second T:third;
|
||||
Foo -> b;
|
||||
T -> a;
|
||||
T -> b;
|
||||
T -> c;
|
||||
EOF
|
||||
run_propane(language: language)
|
||||
compile("spec/test_ast_field_aliases.#{language}", language: language)
|
||||
results = run_test
|
||||
expect(results.stderr).to eq ""
|
||||
expect(results.status).to eq 0
|
||||
end
|
||||
|
||||
it "allows specifying field aliases when AST mode is not enabled" do
|
||||
if language == "d"
|
||||
write_grammar <<EOF
|
||||
@ -1253,6 +1276,56 @@ Start -> id:first id:second <<
|
||||
printf("first is %s\\n", ${first});
|
||||
printf("second is %s\\n", ${second});
|
||||
>>
|
||||
EOF
|
||||
end
|
||||
run_propane(language: language)
|
||||
compile("spec/test_field_aliases.#{language}", language: language)
|
||||
results = run_test
|
||||
expect(results.stderr).to eq ""
|
||||
expect(results.status).to eq 0
|
||||
expect(results.stdout).to match /first is foo1.*second is bar2/m
|
||||
end
|
||||
|
||||
it "aliases the correct field when multiple rules are in a rule set when AST mode is not enabled" do
|
||||
if language == "d"
|
||||
write_grammar <<EOF
|
||||
<<
|
||||
import std.stdio;
|
||||
>>
|
||||
ptype string;
|
||||
token id /[a-zA-Z_][a-zA-Z0-9_]*/ <<
|
||||
$$ = match;
|
||||
>>
|
||||
drop /\\s+/;
|
||||
Start -> id;
|
||||
Start -> Foo;
|
||||
Start -> id:first id:second <<
|
||||
writeln("first is ", ${first});
|
||||
writeln("second is ", ${second});
|
||||
>>
|
||||
Foo -> ;
|
||||
EOF
|
||||
else
|
||||
write_grammar <<EOF
|
||||
<<
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
>>
|
||||
ptype char const *;
|
||||
token id /[a-zA-Z_][a-zA-Z0-9_]*/ <<
|
||||
char * s = malloc(match_length + 1);
|
||||
strncpy(s, (char const *)match, match_length);
|
||||
s[match_length] = 0;
|
||||
$$ = s;
|
||||
>>
|
||||
drop /\\s+/;
|
||||
Start -> id;
|
||||
Start -> Foo;
|
||||
Start -> id:first id:second <<
|
||||
printf("first is %s\\n", ${first});
|
||||
printf("second is %s\\n", ${second});
|
||||
>>
|
||||
Foo -> ;
|
||||
EOF
|
||||
end
|
||||
run_propane(language: language)
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user