Fix error in merging character set transitions

This commit is contained in:
Max Brunsfeld 2014-04-01 13:18:12 -07:00
parent 2a222adb7e
commit 85b97c4f87
3 changed files with 45 additions and 13 deletions

View file

@ -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>({
{ 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>({
{ CharacterSet({ {'a', 'c'} }), choice({ sym("x"), sym("y") }) },
{ CharacterSet({ {'d', 'z'} }), sym("x") },
})));
});
it("handles blanks", [&]() {
AssertThat(char_transitions(blank()), Equals(rule_map<CharacterSet>({})));
});

View file

@ -49,19 +49,25 @@ namespace tree_sitter {
const std::map<rules::CharacterSet, T> &right,
std::function<T(T, T)> merge_fn) {
std::map<rules::CharacterSet, T> 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;
}

View file

@ -26,19 +26,17 @@ namespace tree_sitter {
template<>
map<CharacterSet, rule_ptr>
merge_transitions(const map<CharacterSet, rule_ptr> &left, const map<CharacterSet, rule_ptr> &right) {
auto transitions = merge_char_transitions<rule_ptr>(left, right, [](rule_ptr left, rule_ptr right) {
return merge_char_transitions<rule_ptr>(left, right, [](rule_ptr left, rule_ptr right) {
return make_shared<rules::Choice>(left, right);
});
return *static_cast<map<CharacterSet, rule_ptr> *>(&transitions);
}
template<>
map<Symbol, rule_ptr>
merge_transitions(const map<Symbol, rule_ptr> &left, const map<Symbol, rule_ptr> &right) {
auto transitions = merge_sym_transitions<rule_ptr>(left, right, [](rule_ptr left, rule_ptr right) {
return merge_sym_transitions<rule_ptr>(left, right, [](rule_ptr left, rule_ptr right) {
return make_shared<rules::Choice>(left, right);
});
return *static_cast<map<Symbol, rule_ptr> *>(&transitions);
}
template<typename T>