Simplify handling of precedence & associativity in productions
This commit is contained in:
parent
6d748a6714
commit
5e4bdcbaf8
5 changed files with 37 additions and 74 deletions
|
|
@ -156,7 +156,7 @@ describe("ParseConflictManager", []() {
|
|||
describe("reduce/reduce conflicts", [&]() {
|
||||
describe("when one action has higher precedence", [&]() {
|
||||
ParseAction left = ParseAction::Reduce(sym2, 1, 0, AssociativityLeft, 0);
|
||||
ParseAction right = ParseAction::Reduce(sym2, 1, 3, AssociativityLeft, 0);
|
||||
ParseAction right = ParseAction::Reduce(sym2, 1, 2, AssociativityLeft, 0);
|
||||
|
||||
it("favors that action", [&]() {
|
||||
result = conflict_manager->resolve(left, right, sym1);
|
||||
|
|
|
|||
|
|
@ -138,14 +138,14 @@ describe("flatten_grammar", []() {
|
|||
AssertThat(
|
||||
get_precedence_sequences(grammar.variables[1].productions),
|
||||
Equals(vector<vector<int>>({
|
||||
{ 0, 0, 101, 102, 101, 0 },
|
||||
{ 0, 0, 101, 101, 0 }
|
||||
{ 0, 101, 102, 101, 0, 0 },
|
||||
{ 0, 101, 101, 0, 0 }
|
||||
})));
|
||||
|
||||
AssertThat(
|
||||
get_precedence_sequences(grammar.variables[2].productions),
|
||||
Equals(vector<vector<int>>({
|
||||
{ 0, 102, 0, 103 },
|
||||
{ 102, 0, 103, 103 },
|
||||
})));
|
||||
});
|
||||
|
||||
|
|
@ -155,8 +155,8 @@ describe("flatten_grammar", []() {
|
|||
AssertThat(
|
||||
get_associativity_sequences(grammar.variables[1].productions),
|
||||
Equals(vector<vector<Associativity>>({
|
||||
{ none, none, AssociativityLeft, AssociativityRight, AssociativityLeft, none },
|
||||
{ none, none, AssociativityLeft, AssociativityLeft, none }
|
||||
{ none, AssociativityLeft, AssociativityRight, AssociativityLeft, none, none },
|
||||
{ none, AssociativityLeft, AssociativityLeft, none, none }
|
||||
})));
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -20,7 +20,6 @@
|
|||
namespace tree_sitter {
|
||||
namespace build_tables {
|
||||
|
||||
using std::dynamic_pointer_cast;
|
||||
using std::make_shared;
|
||||
using std::map;
|
||||
using std::set;
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ class ParseTableBuilder {
|
|||
const SyntaxGrammar grammar;
|
||||
const LexicalGrammar lexical_grammar;
|
||||
ParseConflictManager conflict_manager;
|
||||
unordered_map<const ParseItemSet, ParseStateId, ParseItemSet::Hash> parse_state_ids;
|
||||
unordered_map<ParseItemSet, ParseStateId, ParseItemSet::Hash> parse_state_ids;
|
||||
vector<pair<ParseItemSet, ParseStateId>> item_sets_to_process;
|
||||
ParseTable parse_table;
|
||||
std::set<string> conflicts;
|
||||
|
|
@ -112,18 +112,13 @@ class ParseTableBuilder {
|
|||
};
|
||||
|
||||
CompletionStatus get_completion_status(const ParseItem &item) {
|
||||
CompletionStatus result{ false, 0, AssociativityNone };
|
||||
const Production &production =
|
||||
grammar.productions(item.lhs())[item.production_index];
|
||||
if (item.step_index == production.size()) {
|
||||
result.is_done = true;
|
||||
if (item.step_index > 0) {
|
||||
const ProductionStep &step = production[item.step_index - 1];
|
||||
result.precedence = step.precedence;
|
||||
result.associativity = step.associativity;
|
||||
}
|
||||
const ProductionStep &last_step = production[item.step_index - 1];
|
||||
return { true, last_step.precedence, last_step.associativity };
|
||||
}
|
||||
return result;
|
||||
return { false, 0, AssociativityNone };
|
||||
}
|
||||
|
||||
void add_reduce_actions(const ParseItemSet &item_set, ParseStateId state_id) {
|
||||
|
|
@ -239,12 +234,8 @@ class ParseTableBuilder {
|
|||
const ParseItem &item = pair.first;
|
||||
const Production &production =
|
||||
grammar.productions(item.lhs())[item.production_index];
|
||||
if (item.step_index > 0) {
|
||||
if (item.step_index < production.size())
|
||||
result.add(production[item.step_index].precedence);
|
||||
else
|
||||
result.add(production[item.step_index - 1].precedence);
|
||||
}
|
||||
if (item.step_index > 0)
|
||||
result.add(production[item.step_index - 1].precedence);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,56 +17,36 @@ using std::string;
|
|||
using std::vector;
|
||||
|
||||
class FlattenRule : public rules::RuleFn<void> {
|
||||
public:
|
||||
bool has_pending_precedence;
|
||||
int pending_precedence;
|
||||
private:
|
||||
vector<int> precedence_stack;
|
||||
bool has_pending_associativity;
|
||||
Associativity pending_associativity;
|
||||
vector<Associativity> associativity_stack;
|
||||
Production production;
|
||||
|
||||
FlattenRule()
|
||||
: has_pending_precedence(false),
|
||||
pending_precedence(0),
|
||||
has_pending_associativity(false),
|
||||
pending_associativity(AssociativityNone) {}
|
||||
|
||||
void apply_to(const rules::Symbol *sym) {
|
||||
production.push_back(
|
||||
ProductionStep(*sym, current_precedence(), current_associativity()));
|
||||
|
||||
if (has_pending_precedence) {
|
||||
precedence_stack.push_back(pending_precedence);
|
||||
has_pending_precedence = false;
|
||||
}
|
||||
if (has_pending_associativity) {
|
||||
associativity_stack.push_back(pending_associativity);
|
||||
has_pending_associativity = false;
|
||||
}
|
||||
production.push_back(ProductionStep(*sym, precedence_stack.back(),
|
||||
associativity_stack.back()));
|
||||
}
|
||||
|
||||
void apply_to(const rules::Metadata *metadata) {
|
||||
int precedence = metadata->value_for(rules::PRECEDENCE);
|
||||
int associativity = metadata->value_for(rules::ASSOCIATIVITY);
|
||||
|
||||
if (precedence != 0) {
|
||||
pending_precedence = precedence;
|
||||
has_pending_precedence = true;
|
||||
}
|
||||
|
||||
if (associativity != 0) {
|
||||
pending_associativity = static_cast<Associativity>(associativity);
|
||||
has_pending_associativity = true;
|
||||
}
|
||||
if (precedence != 0)
|
||||
precedence_stack.push_back(precedence);
|
||||
if (associativity != 0)
|
||||
associativity_stack.push_back(static_cast<Associativity>(associativity));
|
||||
|
||||
apply(metadata->rule);
|
||||
|
||||
if (precedence != 0)
|
||||
if (precedence != 0) {
|
||||
precedence_stack.pop_back();
|
||||
production.back().precedence = precedence_stack.back();
|
||||
}
|
||||
|
||||
if (associativity != 0)
|
||||
if (associativity != 0) {
|
||||
associativity_stack.pop_back();
|
||||
production.back().associativity = associativity_stack.back();
|
||||
}
|
||||
}
|
||||
|
||||
void apply_to(const rules::Seq *seq) {
|
||||
|
|
@ -74,28 +54,21 @@ class FlattenRule : public rules::RuleFn<void> {
|
|||
apply(seq->right);
|
||||
}
|
||||
|
||||
private:
|
||||
int current_precedence() {
|
||||
if (precedence_stack.empty())
|
||||
return 0;
|
||||
else
|
||||
return precedence_stack.back();
|
||||
}
|
||||
public:
|
||||
FlattenRule()
|
||||
: precedence_stack({ 0 }), associativity_stack({ AssociativityNone }) {}
|
||||
|
||||
Associativity current_associativity() {
|
||||
if (associativity_stack.empty())
|
||||
return AssociativityNone;
|
||||
else
|
||||
return associativity_stack.back();
|
||||
Production flatten(const rule_ptr &rule) {
|
||||
apply(rule);
|
||||
size_t size = production.size();
|
||||
if (size > 1) {
|
||||
production[size - 1].precedence = production[size - 2].precedence;
|
||||
production[size - 1].associativity = production[size - 2].associativity;
|
||||
}
|
||||
return production;
|
||||
}
|
||||
};
|
||||
|
||||
Production flatten_rule(const rule_ptr &rule) {
|
||||
FlattenRule flattener;
|
||||
flattener.apply(rule);
|
||||
return flattener.production;
|
||||
}
|
||||
|
||||
struct ProductionSlice {
|
||||
vector<ProductionStep>::const_iterator start;
|
||||
vector<ProductionStep>::const_iterator end;
|
||||
|
|
@ -137,7 +110,7 @@ SyntaxGrammar flatten_grammar(const InitialSyntaxGrammar &grammar) {
|
|||
for (const Variable &variable : grammar.variables) {
|
||||
vector<Production> productions;
|
||||
for (const rule_ptr &rule_component : extract_choices(variable.rule))
|
||||
productions.push_back(flatten_rule(rule_component));
|
||||
productions.push_back(FlattenRule().flatten(rule_component));
|
||||
result.variables.push_back(
|
||||
SyntaxVariable(variable.name, variable.type, productions));
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue