diff --git a/project.gyp b/project.gyp index 294cb32e..4b9e721c 100644 --- a/project.gyp +++ b/project.gyp @@ -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', diff --git a/spec/compiler/build_tables/conflict_manager_spec.cc b/spec/compiler/build_tables/action_takes_precedence_spec.cc similarity index 84% rename from spec/compiler/build_tables/conflict_manager_spec.cc rename to spec/compiler/build_tables/action_takes_precedence_spec.cc index 8ae88906..7bb03c49 100644 --- a/spec/compiler/build_tables/conflict_manager_spec.cc +++ b/spec/compiler/build_tables/action_takes_precedence_spec.cc @@ -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()); - 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 result; Symbol sym1(0); Symbol sym2(1); diff --git a/src/compiler/build_tables/action_takes_precedence.cc b/src/compiler/build_tables/action_takes_precedence.cc index c22e2748..a90055e2 100644 --- a/src/compiler/build_tables/action_takes_precedence.cc +++ b/src/compiler/build_tables/action_takes_precedence.cc @@ -68,5 +68,42 @@ pair 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 diff --git a/src/compiler/build_tables/action_takes_precedence.h b/src/compiler/build_tables/action_takes_precedence.h index 66ef158b..ee674276 100644 --- a/src/compiler/build_tables/action_takes_precedence.h +++ b/src/compiler/build_tables/action_takes_precedence.h @@ -15,6 +15,9 @@ std::pair 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 diff --git a/src/compiler/build_tables/build_lex_table.cc b/src/compiler/build_tables/build_lex_table.cc index a8e0f858..a8ce9e19 100644 --- a/src/compiler/build_tables/build_lex_table.cc +++ b/src/compiler/build_tables/build_lex_table.cc @@ -4,8 +4,8 @@ #include #include #include +#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 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; } } diff --git a/src/compiler/build_tables/lex_conflict_manager.cc b/src/compiler/build_tables/lex_conflict_manager.cc deleted file mode 100644 index e875b162..00000000 --- a/src/compiler/build_tables/lex_conflict_manager.cc +++ /dev/null @@ -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 diff --git a/src/compiler/build_tables/lex_conflict_manager.h b/src/compiler/build_tables/lex_conflict_manager.h deleted file mode 100644 index 1b0bfaf3..00000000 --- a/src/compiler/build_tables/lex_conflict_manager.h +++ /dev/null @@ -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_