Represent rule metadata as a struct, not a map
This commit is contained in:
parent
cac4f5d5bc
commit
6cf4ccb840
17 changed files with 158 additions and 108 deletions
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -49,10 +49,10 @@ describe("rule_can_be_blank", [&]() {
|
|||
});
|
||||
|
||||
it("ignores metadata rules", [&]() {
|
||||
rule = make_shared<rules::Metadata>(blank(), map<rules::MetadataKey, int>());
|
||||
rule = make_shared<rules::Metadata>(blank(), MetadataParams());
|
||||
AssertThat(rule_can_be_blank(rule), IsTrue());
|
||||
|
||||
rule = make_shared<rules::Metadata>(sym("one"), map<rules::MetadataKey, int>());
|
||||
rule = make_shared<rules::Metadata>(sym("one"), MetadataParams());
|
||||
AssertThat(rule_can_be_blank(rule), IsFalse());
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -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)),
|
||||
})));
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -35,15 +35,16 @@ namespace tree_sitter {
|
|||
return make_shared<rules::Symbol>(index, true);
|
||||
}
|
||||
|
||||
rule_ptr metadata(rule_ptr rule, map<rules::MetadataKey, int> values) {
|
||||
return make_shared<rules::Metadata>(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<rules::Metadata>(rule, map<rules::MetadataKey, int>({
|
||||
{ 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) {
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@
|
|||
#include "compiler/variable.h"
|
||||
|
||||
namespace tree_sitter {
|
||||
rule_ptr metadata(rule_ptr, std::map<rules::MetadataKey, int>);
|
||||
rule_ptr metadata(rule_ptr, rules::MetadataParams params);
|
||||
rule_ptr character(const std::set<uint32_t> &);
|
||||
rule_ptr character(const std::set<uint32_t> &, bool sign);
|
||||
rule_ptr i_sym(size_t index);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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> {
|
|||
}
|
||||
|
||||
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<void> {
|
|||
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);
|
||||
}));
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -44,11 +44,11 @@ class ExpandTokens : public rules::IdentityRuleFn {
|
|||
elements.push_back(rules::CharacterSet().include(el).copy());
|
||||
}
|
||||
|
||||
return make_shared<rules::Metadata>(
|
||||
rules::Seq::build(elements),
|
||||
std::map<rules::MetadataKey, int>({
|
||||
{ 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) {
|
||||
|
|
|
|||
|
|
@ -10,7 +10,6 @@
|
|||
namespace tree_sitter {
|
||||
namespace prepare_grammar {
|
||||
|
||||
using std::make_shared;
|
||||
using std::vector;
|
||||
|
||||
class ExtractChoices : public rules::RuleFn<vector<rule_ptr>> {
|
||||
|
|
@ -29,7 +28,7 @@ class ExtractChoices : public rules::RuleFn<vector<rule_ptr>> {
|
|||
vector<rule_ptr> apply_to(const rules::Metadata *rule) {
|
||||
vector<rule_ptr> result;
|
||||
for (auto entry : apply(rule->rule))
|
||||
result.push_back(make_shared<rules::Metadata>(entry, rule->value));
|
||||
result.push_back(rules::Metadata::build(entry, rule->params));
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -29,24 +29,20 @@ class FlattenRule : public rules::RuleFn<void> {
|
|||
}
|
||||
|
||||
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<rules::Associativity>(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();
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ class IsToken : public rules::RuleFn<bool> {
|
|||
}
|
||||
|
||||
bool apply_to(const rules::Metadata *rule) {
|
||||
return rule->value_for(rules::IS_TOKEN).second;
|
||||
return rule->params.is_token;
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
#include "compiler/rules/metadata.h"
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include <climits>
|
||||
#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<MetadataKey, int> 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<MetadataKey, int> values) {
|
||||
return std::make_shared<Metadata>(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<Metadata>(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<Metadata>();
|
||||
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<int>(&result, pair.first);
|
||||
hash_combine(&result, pair.second);
|
||||
}
|
||||
hash_combine(&result, params.precedence);
|
||||
hash_combine<int>(&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<Metadata>(rule->copy(), value);
|
||||
}
|
||||
|
||||
pair<int, bool> 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<Metadata>(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 {
|
||||
|
|
|
|||
|
|
@ -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<MetadataKey, int> value);
|
||||
static rule_ptr build(rule_ptr rule, std::map<MetadataKey, int> 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<int, bool> value_for(MetadataKey key) const;
|
||||
|
||||
const rule_ptr rule;
|
||||
const std::map<MetadataKey, int> value;
|
||||
MetadataParams params;
|
||||
};
|
||||
|
||||
} // namespace rules
|
||||
|
|
|
|||
|
|
@ -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<rules::MetadataKey, int> values) {
|
||||
return std::make_shared<rules::Metadata>(rule, values);
|
||||
static rule_ptr metadata(rule_ptr rule, MetadataParams params) {
|
||||
return std::make_shared<rules::Metadata>(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
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ rule_ptr IdentityRuleFn::apply_to(const Repeat *rule) {
|
|||
}
|
||||
|
||||
rule_ptr IdentityRuleFn::apply_to(const Metadata *rule) {
|
||||
return std::make_shared<Metadata>(apply(rule->rule), rule->value);
|
||||
return Metadata::build(apply(rule->rule), rule->params);
|
||||
}
|
||||
|
||||
} // namespace rules
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue