Replace LexConflictManager class with action_takes_precedence function

This commit is contained in:
Max Brunsfeld 2014-11-05 23:34:23 -08:00
parent 5dc08ccce9
commit 0d267e41aa
7 changed files with 56 additions and 109 deletions

View file

@ -20,7 +20,6 @@
'src/compiler/build_tables/item.cc',
'src/compiler/build_tables/item_set_closure.cc',
'src/compiler/build_tables/item_set_transitions.cc',
'src/compiler/build_tables/lex_conflict_manager.cc',
'src/compiler/build_tables/lex_item.cc',
'src/compiler/build_tables/parse_item.cc',
'src/compiler/build_tables/rule_can_be_blank.cc',

View file

@ -2,7 +2,6 @@
#include "compiler/rules/built_in_symbols.h"
#include "compiler/parse_table.h"
#include "compiler/build_tables/action_takes_precedence.h"
#include "compiler/build_tables/lex_conflict_manager.h"
#include "compiler/prepared_grammar.h"
using namespace rules;
@ -10,7 +9,7 @@ using namespace build_tables;
START_TEST
describe("resolving parse conflicts", []() {
describe("action_takes_precedence", []() {
bool update;
SyntaxGrammar parse_grammar({
@ -18,41 +17,25 @@ describe("resolving parse conflicts", []() {
{ "rule2", sym("token1") },
}, {}, set<rules::Symbol>());
LexicalGrammar lex_grammar({
{ "token1", pattern("[a-c]") },
{ "token2", pattern("[b-d]") },
{ "token3", keyword("stuff") },
}, {}, {});
describe("LexConflictManager", [&]() {
describe("lexical conflicts", [&]() {
Symbol sym1(0, SymbolOptionToken);
Symbol sym2(1, SymbolOptionToken);
Symbol sym3(2, SymbolOptionToken);
LexConflictManager *manager;
before_each([&]() {
manager = new LexConflictManager(lex_grammar);
});
after_each([&]() {
delete manager;
});
it("favors non-errors over lexical errors", [&]() {
update = manager->resolve_lex_action(LexAction::Error(), LexAction::Advance(2, {0}));
update = action_takes_precedence(LexAction::Advance(2, {0}), LexAction::Error());
AssertThat(update, IsTrue());
update = manager->resolve_lex_action(LexAction::Advance(2, {0}), LexAction::Error());
update = action_takes_precedence(LexAction::Error(), LexAction::Advance(2, {0}));
AssertThat(update, IsFalse());
});
describe("accept-token/advance conflicts", [&]() {
it("prefers the advance", [&]() {
update = manager->resolve_lex_action(LexAction::Accept(sym3, 3), LexAction::Advance(1, { 0 }));
update = action_takes_precedence(LexAction::Advance(1, { 0 }), LexAction::Accept(sym3, 3));
AssertThat(update, IsTrue());
update = manager->resolve_lex_action(LexAction::Advance(1, { 0 }), LexAction::Accept(sym3, 3));
update = action_takes_precedence(LexAction::Accept(sym3, 3), LexAction::Advance(1, { 0 }));
AssertThat(update, IsFalse());
});
});
@ -60,27 +43,27 @@ describe("resolving parse conflicts", []() {
describe("accept-token/accept-token conflicts", [&]() {
describe("when one token has a higher precedence than the other", [&]() {
it("prefers the token with the higher precedence", [&]() {
update = manager->resolve_lex_action(LexAction::Accept(sym3, 2), LexAction::Accept(sym2, 0));
update = action_takes_precedence(LexAction::Accept(sym2, 0), LexAction::Accept(sym3, 2));
AssertThat(update, IsFalse());
update = manager->resolve_lex_action(LexAction::Accept(sym2, 0), LexAction::Accept(sym3, 2));
update = action_takes_precedence(LexAction::Accept(sym3, 2), LexAction::Accept(sym2, 0));
AssertThat(update, IsTrue());
});
});
describe("when both tokens have the same precedence", [&]() {
it("prefers the token listed earlier in the grammar", [&]() {
update = manager->resolve_lex_action(LexAction::Accept(sym1, 0), LexAction::Accept(sym2, 0));
update = action_takes_precedence(LexAction::Accept(sym2, 0), LexAction::Accept(sym1, 0));
AssertThat(update, IsFalse());
update = manager->resolve_lex_action(LexAction::Accept(sym2, 0), LexAction::Accept(sym1, 0));
update = action_takes_precedence(LexAction::Accept(sym1, 0), LexAction::Accept(sym2, 0));
AssertThat(update, IsTrue());
});
});
});
});
describe("action_takes_precedence", [&]() {
describe("parsing conflicts", [&]() {
pair<bool, bool> result;
Symbol sym1(0);
Symbol sym2(1);

View file

@ -68,5 +68,42 @@ pair<bool, bool> action_takes_precedence(const ParseAction &new_action,
return { has_precedence, has_conflict };
}
bool action_takes_precedence(const LexAction &new_action,
const LexAction &old_action) {
if (new_action.type < old_action.type)
return !action_takes_precedence(old_action, new_action);
switch (old_action.type) {
case LexActionTypeError:
return true;
case LexActionTypeAccept: {
int old_precedence = *old_action.precedence_values.begin();
switch (new_action.type) {
case LexActionTypeAccept: {
int new_precedence = *new_action.precedence_values.begin();
if (new_precedence > old_precedence)
return true;
else if (new_precedence < old_precedence)
return false;
else
return new_action.symbol.index < old_action.symbol.index;
}
case LexActionTypeAdvance:
return true;
default:
return false;
}
return true;
}
default:
return false;
}
}
} // namespace build_tables
} // namespace tree_sitter

View file

@ -15,6 +15,9 @@ std::pair<bool, bool> action_takes_precedence(const ParseAction &new_action,
const rules::Symbol &symbol,
const SyntaxGrammar &grammar);
bool action_takes_precedence(const LexAction &new_action,
const LexAction &old_action);
} // namespace build_tables
} // namespace tree_sitter

View file

@ -4,8 +4,8 @@
#include <unordered_map>
#include <utility>
#include <vector>
#include "compiler/build_tables/action_takes_precedence.h"
#include "compiler/build_tables/item_set_transitions.h"
#include "compiler/build_tables/lex_conflict_manager.h"
#include "compiler/build_tables/lex_item.h"
#include "compiler/parse_table.h"
#include "compiler/prepared_grammar.h"
@ -31,15 +31,12 @@ using rules::Symbol;
class LexTableBuilder {
const LexicalGrammar lex_grammar;
ParseTable *parse_table;
LexConflictManager conflict_manager;
unordered_map<const LexItemSet, LexStateId> lex_state_ids;
LexTable lex_table;
public:
LexTableBuilder(ParseTable *parse_table, const LexicalGrammar &lex_grammar)
: lex_grammar(lex_grammar),
parse_table(parse_table),
conflict_manager(LexConflictManager(lex_grammar)) {}
: lex_grammar(lex_grammar), parse_table(parse_table) {}
LexTable build() {
for (auto &parse_state : parse_table->states) {
@ -98,8 +95,8 @@ class LexTableBuilder {
LexStateId new_state_id = add_lex_state(new_item_set);
auto action = LexAction::Advance(
new_state_id, precedence_values_for_item_set(new_item_set));
if (conflict_manager.resolve_lex_action(
lex_table.state(state_id).default_action, action))
if (action_takes_precedence(action,
lex_table.state(state_id).default_action))
lex_table.state(state_id).actions[rule] = action;
}
}
@ -109,7 +106,7 @@ class LexTableBuilder {
if (item.is_done()) {
auto current_action = lex_table.state(state_id).default_action;
auto new_action = LexAction::Accept(item.lhs, item.precedence());
if (conflict_manager.resolve_lex_action(current_action, new_action))
if (action_takes_precedence(new_action, current_action))
lex_table.state(state_id).default_action = new_action;
}
}

View file

@ -1,49 +0,0 @@
#include "compiler/build_tables/lex_conflict_manager.h"
#include "compiler/util/string_helpers.h"
#include "compiler/prepared_grammar.h"
namespace tree_sitter {
namespace build_tables {
LexConflictManager::LexConflictManager(const LexicalGrammar &grammar)
: grammar(grammar) {}
bool LexConflictManager::resolve_lex_action(const LexAction &old_action,
const LexAction &new_action) {
if (new_action.type < old_action.type)
return !resolve_lex_action(new_action, old_action);
switch (old_action.type) {
case LexActionTypeError:
return true;
case LexActionTypeAccept: {
int old_precedence = *old_action.precedence_values.begin();
switch (new_action.type) {
case LexActionTypeAccept: {
int new_precedence = *new_action.precedence_values.begin();
if (new_precedence > old_precedence)
return true;
else if (new_precedence < old_precedence)
return false;
else
return new_action.symbol.index < old_action.symbol.index;
}
case LexActionTypeAdvance:
return true;
default:
return false;
}
return true;
}
default:
return false;
}
}
} // namespace build_tables
} // namespace tree_sitter

View file

@ -1,23 +0,0 @@
#ifndef COMPILER_BUILD_TABLES_LEX_CONFLICT_MANAGER_H_
#define COMPILER_BUILD_TABLES_LEX_CONFLICT_MANAGER_H_
#include "tree_sitter/compiler.h"
#include "compiler/lex_table.h"
#include "compiler/prepared_grammar.h"
namespace tree_sitter {
namespace build_tables {
class LexConflictManager {
const LexicalGrammar grammar;
public:
explicit LexConflictManager(const LexicalGrammar &grammar);
bool resolve_lex_action(const LexAction &old_action,
const LexAction &new_action);
};
} // namespace build_tables
} // namespace tree_sitter
#endif // COMPILER_BUILD_TABLES_LEX_CONFLICT_MANAGER_H_