From 6cf4ccb8408bc3e5ba71ef958de7a4cfb57bd1d6 Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Sat, 19 Nov 2016 13:53:16 -0800 Subject: [PATCH] Represent rule metadata as a struct, not a map --- spec/compiler/build_tables/lex_item_spec.cc | 15 ++-- .../build_tables/rule_can_be_blank_spec.cc | 4 +- .../prepare_grammar/expand_tokens_spec.cc | 14 ++-- spec/helpers/rule_helpers.cc | 13 +-- spec/helpers/rule_helpers.h | 2 +- src/compiler/build_tables/build_lex_table.cc | 9 +-- src/compiler/build_tables/lex_item.cc | 6 +- .../build_tables/lex_item_transitions.cc | 20 ++--- src/compiler/prepare_grammar/expand_tokens.cc | 10 +-- .../prepare_grammar/extract_choices.cc | 3 +- .../prepare_grammar/extract_tokens.cc | 2 +- .../prepare_grammar/flatten_grammar.cc | 16 ++-- src/compiler/prepare_grammar/is_token.cc | 2 +- src/compiler/rules/metadata.cc | 80 +++++++++++++------ src/compiler/rules/metadata.h | 28 ++++--- src/compiler/rules/rules.cc | 40 +++++++--- src/compiler/rules/visitor.cc | 2 +- 17 files changed, 158 insertions(+), 108 deletions(-) diff --git a/spec/compiler/build_tables/lex_item_spec.cc b/spec/compiler/build_tables/lex_item_spec.cc index 4a867915..94997956 100644 --- a/spec/compiler/build_tables/lex_item_spec.cc +++ b/spec/compiler/build_tables/lex_item_spec.cc @@ -19,8 +19,12 @@ describe("LexItem", []() { AssertThat(item1.completion_status().precedence, Equals(PrecedenceRange())); AssertThat(item1.completion_status().is_string, IsFalse()); + MetadataParams params; + params.precedence = 3; + params.has_precedence = true; + params.is_string = 1; LexItem item2(Symbol(0, true), choice({ - metadata(blank(), { {PRECEDENCE, 3}, {IS_STRING, 1} }), + metadata(blank(), params), character({ 'a', 'b', 'c' }) })); @@ -59,10 +63,11 @@ describe("LexItemSet::transitions()", [&]() { }); it("marks transitions that are within the main token (as opposed to separators)", [&]() { + MetadataParams params; + params.is_main_token = true; + LexItemSet item_set({ - LexItem(Symbol(1), metadata(character({ 'x' }), { - {MAIN_TOKEN, true} - })), + LexItem(Symbol(1), metadata(character({ 'x' }), params)), }); AssertThat( @@ -72,7 +77,7 @@ describe("LexItemSet::transitions()", [&]() { CharacterSet().include('x'), Transition{ LexItemSet({ - LexItem(Symbol(1), metadata(blank(), { {MAIN_TOKEN, true}})), + LexItem(Symbol(1), metadata(blank(), params)), }), PrecedenceRange(), true diff --git a/spec/compiler/build_tables/rule_can_be_blank_spec.cc b/spec/compiler/build_tables/rule_can_be_blank_spec.cc index c5074df9..61aa92bc 100644 --- a/spec/compiler/build_tables/rule_can_be_blank_spec.cc +++ b/spec/compiler/build_tables/rule_can_be_blank_spec.cc @@ -49,10 +49,10 @@ describe("rule_can_be_blank", [&]() { }); it("ignores metadata rules", [&]() { - rule = make_shared(blank(), map()); + rule = make_shared(blank(), MetadataParams()); AssertThat(rule_can_be_blank(rule), IsTrue()); - rule = make_shared(sym("one"), map()); + rule = make_shared(sym("one"), MetadataParams()); AssertThat(rule_can_be_blank(rule), IsFalse()); }); }); diff --git a/spec/compiler/prepare_grammar/expand_tokens_spec.cc b/spec/compiler/prepare_grammar/expand_tokens_spec.cc index a2e11538..0aa83b3a 100644 --- a/spec/compiler/prepare_grammar/expand_tokens_spec.cc +++ b/spec/compiler/prepare_grammar/expand_tokens_spec.cc @@ -9,6 +9,10 @@ using namespace rules; using prepare_grammar::expand_tokens; describe("expand_tokens", []() { + MetadataParams string_token_params; + string_token_params.is_string = true; + string_token_params.is_token = true; + describe("string rules", [&]() { it("replaces strings with sequences of character sets", [&]() { LexicalGrammar grammar{{ @@ -29,10 +33,7 @@ describe("expand_tokens", []() { character({ 'x' }), character({ 'y' }), character({ 'z' }), - }), { - {IS_STRING, 1}, - {IS_TOKEN, 1}, - }), + }), string_token_params), i_sym(11), })), }))); @@ -50,10 +51,7 @@ describe("expand_tokens", []() { character({ 945 }), character({ ' ' }), character({ 946 }), - }), { - {IS_STRING, 1}, - {IS_TOKEN, 1}, - })), + }), string_token_params)), }))); }); }); diff --git a/spec/helpers/rule_helpers.cc b/spec/helpers/rule_helpers.cc index 31141d3e..8bf32360 100644 --- a/spec/helpers/rule_helpers.cc +++ b/spec/helpers/rule_helpers.cc @@ -35,15 +35,16 @@ namespace tree_sitter { return make_shared(index, true); } - rule_ptr metadata(rule_ptr rule, map values) { - return make_shared(rule, values); + rule_ptr metadata(rule_ptr rule, rules::MetadataParams params) { + return rules::Metadata::build(rule, params); } rule_ptr active_prec(int precedence, rule_ptr rule) { - return std::make_shared(rule, map({ - { rules::PRECEDENCE, precedence }, - { rules::IS_ACTIVE, true } - })); + rules::MetadataParams params; + params.precedence = precedence; + params.has_precedence = true; + params.is_active = true; + return rules::Metadata::build(rule, params); } bool operator==(const Variable &left, const Variable &right) { diff --git a/spec/helpers/rule_helpers.h b/spec/helpers/rule_helpers.h index e29208e8..a985d294 100644 --- a/spec/helpers/rule_helpers.h +++ b/spec/helpers/rule_helpers.h @@ -8,7 +8,7 @@ #include "compiler/variable.h" namespace tree_sitter { - rule_ptr metadata(rule_ptr, std::map); + rule_ptr metadata(rule_ptr, rules::MetadataParams params); rule_ptr character(const std::set &); rule_ptr character(const std::set &, bool sign); rule_ptr i_sym(size_t index); diff --git a/src/compiler/build_tables/build_lex_table.cc b/src/compiler/build_tables/build_lex_table.cc index d55e1c94..151da7cf 100644 --- a/src/compiler/build_tables/build_lex_table.cc +++ b/src/compiler/build_tables/build_lex_table.cc @@ -34,9 +34,6 @@ using rules::Repeat; using rules::Symbol; using rules::Metadata; using rules::Seq; -using rules::MAIN_TOKEN; -using rules::PRECEDENCE; -using rules::IS_ACTIVE; class LexTableBuilder { LexTable lex_table; @@ -160,12 +157,10 @@ class LexTableBuilder { for (const rule_ptr &separator_rule : separator_rules) result.entries.insert(LexItem( symbol, - Metadata::build( + Metadata::separator( Seq::build({ separator_rule, - Metadata::build(rule, { { PRECEDENCE, 0 }, { MAIN_TOKEN, 1 } }), - }), - { { PRECEDENCE, INT_MIN }, { IS_ACTIVE, true } }))); + Metadata::main_token(rule) })))); return result; } diff --git a/src/compiler/build_tables/lex_item.cc b/src/compiler/build_tables/lex_item.cc index 5272f3bd..152b2469 100644 --- a/src/compiler/build_tables/lex_item.cc +++ b/src/compiler/build_tables/lex_item.cc @@ -41,9 +41,9 @@ LexItem::CompletionStatus LexItem::completion_status() const { CompletionStatus apply_to(const rules::Metadata *rule) { CompletionStatus result = apply(rule->rule); if (result.is_done) { - if (result.precedence.empty && rule->value_for(rules::PRECEDENCE).second) - result.precedence.add(rule->value_for(rules::PRECEDENCE).first); - if (rule->value_for(rules::IS_STRING).second) + if (result.precedence.empty && rule->params.has_precedence) + result.precedence.add(rule->params.precedence); + if (rule->params.is_string) result.is_string = true; } return result; diff --git a/src/compiler/build_tables/lex_item_transitions.cc b/src/compiler/build_tables/lex_item_transitions.cc index f1050ead..9dc4f762 100644 --- a/src/compiler/build_tables/lex_item_transitions.cc +++ b/src/compiler/build_tables/lex_item_transitions.cc @@ -25,14 +25,10 @@ using std::vector; using rules::CharacterSet; using rules::Symbol; using rules::Blank; -using rules::MetadataKey; using rules::Choice; using rules::Seq; using rules::Repeat; using rules::Metadata; -using rules::PRECEDENCE; -using rules::IS_ACTIVE; -using rules::MAIN_TOKEN; typedef LexItemSet::Transition Transition; typedef LexItemSet::TransitionMap TransitionMap; @@ -141,16 +137,16 @@ class TransitionBuilder : public rules::RuleFn { } void apply_to(const Metadata *metadata) { - bool has_active_precedence = metadata->value_for(IS_ACTIVE).second; + bool has_active_precedence = metadata->params.is_active; if (has_active_precedence) - precedence_stack->push_back(metadata->value_for(PRECEDENCE).first); + precedence_stack->push_back(metadata->params.precedence); - if (metadata->value_for(MAIN_TOKEN).second) + if (metadata->params.is_main_token) in_main_token = true; - auto metadata_value = metadata->value; - if (metadata_value.count(PRECEDENCE)) - metadata_value.insert({ IS_ACTIVE, true }); + rules::MetadataParams params = metadata->params; + if (params.has_precedence) + params.is_active = true; TransitionMap content_transitions; TransitionBuilder(&content_transitions, this).apply(metadata->rule); @@ -158,8 +154,8 @@ class TransitionBuilder : public rules::RuleFn { for (const auto &pair : content_transitions) { add_transition( transitions, pair.first, - transform_transition(pair.second, [&metadata_value](rule_ptr rule) { - return Metadata::build(rule, metadata_value); + transform_transition(pair.second, [¶ms](rule_ptr rule) { + return Metadata::build(rule, params); })); } diff --git a/src/compiler/prepare_grammar/expand_tokens.cc b/src/compiler/prepare_grammar/expand_tokens.cc index 4f49244b..b024e27c 100644 --- a/src/compiler/prepare_grammar/expand_tokens.cc +++ b/src/compiler/prepare_grammar/expand_tokens.cc @@ -44,11 +44,11 @@ class ExpandTokens : public rules::IdentityRuleFn { elements.push_back(rules::CharacterSet().include(el).copy()); } - return make_shared( - rules::Seq::build(elements), - std::map({ - { rules::IS_TOKEN, 1 }, { rules::IS_STRING, 1 }, - })); + rules::MetadataParams params; + params.is_token = true; + params.is_string = true; + + return rules::Metadata::build(rules::Seq::build(elements), params); } rule_ptr apply_to(const Pattern *rule) { diff --git a/src/compiler/prepare_grammar/extract_choices.cc b/src/compiler/prepare_grammar/extract_choices.cc index 043b5653..6262001c 100644 --- a/src/compiler/prepare_grammar/extract_choices.cc +++ b/src/compiler/prepare_grammar/extract_choices.cc @@ -10,7 +10,6 @@ namespace tree_sitter { namespace prepare_grammar { -using std::make_shared; using std::vector; class ExtractChoices : public rules::RuleFn> { @@ -29,7 +28,7 @@ class ExtractChoices : public rules::RuleFn> { vector apply_to(const rules::Metadata *rule) { vector result; for (auto entry : apply(rule->rule)) - result.push_back(make_shared(entry, rule->value)); + result.push_back(rules::Metadata::build(entry, rule->params)); return result; } diff --git a/src/compiler/prepare_grammar/extract_tokens.cc b/src/compiler/prepare_grammar/extract_tokens.cc index ebc7a36e..bf7ac514 100644 --- a/src/compiler/prepare_grammar/extract_tokens.cc +++ b/src/compiler/prepare_grammar/extract_tokens.cc @@ -79,7 +79,7 @@ class TokenExtractor : public rules::IdentityRuleFn { } rule_ptr apply_to(const rules::Metadata *rule) { - if (rule->value_for(rules::IS_TOKEN).second) + if (rule->params.is_token) return apply_to_token(rule->rule.get(), VariableTypeAuxiliary); else return rules::IdentityRuleFn::apply_to(rule); diff --git a/src/compiler/prepare_grammar/flatten_grammar.cc b/src/compiler/prepare_grammar/flatten_grammar.cc index 85093298..fa253718 100644 --- a/src/compiler/prepare_grammar/flatten_grammar.cc +++ b/src/compiler/prepare_grammar/flatten_grammar.cc @@ -29,24 +29,20 @@ class FlattenRule : public rules::RuleFn { } void apply_to(const rules::Metadata *metadata) { - auto precedence = metadata->value_for(rules::PRECEDENCE); - auto associativity = metadata->value_for(rules::ASSOCIATIVITY); - - if (precedence.second) - precedence_stack.push_back(precedence.first); - if (associativity.second) - associativity_stack.push_back( - static_cast(associativity.first)); + if (metadata->params.has_precedence) + precedence_stack.push_back(metadata->params.precedence); + if (metadata->params.has_associativity) + associativity_stack.push_back(metadata->params.associativity); apply(metadata->rule); - if (precedence.second) { + if (metadata->params.has_precedence) { last_precedence = precedence_stack.back(); precedence_stack.pop_back(); production.back().precedence = precedence_stack.back(); } - if (associativity.second) { + if (metadata->params.has_associativity) { last_associativity = associativity_stack.back(); associativity_stack.pop_back(); production.back().associativity = associativity_stack.back(); diff --git a/src/compiler/prepare_grammar/is_token.cc b/src/compiler/prepare_grammar/is_token.cc index b7dfab1f..4d209882 100644 --- a/src/compiler/prepare_grammar/is_token.cc +++ b/src/compiler/prepare_grammar/is_token.cc @@ -18,7 +18,7 @@ class IsToken : public rules::RuleFn { } bool apply_to(const rules::Metadata *rule) { - return rule->value_for(rules::IS_TOKEN).second; + return rule->params.is_token; } }; diff --git a/src/compiler/rules/metadata.cc b/src/compiler/rules/metadata.cc index 97fd0fed..5b9724d8 100644 --- a/src/compiler/rules/metadata.cc +++ b/src/compiler/rules/metadata.cc @@ -1,6 +1,7 @@ #include "compiler/rules/metadata.h" #include #include +#include #include "compiler/rules/visitor.h" #include "compiler/rules/blank.h" #include "compiler/util/hash_combine.h" @@ -13,47 +14,80 @@ using std::map; using std::pair; using util::hash_combine; -Metadata::Metadata(rule_ptr rule, map values) - : rule(rule), value(values) {} +MetadataParams::MetadataParams() : + precedence{0}, + associativity{AssociativityNone}, + has_precedence{false}, + has_associativity{false}, + is_token{false}, + is_string{false}, + is_active{false}, + is_main_token{false} {} -rule_ptr Metadata::build(rule_ptr rule, map values) { - return std::make_shared(rule, values); +bool MetadataParams::operator==(const MetadataParams &other) const { + return + precedence == other.precedence && + associativity == other.associativity && + has_precedence == other.has_precedence && + has_associativity == other.has_associativity && + is_token == other.is_token && + is_string == other.is_string && + is_active == other.is_active && + is_main_token == other.is_main_token; +} + +Metadata::Metadata(rule_ptr rule, MetadataParams params) + : rule(rule), params(params) {} + +rule_ptr Metadata::build(rule_ptr rule, MetadataParams params) { + return std::make_shared(rule, params); +} + +rule_ptr Metadata::main_token(rule_ptr rule) { + MetadataParams params; + params.has_precedence = true; + params.precedence = 0; + params.is_main_token = true; + return Metadata::build(rule, params); +} + +rule_ptr Metadata::separator(rule_ptr rule) { + MetadataParams params; + params.has_precedence = true; + params.precedence = INT_MIN; + params.is_active = true; + return Metadata::build(rule, params); } bool Metadata::operator==(const Rule &rule) const { auto other = rule.as(); - return other && other->value == value && other->rule->operator==(*this->rule); + return other && other->params == params && other->rule->operator==(*this->rule); } size_t Metadata::hash_code() const { size_t result = 0; - hash_combine(&result, value.size()); - for (auto &pair : value) { - hash_combine(&result, pair.first); - hash_combine(&result, pair.second); - } + hash_combine(&result, params.precedence); + hash_combine(&result, params.associativity); + hash_combine(&result, params.has_precedence); + hash_combine(&result, params.has_associativity); + hash_combine(&result, params.is_token); + hash_combine(&result, params.is_string); + hash_combine(&result, params.is_active); + hash_combine(&result, params.is_main_token); return result; } rule_ptr Metadata::copy() const { - return make_shared(rule->copy(), value); -} - -pair Metadata::value_for(MetadataKey key) const { - auto entry = value.find(key); - if (entry == value.end()) - return { 0, false }; - else - return { entry->second, true }; + return make_shared(rule->copy(), params); } std::string Metadata::to_string() const { - auto precedence = value_for(rules::PRECEDENCE); - if (precedence.second && value_for(rules::IS_ACTIVE).second) - return "(metadata prec:" + std::to_string(precedence.first) + " " + + if (params.has_precedence) { + return "(metadata prec:" + std::to_string(params.precedence) + " " + rule->to_string() + ")"; - else + } else { return "(metadata " + rule->to_string() + ")"; + } } void Metadata::accept(Visitor *visitor) const { diff --git a/src/compiler/rules/metadata.h b/src/compiler/rules/metadata.h index 72cdbed0..a9f43c2f 100644 --- a/src/compiler/rules/metadata.h +++ b/src/compiler/rules/metadata.h @@ -14,29 +14,35 @@ enum Associativity { AssociativityRight, }; -enum MetadataKey { - MAIN_TOKEN, - PRECEDENCE, - ASSOCIATIVITY, - IS_TOKEN, - IS_STRING, - IS_ACTIVE, +struct MetadataParams { + int precedence; + Associativity associativity; + bool has_precedence; + bool has_associativity; + bool is_token; + bool is_string; + bool is_active; + bool is_main_token; + + MetadataParams(); + bool operator==(const MetadataParams &) const; }; class Metadata : public Rule { public: - Metadata(rule_ptr rule, std::map value); - static rule_ptr build(rule_ptr rule, std::map value); + Metadata(rule_ptr rule, MetadataParams); + static rule_ptr build(rule_ptr rule, MetadataParams); + static rule_ptr main_token(rule_ptr rule); + static rule_ptr separator(rule_ptr rule); bool operator==(const Rule &other) const; size_t hash_code() const; rule_ptr copy() const; std::string to_string() const; void accept(Visitor *visitor) const; - std::pair value_for(MetadataKey key) const; const rule_ptr rule; - const std::map value; + MetadataParams params; }; } // namespace rules diff --git a/src/compiler/rules/rules.cc b/src/compiler/rules/rules.cc index b61358e8..fdb0ebdf 100644 --- a/src/compiler/rules/rules.cc +++ b/src/compiler/rules/rules.cc @@ -22,9 +22,10 @@ using std::string; using std::set; using std::vector; using std::map; +using rules::MetadataParams; -static rule_ptr metadata(rule_ptr rule, map values) { - return std::make_shared(rule, values); +static rule_ptr metadata(rule_ptr rule, MetadataParams params) { + return std::make_shared(rule, params); } rule_ptr blank() { @@ -60,29 +61,48 @@ rule_ptr str(const string &value) { } rule_ptr prec_left(const rule_ptr &rule) { - return metadata(rule, { { rules::ASSOCIATIVITY, rules::AssociativityLeft } }); + MetadataParams params; + params.has_associativity = true; + params.associativity = rules::AssociativityLeft; + return metadata(rule, params); } rule_ptr prec_left(int precedence, const rule_ptr &rule) { - return metadata(rule, { { rules::PRECEDENCE, precedence }, - { rules::ASSOCIATIVITY, rules::AssociativityLeft } }); + MetadataParams params; + params.has_associativity = true; + params.associativity = rules::AssociativityLeft; + params.has_precedence = true; + params.precedence = precedence; + return metadata(rule, params); } rule_ptr prec_right(const rule_ptr &rule) { - return metadata(rule, { { rules::ASSOCIATIVITY, rules::AssociativityRight } }); + MetadataParams params; + params.has_associativity = true; + params.associativity = rules::AssociativityRight; + return metadata(rule, params); } rule_ptr prec_right(int precedence, const rule_ptr &rule) { - return metadata(rule, { { rules::PRECEDENCE, precedence }, - { rules::ASSOCIATIVITY, rules::AssociativityRight } }); + MetadataParams params; + params.has_associativity = true; + params.associativity = rules::AssociativityRight; + params.has_precedence = true; + params.precedence = precedence; + return metadata(rule, params); } rule_ptr prec(int precedence, const rule_ptr &rule) { - return metadata(rule, { { rules::PRECEDENCE, precedence } }); + MetadataParams params; + params.has_precedence = true; + params.precedence = precedence; + return metadata(rule, params); } rule_ptr token(const rule_ptr &rule) { - return metadata(rule, { { rules::IS_TOKEN, 1 } }); + MetadataParams params; + params.is_token = true; + return metadata(rule, params); } } // namespace tree_sitter diff --git a/src/compiler/rules/visitor.cc b/src/compiler/rules/visitor.cc index db3600ce..e06f6c7f 100644 --- a/src/compiler/rules/visitor.cc +++ b/src/compiler/rules/visitor.cc @@ -37,7 +37,7 @@ rule_ptr IdentityRuleFn::apply_to(const Repeat *rule) { } rule_ptr IdentityRuleFn::apply_to(const Metadata *rule) { - return std::make_shared(apply(rule->rule), rule->value); + return Metadata::build(apply(rule->rule), rule->params); } } // namespace rules