Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5ebcbb2d6d | ||
|
|
61ebbb4f19 | ||
|
|
1b4ca59158 | ||
|
|
b02c9205c0 |
No files matched your search
@@ -1,3 +1,15 @@
|
||||
## v2.1.1
|
||||
|
||||
### Fixes
|
||||
|
||||
- Field aliases for AST node fields could alias incorrect field when multiple rule alternatives present for one rule set (#33)
|
||||
|
||||
## v2.1.0
|
||||
|
||||
### Improvements
|
||||
|
||||
- Report rule name and line number for conflicting AST node field positions errors (#32)
|
||||
|
||||
## v2.0.0
|
||||
|
||||
### Improvements
|
||||
|
||||
+12
-12
@@ -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
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
class Propane
|
||||
VERSION = "2.1.0"
|
||||
VERSION = "2.1.1"
|
||||
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)
|
||||
|
||||
Reference in new issue
Block a user