tree-sitter/src/compiler/build_tables/lex_item.cc
2015-10-30 16:48:37 -07:00

122 lines
3.4 KiB
C++

#include "compiler/build_tables/lex_item.h"
#include <unordered_set>
#include "compiler/build_tables/lex_item_transitions.h"
#include "compiler/build_tables/rule_can_be_blank.h"
#include "compiler/rules/choice.h"
#include "compiler/rules/metadata.h"
#include "compiler/rules/seq.h"
#include "compiler/rules/symbol.h"
#include "compiler/rules/repeat.h"
#include "compiler/rules/visitor.h"
namespace tree_sitter {
namespace build_tables {
using std::hash;
using std::map;
using std::string;
using std::unordered_set;
using rules::CharacterSet;
using rules::Symbol;
LexItem::LexItem(const rules::Symbol &lhs, const rule_ptr rule)
: lhs(lhs), rule(rule) {}
bool LexItem::operator==(const LexItem &other) const {
return (other.lhs == lhs) && other.rule->operator==(*rule);
}
bool LexItem::is_token_start() const {
class IsTokenStart : public rules::RuleFn<bool> {
bool apply_to(const rules::Seq *rule) {
return apply(rule->left) ||
(rule_can_be_blank(rule->left) && apply(rule->right));
}
bool apply_to(const rules::Metadata *rule) {
return (rule->value_for(rules::START_TOKEN) > 0) || apply(rule->rule);
}
bool apply_to(const rules::Choice *rule) {
for (const rule_ptr &element : rule->elements)
if (apply(element))
return true;
return false;
}
};
return IsTokenStart().apply(rule);
}
LexItem::CompletionStatus LexItem::completion_status() const {
class GetCompletionStatus : public rules::RuleFn<CompletionStatus> {
protected:
CompletionStatus apply_to(const rules::Choice *rule) {
for (const auto &element : rule->elements) {
CompletionStatus status = apply(element);
if (status.is_done)
return status;
}
return { false, 0, false };
}
CompletionStatus apply_to(const rules::Metadata *rule) {
CompletionStatus result = apply(rule->rule);
if (result.is_done) {
if (!result.precedence && rule->value_for(rules::PRECEDENCE))
result.precedence = rule->value_for(rules::PRECEDENCE);
if (rule->value_for(rules::IS_STRING))
result.is_string = true;
}
return result;
}
CompletionStatus apply_to(const rules::Repeat *rule) {
return apply(rule->content);
}
CompletionStatus apply_to(const rules::Blank *rule) {
return { true, 0, false };
}
CompletionStatus apply_to(const rules::Seq *rule) {
CompletionStatus left_status = apply(rule->left);
if (left_status.is_done)
return apply(rule->right);
else
return { false, 0, false };
}
};
return GetCompletionStatus().apply(rule);
}
size_t LexItem::Hash::operator()(const LexItem &item) const {
return hash<Symbol>()(item.lhs) ^ hash<rule_ptr>()(item.rule);
}
size_t LexItemSet::Hash::operator()(const LexItemSet &item_set) const {
size_t result = hash<size_t>()(item_set.entries.size());
for (const auto &item : item_set.entries)
result ^= LexItem::Hash()(item);
return result;
}
LexItemSet::LexItemSet() {}
LexItemSet::LexItemSet(const unordered_set<LexItem, LexItem::Hash> &entries)
: entries(entries) {}
bool LexItemSet::operator==(const LexItemSet &other) const {
return entries == other.entries;
}
LexItemSet::TransitionMap LexItemSet::transitions() const {
TransitionMap result;
for (const LexItem &item : entries)
lex_item_transitions(&result, item);
return result;
}
} // namespace build_tables
} // namespace tree_sitter