#include "generative_grammar/symbol.h" #include "core/error/error_macros.h" #include "core/object/class_db.h" #include "core/templates/hash_map.h" void Symbol::_bind_methods() { BIND_HPROPERTY(Variant::INT, symbol, PROPERTY_HINT_ENUM, Type_hint()); BIND_HPROPERTY(Variant::ARRAY, children_array, PROPERTY_HINT_ARRAY_TYPE, vformat("%s/%s:%s", Variant::OBJECT, PROPERTY_HINT_RESOURCE_TYPE, "Symbol")); } bool Symbol::is_terminal() const { switch (this->symbol) { default: return false; } } void Symbol::set_children_array(TypedArray> array) { for (Ref symbol : this->children) { if (symbol.is_valid()) { symbol->set_parent(nullptr); } } this->children.clear(); for (Variant var : array) { Ref child{ var }; this->children.insert(var); if (child.is_valid()) { child->set_parent(this); } } } TypedArray> Symbol::get_children_array() const { TypedArray> array{}; for (Ref symbol : this->children) { array.push_back(symbol); } return array; } void Rule::_bind_methods() { BIND_HPROPERTY(Variant::OBJECT, pattern, PROPERTY_HINT_RESOURCE_TYPE, "Symbol"); BIND_HPROPERTY(Variant::OBJECT, result, PROPERTY_HINT_RESOURCE_TYPE, "Symbol"); } bool Rule::match_symbols(Ref match, Ref pattern, HashMap, Ref> &matches) { if (match == pattern) { return true; // reference match or null match } ERR_FAIL_COND_V_EDMSG(match.is_valid() == false, false, "Attempt to match null symbol, is not possible"); if (pattern.is_null()) { return false; // null matches nothing } if (match->get_symbol() != pattern->get_symbol()) { return false; // symbol type mismatch } if (match->get_children().size() < pattern->get_children().size()) { return false; // too little children to be able to match } // check for matching outgoing edges for (Ref pattern_symbol : pattern->get_children()) { bool match_found{ false }; for (Ref match_symbol : match->get_children()) { if (match_symbols(match_symbol, pattern_symbol, matches)) { match_found = true; break; } } if (!match_found) { return false; } } matches.insert(pattern, match); return true; } bool Rule::try_apply(Ref match) { // identify corresponding symbols HashMap, Ref> symbols{}; if (!match_symbols(match, this->pattern, symbols)) { return false; } // clear matching edges for (KeyValue, Ref> kvp : symbols) { } return true; }