#include "rules.h" using std::string; using std::hash; using std::set; using std::pair; namespace tree_sitter { namespace rules { const char MAX_CHAR = '\xff'; CharacterRange::CharacterRange(char value) : min(value), max(value) {} CharacterRange::CharacterRange(char min, char max) : min(min), max(max) {} bool CharacterRange::operator==(const CharacterRange &other) const { return min == other.min && max == other.max; } bool CharacterRange::operator<(const CharacterRange &other) const { if (min < other.min) return true; if (min > other.min) return false; if (max < other.max) return true; return false; } string escape_character(char input) { switch (input) { case '\0': return ""; case MAX_CHAR: return ""; default: return string() + input; } } int max_int(const CharacterRange &range) { return range.max == MAX_CHAR ? 255 : (int)range.max; } int min_int(const CharacterRange &range) { return (int)range.min; } string CharacterRange::to_string() const { if (min == 0 && max == MAX_CHAR) return ""; if (min == max) return escape_character(min); else return string() + escape_character(min) + "-" + escape_character(max); } CharacterSet::CharacterSet() : ranges({}) {} CharacterSet::CharacterSet(const set &ranges) : ranges(ranges) {} CharacterSet::CharacterSet(const set &ranges, bool sign) : ranges(sign ? ranges : CharacterSet(ranges).complement().ranges) {} bool CharacterSet::operator==(const Rule &rule) const { const CharacterSet *other = dynamic_cast(&rule); return other && (ranges == other->ranges); } size_t CharacterSet::hash_code() const { return typeid(this).hash_code() ^ hash()(to_string()); } rule_ptr CharacterSet::copy() const { return std::make_shared(*this); } string CharacterSet::to_string() const { string result("#"; } CharacterSet CharacterSet::complement() const { CharacterSet result({ {0, MAX_CHAR} }, true); result.remove_set(*this); return result; } std::pair CharacterSet::most_compact_representation() const { auto first_range = *ranges.begin(); if (first_range.min == 0 && first_range.max > 0) { return { this->complement(), false }; } else { return { *this, true }; } } void add_range(CharacterSet *self, CharacterRange new_range) { set new_ranges; for (auto range : self->ranges) { auto new_min = min_int(new_range); auto new_max = max_int(new_range); bool is_adjacent = false; if (min_int(range) < new_min) { if (max_int(range) >= new_min - 1) { is_adjacent = true; new_range.min = range.min; } } if (max_int(range) > new_max) { if (min_int(range) <= new_max + 1) { is_adjacent = true; new_range.max = range.max; } } if (!is_adjacent) { new_ranges.insert(range); } } new_ranges.insert(new_range); self->ranges = new_ranges; } CharacterSet remove_range(CharacterSet *self, CharacterRange new_range) { CharacterSet removed_set; set new_ranges; auto new_min = min_int(new_range); auto new_max = max_int(new_range); for (auto range : self->ranges) { if (new_min <= min_int(range)) { if (new_max < min_int(range)) { new_ranges.insert(range); } else if (new_max <= max_int(range)) { new_ranges.insert(CharacterRange(new_max + 1, range.max)); add_range(&removed_set, CharacterRange(range.min, new_max)); } } else if (new_min <= max_int(range)) { if (new_max < max_int(range)) { new_ranges.insert(CharacterRange(range.min, new_min - 1)); new_ranges.insert(CharacterRange(new_max + 1, range.max)); add_range(&removed_set, new_range); } else { new_ranges.insert(CharacterRange(range.min, new_min - 1)); add_range(&removed_set, CharacterRange(new_min, range.max)); } } else { new_ranges.insert(range); } } self->ranges = new_ranges; return removed_set; } bool CharacterSet::is_empty() const { return ranges.empty(); } void CharacterSet::add_set(const CharacterSet &other) { for (auto &other_range : other.ranges) { add_range(this, other_range); } } CharacterSet CharacterSet::remove_set(const CharacterSet &other) { CharacterSet result; for (auto &other_range : other.ranges) { auto removed_set = remove_range(this, other_range); result.add_set(removed_set); } return result; } CharacterSet CharacterSet::intersect(const CharacterSet &set) const { CharacterSet copy = *this; return copy.remove_set(set); } void CharacterSet::accept(Visitor &visitor) const { visitor.visit(this); } } }