diff --git a/spec/compiler/build_tables/merge_transitions_spec.cc b/spec/compiler/build_tables/merge_transitions_spec.cc index 7724ec90..58f4fad4 100644 --- a/spec/compiler/build_tables/merge_transitions_spec.cc +++ b/spec/compiler/build_tables/merge_transitions_spec.cc @@ -6,11 +6,11 @@ using namespace build_tables; START_TEST -describe("merge_char_transitions", []() { +describe("merge_transition", []() { typedef map int_map; auto do_merge = [&](int_map *left, const pair &new_pair) { - merge_char_transition(left, new_pair, [](int *l, const int *r) { + merge_transition(left, new_pair, [](int *l, const int *r) { *l = *l | *r; }); }; diff --git a/spec/compiler/build_tables/rule_transitions_spec.cc b/spec/compiler/build_tables/rule_transitions_spec.cc index ab03cba1..57e6fb47 100644 --- a/spec/compiler/build_tables/rule_transitions_spec.cc +++ b/spec/compiler/build_tables/rule_transitions_spec.cc @@ -5,10 +5,9 @@ using namespace rules; using namespace build_tables; -template -class rule_map : public std::map { +class transition_map : public std::map { public: - bool operator==(const std::map &other) const { + bool operator==(const std::map &other) const { if (this->size() != other.size()) return false; for (const auto &pair : *this) { auto other_pair = other.find(pair.first); @@ -18,108 +17,72 @@ class rule_map : public std::map { return true; } - rule_map(const std::initializer_list> &list) : std::map(list) {} + transition_map(const std::initializer_list> &list) : + std::map(list) {} }; START_TEST -describe("sym_transitions", []() { - it("handles symbols", [&]() { +describe("rule_transitions", []() { + it("handles single characters", [&]() { AssertThat( - sym_transitions(i_sym(1)), - Equals(rule_map({ - { Symbol(1), blank() } - }))); - }); - - it("handles choices", [&]() { - AssertThat( - sym_transitions(choice({ i_sym(1), i_sym(2) })), - Equals(rule_map({ - { Symbol(1), blank() }, - { Symbol(2), blank() } + rule_transitions(character({ '1' })), + Equals(transition_map({ + { CharacterSet().include('1'), blank() } }))); }); it("handles sequences", [&]() { AssertThat( - sym_transitions(seq({ i_sym(1), i_sym(2) })), - Equals(rule_map({ - { Symbol(1), i_sym(2) } + rule_transitions(seq({ character({ '1' }), character({ '2' }) })), + Equals(transition_map({ + { CharacterSet().include('1'), character({ '2' }) } }))); }); it("handles long sequences", [&]() { AssertThat( - sym_transitions(seq({ - i_sym(1), - i_sym(2), - i_sym(3), - i_sym(4) + rule_transitions(seq({ + character({ '1' }), + character({ '2' }), + character({ '3' }), + character({ '4' }) })), - Equals(rule_map({ - { Symbol(1), seq({ i_sym(2), i_sym(3), i_sym(4) }) } + Equals(transition_map({ + { + CharacterSet().include('1'), + seq({ character({ '2' }), character({ '3' }), character({ '4' }) }), + } }))); }); it("handles sequences whose left sides can be blank", [&]() { AssertThat( - sym_transitions(seq({ + rule_transitions(seq({ choice({ - i_sym(1), + character({ '1' }), blank() }), seq({ - i_sym(1), - i_sym(2) }) - })), Equals(rule_map({ - { Symbol(1), choice({ seq({ i_sym(1), i_sym(2) }), i_sym(2), }) } - }))); - }); - - it("handles choices with common starting symbols", [&]() { - AssertThat( - sym_transitions( - choice({ - seq({ i_sym(1), i_sym(2) }), - seq({ i_sym(1), i_sym(3) }) })), - Equals(rule_map({ - { Symbol(1), choice({ i_sym(2), i_sym(3) }) } - }))); - }); - - it("preserves metadata", [&]() { - map metadata_value({ - { PRECEDENCE, 5 } - }); - - rule_ptr rule = make_shared(seq({ i_sym(1), i_sym(2) }), metadata_value); - AssertThat( - sym_transitions(rule), - Equals(rule_map({ - { Symbol(1), make_shared(i_sym(2), metadata_value)}, - }))); - }); -}); - -describe("char_transitions", []() { - it("handles characters", [&]() { - AssertThat( - char_transitions(character({ '1' })), - Equals(rule_map({ - { CharacterSet().include('1'), blank() } + character({ '1' }), + character({ '2' }) }) + })), Equals(transition_map({ + { + CharacterSet().include('1'), + choice({ seq({ character({ '1' }), character({ '2' }) }), character({ '2' }), }), + } }))); }); it("handles choices between overlapping character sets", [&]() { AssertThat( - char_transitions(choice({ + rule_transitions(choice({ seq({ character({ 'a', 'b', 'c', 'd' }), sym("x") }), seq({ character({ 'c', 'd', 'e', 'f' }), sym("y") }) })), - Equals(rule_map({ + Equals(transition_map({ { CharacterSet().include('a', 'b'), sym("x") }, { CharacterSet().include('c', 'd'), choice({ sym("x"), sym("y") }) }, { CharacterSet().include('e', 'f'), sym("y") }, @@ -128,7 +91,7 @@ describe("char_transitions", []() { it("handles choices between whitelisted and blacklisted character sets", [&]() { AssertThat( - char_transitions(seq({ + rule_transitions(seq({ choice({ character({ '/' }, false), seq({ @@ -136,7 +99,7 @@ describe("char_transitions", []() { character({ '/' }) }) }), character({ '/' }) })), - Equals(rule_map({ + Equals(transition_map({ { CharacterSet() .include_all() .exclude('/') @@ -154,42 +117,42 @@ describe("char_transitions", []() { it("handles choices between a subset and a superset of characters", [&]() { AssertThat( - char_transitions(choice({ + rule_transitions(choice({ seq({ character({ 'b', 'c', 'd' }), sym("x") }), seq({ character({ 'a', 'b', 'c', 'd', 'e', 'f' }), sym("y") }) })), - Equals(rule_map({ + Equals(transition_map({ { CharacterSet().include('b', 'd'), choice({ sym("x"), sym("y") }) }, { CharacterSet().include('a').include('e', 'f'), sym("y") }, }))); AssertThat( - char_transitions(choice({ + rule_transitions(choice({ seq({ character({ 'a', 'b', 'c', 'd', 'e', 'f' }), sym("x") }), seq({ character({ 'b', 'c', 'd' }), sym("y") }) })), - Equals(rule_map({ + Equals(transition_map({ { CharacterSet().include('b', 'd'), choice({ sym("x"), sym("y") }) }, { CharacterSet().include('a').include('e', 'f'), sym("x") }, }))); }); it("handles blanks", [&]() { - AssertThat(char_transitions(blank()), Equals(rule_map({}))); + AssertThat(rule_transitions(blank()), Equals(transition_map({}))); }); it("handles repeats", [&]() { rule_ptr rule = repeat(seq({ character({ 'a' }), character({ 'b' }) })); AssertThat( - char_transitions(rule), - Equals(rule_map({ + rule_transitions(rule), + Equals(transition_map({ { CharacterSet().include('a'), seq({ @@ -200,8 +163,8 @@ describe("char_transitions", []() { rule = repeat(character({ 'a' })); AssertThat( - char_transitions(rule), - Equals(rule_map({ + rule_transitions(rule), + Equals(transition_map({ { CharacterSet().include('a'), rule } }))); }); diff --git a/src/compiler/build_tables/item_set_transitions.cc b/src/compiler/build_tables/item_set_transitions.cc index 273b4419..96e2cfdd 100644 --- a/src/compiler/build_tables/item_set_transitions.cc +++ b/src/compiler/build_tables/item_set_transitions.cc @@ -40,9 +40,9 @@ map sym_transitions(const ParseItemSet &input_item_set, map char_transitions(const LexItemSet &item_set) { map result; for (const LexItem &item : item_set) { - for (auto &transition : char_transitions(item.rule)) { + for (auto &transition : rule_transitions(item.rule)) { LexItem next_item(item.lhs, transition.second); - merge_char_transition( + merge_transition( &result, { transition.first, LexItemSet({ next_item }) }, [](LexItemSet *left, const LexItemSet *right) { left->insert(right->begin(), right->end()); diff --git a/src/compiler/build_tables/merge_transitions.h b/src/compiler/build_tables/merge_transitions.h index b7595a7f..0e2ecf7c 100644 --- a/src/compiler/build_tables/merge_transitions.h +++ b/src/compiler/build_tables/merge_transitions.h @@ -9,29 +9,6 @@ namespace tree_sitter { namespace build_tables { -/* - * Merges a new transition into a map with symbol keys. - * If the symbol already exists in the map, the new value for that - * symbol will be computed by merging the old and new values - * using the given function. - */ -template -void merge_sym_transition(std::map *left, - const std::pair &new_pair, - std::function merge_fn) { - auto new_symbol = new_pair.first; - for (auto &existing_pair : *left) { - auto existing_symbol = existing_pair.first; - if (new_symbol < existing_symbol) - break; - if (existing_symbol == new_symbol) { - merge_fn(&existing_pair.second, &new_pair.second); - return; - } - } - left->insert(new_pair); -} - /* * Merges two transition maps with character set keys. If the * two maps contain values for overlapping character sets, the @@ -39,9 +16,9 @@ void merge_sym_transition(std::map *left, * merging the old and new values using the given function. */ template -void merge_char_transition(std::map *left, - const std::pair &new_pair, - std::function merge_fn) { +void merge_transition(std::map *left, + const std::pair &new_pair, + std::function merge_fn) { rules::CharacterSet new_char_set = new_pair.first; T new_value = new_pair.second; diff --git a/src/compiler/build_tables/rule_transitions.cc b/src/compiler/build_tables/rule_transitions.cc index 319624da..1822b3fc 100644 --- a/src/compiler/build_tables/rule_transitions.cc +++ b/src/compiler/build_tables/rule_transitions.cc @@ -19,72 +19,46 @@ using rules::CharacterSet; using rules::Choice; using rules::Symbol; -template -void merge_transitions(map *, const map &); - -struct MergeAsChoice { - void operator()(rule_ptr *left, const rule_ptr *right) { - *left = Choice::build({ *left, *right }); - } -}; - -template <> -void merge_transitions(map *left, - const map &right) { - for (auto &pair : right) - merge_char_transition(left, pair, MergeAsChoice()); -} - -template <> -void merge_transitions(map *left, - const map &right) { - for (auto &pair : right) - merge_sym_transition(left, pair, MergeAsChoice()); -} - -template -class RuleTransitions : public rules::RuleFn> { +class RuleTransitions : public rules::RuleFn> { private: - map apply_to_primitive(const Rule *rule) { - auto primitive = dynamic_cast(rule); - if (primitive) - return map({ { *primitive, make_shared() } }); - else - return map(); + void merge_transitions(map *left, + const map &right) { + for (auto &pair : right) + merge_transition( + left, pair, [](rule_ptr *left, const rule_ptr *right) { + *left = Choice::build({ *left, *right }); + }); } - map apply_to(const CharacterSet *rule) { - return apply_to_primitive(rule); + map apply_to(const CharacterSet *rule) { + return map( + { { *rule, make_shared() } }); } - map apply_to(const Symbol *rule) { - return apply_to_primitive(rule); - } - - map apply_to(const rules::Choice *rule) { - map result; + map apply_to(const rules::Choice *rule) { + map result; for (const auto &el : rule->elements) - merge_transitions(&result, this->apply(el)); + merge_transitions(&result, this->apply(el)); return result; } - map apply_to(const rules::Seq *rule) { + map apply_to(const rules::Seq *rule) { auto result = this->apply(rule->left); for (auto &pair : result) pair.second = rules::Seq::build({ pair.second, rule->right }); if (rule_can_be_blank(rule->left)) - merge_transitions(&result, this->apply(rule->right)); + merge_transitions(&result, this->apply(rule->right)); return result; } - map apply_to(const rules::Repeat *rule) { + map apply_to(const rules::Repeat *rule) { auto result = this->apply(rule->content); for (auto &pair : result) pair.second = rules::Seq::build({ pair.second, rule->copy() }); return result; } - map apply_to(const rules::Metadata *rule) { + map apply_to(const rules::Metadata *rule) { auto result = this->apply(rule->rule); for (auto &pair : result) pair.second = make_shared(pair.second, rule->value); @@ -92,12 +66,8 @@ class RuleTransitions : public rules::RuleFn> { } }; -map char_transitions(const rule_ptr &rule) { - return RuleTransitions().apply(rule); -} - -map sym_transitions(const rule_ptr &rule) { - return RuleTransitions().apply(rule); +map rule_transitions(const rule_ptr &rule) { + return RuleTransitions().apply(rule); } } // namespace build_tables diff --git a/src/compiler/build_tables/rule_transitions.h b/src/compiler/build_tables/rule_transitions.h index 789f1e55..b97ded09 100644 --- a/src/compiler/build_tables/rule_transitions.h +++ b/src/compiler/build_tables/rule_transitions.h @@ -8,9 +8,7 @@ namespace tree_sitter { namespace build_tables { -std::map char_transitions(const rule_ptr &rule); - -std::map sym_transitions(const rule_ptr &rule); +std::map rule_transitions(const rule_ptr &); } // namespace build_tables } // namespace tree_sitter