From 85b97c4f872e1d8f0bd17bdd734e61979acd31aa Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Tue, 1 Apr 2014 13:18:12 -0700 Subject: [PATCH] Fix error in merging character set transitions --- .../build_tables/rule_transitions_spec.cc | 30 ++++++++++++++++++- src/compiler/build_tables/merge_transitions.h | 22 +++++++++----- src/compiler/build_tables/rule_transitions.cc | 6 ++-- 3 files changed, 45 insertions(+), 13 deletions(-) diff --git a/spec/compiler/build_tables/rule_transitions_spec.cc b/spec/compiler/build_tables/rule_transitions_spec.cc index 4bb437b6..869c8d33 100644 --- a/spec/compiler/build_tables/rule_transitions_spec.cc +++ b/spec/compiler/build_tables/rule_transitions_spec.cc @@ -113,7 +113,6 @@ describe("rule transitions", []() { }))); }); - it("handles choices between overlapping character sets", [&]() { AssertThat( char_transitions(choice({ @@ -130,6 +129,35 @@ describe("rule transitions", []() { }))); }); + it("handles choices between a subset and a superset of characters", [&]() { + AssertThat( + char_transitions(choice({ + seq({ + character({ {'a', 'c'} }), + sym("x") }), + seq({ + character({ { 'a', 'z' } }), + sym("y") }) })), + Equals(rule_map({ + { CharacterSet({ {'a', 'c'} }), choice({ sym("x"), sym("y") }) }, + { CharacterSet({ {'d', 'z'} }), sym("y") }, + }))); + + AssertThat( + char_transitions(choice({ + seq({ + character({ { 'a', 'z' } }), + sym("x") }), + seq({ + character({ {'a', 'c'} }), + sym("y") }) })), + Equals(rule_map({ + { CharacterSet({ {'a', 'c'} }), choice({ sym("x"), sym("y") }) }, + { CharacterSet({ {'d', 'z'} }), sym("x") }, + }))); + + }); + it("handles blanks", [&]() { AssertThat(char_transitions(blank()), Equals(rule_map({}))); }); diff --git a/src/compiler/build_tables/merge_transitions.h b/src/compiler/build_tables/merge_transitions.h index 9032f590..707e1e89 100644 --- a/src/compiler/build_tables/merge_transitions.h +++ b/src/compiler/build_tables/merge_transitions.h @@ -49,19 +49,25 @@ namespace tree_sitter { const std::map &right, std::function merge_fn) { std::map result(left); - for (auto &pair : right) { - auto rule = pair.first; + for (auto &new_pair : right) { + rules::CharacterSet new_rule = new_pair.first; + T new_value = new_pair.second; + for (auto &existing_pair : left) { - auto existing_rule = existing_pair.first; - auto intersection = existing_rule.remove_set(rule); + rules::CharacterSet existing_rule = existing_pair.first; + T existing_value = existing_pair.second; + + rules::CharacterSet intersection = existing_rule.remove_set(new_rule); if (!intersection.is_empty()) { result.erase(existing_pair.first); - result.insert({ existing_rule, existing_pair.second }); - rule.remove_set(intersection); - result.insert({ intersection, merge_fn(existing_pair.second, pair.second) }); + if (!existing_rule.is_empty()) + result.insert({ existing_rule, existing_value }); + result.insert({ intersection, merge_fn(existing_value, new_value) }); + new_rule.remove_set(intersection); } } - result.insert({ rule, pair.second }); + if (!new_rule.is_empty()) + result.insert({ new_rule, new_pair.second }); } return result; } diff --git a/src/compiler/build_tables/rule_transitions.cc b/src/compiler/build_tables/rule_transitions.cc index 1e28b85f..332b0aaf 100644 --- a/src/compiler/build_tables/rule_transitions.cc +++ b/src/compiler/build_tables/rule_transitions.cc @@ -26,19 +26,17 @@ namespace tree_sitter { template<> map merge_transitions(const map &left, const map &right) { - auto transitions = merge_char_transitions(left, right, [](rule_ptr left, rule_ptr right) { + return merge_char_transitions(left, right, [](rule_ptr left, rule_ptr right) { return make_shared(left, right); }); - return *static_cast *>(&transitions); } template<> map merge_transitions(const map &left, const map &right) { - auto transitions = merge_sym_transitions(left, right, [](rule_ptr left, rule_ptr right) { + return merge_sym_transitions(left, right, [](rule_ptr left, rule_ptr right) { return make_shared(left, right); }); - return *static_cast *>(&transitions); } template