def get_reference_propositions(self, obj, attr, name_part): """ retrieve a list of reference propositions. Args: obj: parent attr: attribute name_part: The name is used to build the list (e.g. using a substring-like logic). Returns: the list of objects representing the proposed references """ from textx.scoping.tools import resolve_model_path from textx import textx_isinstance obj_list = resolve_model_path(obj, self.path_to_container_object) if type(obj_list) is Postponed: self.postponed_counter += 1 return obj_list # the referenced element must be a list # (else it is a design error in the path passed to # the RelativeName object). if not isinstance(obj_list, list): from textx.exceptions import TextXError raise TextXError( "expected path to list in the model ({})".format( self.path_to_container_object)) obj_list = filter( lambda x: textx_isinstance(x, attr.cls) and x.name.find(name_part) >= 0, obj_list) return list(obj_list)
def custom_scope_redirection(obj): from textx import textx_isinstance if textx_isinstance(obj, mm["PackageRef"]): if obj.ref is None: from textx.scoping import Postponed return Postponed() return [obj.ref] else: return []
def _find_obj_fqn(p, fqn_name, cls): """ Helper function: find a named object based on a qualified name ("."-separated names) starting from object p. Args: p: the container where to start the search fqn_name: the "."-separated name Returns: the object or None """ def find_obj(parent, name): if parent is not current_obj and \ self.scope_redirection_logic is not None: from textx.scoping import Postponed res = self.scope_redirection_logic(parent) assert res is not None, \ "scope_redirection_logic must not return None" if type(res) is Postponed: return res for m in res: return_value = find_obj(m, name) if return_value is not None: return return_value for attr in [a for a in parent.__dict__ if not a.startswith('__') and not a.startswith('_tx_') and not callable(getattr(parent, a))]: obj = getattr(parent, attr) if isinstance(obj, (list, tuple)): for innerobj in obj: if hasattr(innerobj, "name") \ and innerobj.name == name: return innerobj else: if hasattr(obj, "name") and obj.name == name: return obj return None for n in fqn_name.split('.'): obj = find_obj(p, n) if obj: if type(obj) is Postponed: return obj p = obj else: return None from textx import textx_isinstance if textx_isinstance(obj, cls): return p else: return None
def test_textx_isinstace(): grammar = \ ''' Model: a=A; A: B; B: C; C: x=ID; ''' my_meta_model = metamodel_from_str(grammar) A = my_meta_model['A'] B = my_meta_model['B'] C = my_meta_model['C'] my_model = my_meta_model.model_from_str("c") c = get_children_of_type("C", my_model) assert len(c) == 1 c = c[0] assert textx_isinstance(c, C) assert textx_isinstance(c, B) assert textx_isinstance(c, A)
def get_reference_propositions(self, obj, attr, name_part): """ retrieve a list of reference propositions. Args: obj: parent attr: attribute name_part: The name is used to build the list (e.g. using a substring-like logic). Returns: the list of objects representing the proposed references """ from textx.scoping.tools import resolve_model_path from textx import textx_isinstance # find all all "connected" objects # (e.g. find all classes: the most derived # class, its base, the base of its base, etc.) from textx.scoping.tools import get_list_of_concatenated_objects def_obj = resolve_model_path(obj, self.path_to_definition_object) def_objs = get_list_of_concatenated_objects( def_obj, self.path_to_extension) # for all containing classes, collect all # objects to be looked up (e.g. methods) obj_list = [] for def_obj in def_objs: if type(def_obj) is Postponed: self.postponed_counter += 1 return def_obj tmp_list = resolve_model_path(def_obj, self.path_to_target) assert tmp_list is not None # expected to point to alist if not isinstance(tmp_list, list): from textx.exceptions import TextXError raise TextXError( "expected path to list in the model ({})".format( self.path_to_target)) tmp_list = list(filter( lambda x: textx_isinstance(x, attr.cls) and x.name.find(name_part) >= 0, tmp_list)) obj_list = obj_list + tmp_list return list(obj_list)
def ref_scope(refItem, attr, attr_ref): from textx.scoping.tools import get_named_obj_in_list from textx.scoping import Postponed from textx import textx_isinstance reference = refItem.parent if reference is None: return Postponed() index = reference.refs.index(refItem) assert (index >= 0) base = reference.instance if index == 0 \ else reference.refs[index - 1].valref if base is None or base.type is None: return Postponed() x = get_named_obj_in_list(base.type.vals, attr_ref.obj_name) if index == len(reference.refs)-1: if not textx_isinstance(x, attr.cls): print(x) return None return x
def _assert_attr_used_in_formula_must_have_a_max_and_default_value(f, d): mm = get_metamodel(d) all_refs = list( map(lambda x: x.ref._tx_path, get_children_of_type("AttrRef", f))) # _tx_apth is a list of references to the final variable (e.g. header.n # yields [header,n]. if len(all_refs) > 0: all_refs = reduce(lambda a, b: a + b, all_refs) # merge all ref lists all_refs = filter( lambda x: textx_isinstance(x, mm["ScalarAttribute"]) and x.has_rawtype( ), all_refs, ) for r in all_refs: textx_assert( has_property(r, "maxValue"), d, f"attribute {r.name} used in dim formula must have a 'maxValue'", ) textx_assert( has_property(r, "defaultValue"), d, f"attribute {r.name} used in dim formula must have a 'defaultValue'", )
def __call__(self, obj, attr, obj_ref): """ the default scope provider Args: obj: unused (used for multi_metamodel_support) attr: unused obj_ref: the cross reference to be resolved Returns: the resolved reference or None """ from textx.const import RULE_COMMON, RULE_ABSTRACT from textx.model import ObjCrossRef from textx.scoping.tools import get_parser if obj_ref is None: return None # an error! (see model.py: resolve_refs (TODO check) assert type(obj_ref) is ObjCrossRef, type(obj_ref) if get_parser(obj).debug: get_parser(obj).dprint("Resolving obj crossref: {}:{}" .format(obj_ref.cls, obj_ref.obj_name)) def _inner_resolve_link_rule_ref(cls, obj_name): """ Depth-first resolving of link rule reference. """ if cls._tx_type is RULE_ABSTRACT: for inherited in cls._tx_inh_by: result = _inner_resolve_link_rule_ref(inherited, obj_name) if result: return result elif cls._tx_type == RULE_COMMON: # TODO make this code exchangable # allow to know the current attribute (model location for # namespace) and to navigate through the whole model... # OR (with another scope provider) to make custom lookups in # the model # # Scopeprovider # - needs: .current reference (in the model) # .the model (?) # - provides: the resolved object or None if id(cls) in get_parser(obj)._instances: objs = get_parser(obj)._instances[id(cls)] return objs.get(obj_name) if self.multi_metamodel_support: from textx import get_model, get_children from textx import textx_isinstance result_lst = get_children( lambda x: hasattr(x, "name") and x.name == obj_ref.obj_name and textx_isinstance(x, obj_ref.cls), get_model(obj)) if len(result_lst) == 1: result = result_lst[0] elif len(result_lst) > 1: line, col = get_parser(obj).pos_to_linecol(obj_ref.position) raise TextXSemanticError( "name {} is not unique.".format(obj_ref.obj_name), line=line, col=col, filename=get_model(obj)._tx_filename) else: result = None else: result = _inner_resolve_link_rule_ref(obj_ref.cls, obj_ref.obj_name) if result: return result return None # error handled outside
def generate_cpp_struct(f, i): """ :param f: output file obj :param i: item to be generated (the struct) """ mm = textx.get_metamodel(i) f.write("//---------------------------\n") f.write("#ifdef SWIG\n") f.write("%shared_ptr({});\n".format(fqn(i))) f.write( "%template(MDSD_StructFunctions_{}) mdsd::StructFunctions<{}>;\n".format( i.name, fqn(i) ) ) f.write("%template(MDSD_Struct_{}) mdsd::Struct<{}>;\n".format(i.name, fqn(i))) f.write( "%template(MDSD_StructWrapper_{}) mdsd::StructWrapper<{}>;\n".format( i.name, fqn(i) ) ) for a in i.attributes: if textx.textx_isinstance(a, mm["ArrayAttribute"]): if a.has_fixed_size(): f.write(define_swig_array(a.type, a.compute_formula(), mm)) else: f.write(define_swig_vector(a.type, mm)) f.write("#endif\n") f.write("//---------------------------\n") f.write(get_open_namespace_for_obj(i)) f.write("struct {} {{\n".format(i.name)) for c in i.constant_entries: f.write( " static constexpr {} {} = {};\n".format( fqn(c.type), c.name, c.value.render_formula() ) ) for a in i.attributes: if a.is_embedded(): value_type = get_cpp_return_type(a.type) if textx.textx_isinstance(a, mm["ScalarAttribute"]): f.write(" inline {} {}() const;\n".format(value_type, a.name)) else: f.write( " inline {} {}(size_t idx) const;\n".format(value_type, a.name) ) if textx.textx_isinstance(a, mm["ScalarAttribute"]): f.write(" inline void {}({} val);\n".format(a.name, value_type)) else: f.write( " inline void {}(size_t idx, {} val);\n".format(a.name, value_type) ) continue if textx.textx_isinstance(a, mm["ScalarAttribute"]): f.write(" {} {} = {{}};\n".format(fqn(a.type), a.name)) elif textx.textx_isinstance(a, mm["ArrayAttribute"]): if a.has_fixed_size(): f.write( " std::array<{},{}> {} = {{}};\n".format( fqn(a.type), a.compute_formula(), a.name ) ) else: f.write(" std::vector<{}> {} = {{}};\n".format(fqn(a.type), a.name)) elif textx.textx_isinstance(a, mm["VariantAttribute"]): f.write( " std::variant<{}> {} = {{}};\n".format(get_variant_types(a), a.name) ) else: raise Exception("unexpected type") f.write( " mdsd::StructWrapper<{0}> _GET_WRAPPER() {{ return mdsd::StructWrapper<{0}>{{this}}; }}\n".format( i.name ) ) f.write("\n#ifndef SWIG\n") f.write(" struct META {\n") # ---------------------------------------- f.write( " template<class STRUCT,class VISITOR, class ...T> // enable accept for this struct: \n" ) f.write(" static void __accept_varargs(VISITOR &&v, T&... s) {\n") for a in i.attributes: f.write(" v.template visit<{}::META::{}>(s...);\n".format(i.name, a.name)) f.write(" }\n") # ---------------------------------------- f.write(" static constexpr const char* __name() ") f.write('{{ return "{}"; }}\n'.format(i.name)) f.write(f" static constexpr bool __is_dynamic = {tf(is_dynamic(i))};\n") f.write(" // META substructs:\n") for a in i.attributes: if a.is_variant(): for m in a.mappings: pdefs = get_all_possible_properties(m) pdefs = sorted(pdefs.keys()) f.write(" struct {} {{\n".format(meta_name_of_variant_mapping(m))) f.write(" using STRUCT={};\n".format(i.name)) f.write(" static constexpr const char* __name() ") f.write('{{ return "{}"; }}\n'.format(a.name)) f.write(" static constexpr bool __is_variant_entry = true;\n") f.write(" static constexpr bool __is_scalar = true;\n") f.write(" static constexpr bool __is_variant = false;\n") f.write(" static constexpr bool __is_array = false;\n") f.write(" static constexpr bool __is_enumtype = false;\n") f.write(" static constexpr bool __is_rawtype = false;\n") f.write(" static constexpr bool __is_struct = true;\n") f.write(" static constexpr bool __is_container = false;\n") insert_normal_meta_info(f, pdefs, m) f.write(" };\n") for a in i.attributes: f.write(" struct {} {{\n".format(a.name)) f.write(" using STRUCT={};\n".format(i.name)) f.write(" static constexpr const char* __name() ") f.write('{{ return "{}"; }}\n'.format(a.name)) f.write(" static constexpr bool __is_variant_entry = false;\n") if not textx.textx_isinstance(a, mm["VariantAttribute"]): f.write(f" using __type = {fqn(a.type)};") f.write(f" static constexpr bool __is_dynamic = {tf(is_dynamic(a))};\n") if hasattr(a, "type") and a.type.name == "char": f.write(" static constexpr bool __has_char_content = true;\n") else: f.write(" static constexpr bool __has_char_content = false;\n") if a.if_attr is None: f.write(" static constexpr bool __has_if_restriction = false;\n") f.write( " static constexpr bool __if_restriction(const STRUCT &) { return true; }\n\n" ) else: f.write(" static constexpr bool __has_if_restriction = true;\n") f.write( " static constexpr bool __if_restriction(const STRUCT &s) {{ return {}; }}\n\n".format( a.if_attr.predicate.render_formula(prefix="s.") ) ) if not (a.is_embedded()): if ( textx.textx_isinstance(a, mm["ArrayAttribute"]) and a.type.name == "char" ): f.write( " static constexpr auto __get_ref(STRUCT &s) {{ return mdsd::String(s.{}); }}\n".format( a.name ) ) f.write( " static constexpr const auto __get_ref(const STRUCT &s)" " {{ return mdsd::String(s.{}); }}\n".format(a.name) ) else: f.write( " static constexpr auto& __get_ref(STRUCT &s) {{ return s.{}; }}\n".format( a.name ) ) f.write( " static constexpr const auto& __get_ref(const STRUCT &s) {{ return s.{}; }}\n".format( a.name ) ) else: f.write( " static constexpr auto& __get_ref_of_container(STRUCT &s) {{ return s.{}; }}\n".format( get_container(a).name ) ) f.write( " static constexpr const auto& __get_ref_of_container(const STRUCT &s)" " {{ return s.{}; }}\n".format(get_container(a).name) ) if textx.textx_isinstance(a, mm["ArrayAttribute"]): f.write( " static constexpr auto __get_ref(STRUCT &s) {{ return mdsd::makeArrayRef<{}>(\n".format( fqn(a.type) ) ) f.write( " [&s](size_t idx){{ return s.{}(idx); }},\n".format( a.name ) ) f.write( " [&s](size_t idx, {} x){{ return s.{}(idx, x); }},\n".format( fqn(a.type), a.name ) ) f.write(" {}\n".format(a.compute_formula())) f.write(" ); }\n") f.write( " static constexpr auto __get_ref(const STRUCT &s)" " {{ return mdsd::makeCArrayRef<{}>(\n".format(fqn(a.type)) ) f.write( " [&s](size_t idx){{ return s.{}(idx); }},\n".format( a.name ) ) f.write(" {}\n".format(a.compute_formula())) f.write(" ); }\n") else: f.write( " static constexpr auto __get_ref(STRUCT &s) {{ return mdsd::makeRef<{}>(\n".format( fqn(a.type) ) ) f.write(" [&s](){{ return s.{}(); }},\n".format(a.name)) f.write( " [&s]({} x){{ return s.{}(x); }}\n".format( fqn(a.type), a.name ) ) f.write(" ); }\n") f.write( " static constexpr auto __get_ref(const STRUCT &s) {{ return mdsd::makeCRef<{}>(\n".format( fqn(a.type) ) ) f.write(" [&s](){{ return s.{}(); }}\n".format(a.name)) f.write(" ); }\n") pdefs = get_all_possible_properties(a) pdefs = sorted(pdefs.keys()) if "fixpointLsbValue" in pdefs: if has_fixpoint(a): f.write(" static constexpr bool __is_fixpoint = true;\n") f.write( f" static constexpr double __fixpointLsbValue = {get_fixpoint_LSB_value(a)};\n" ) f.write( f" static constexpr double __fixpointOffsetValue = {get_fixpoint_offset_value(a)};\n" ) f.write( f" template<class FLOAT=double> static constexpr {fqn(a.type)} __float2integral(FLOAT f) " f"{{ return static_cast<{fqn(a.type)}>(std::llround((f-__fixpointOffsetValue)" f"/__fixpointLsbValue)); }}\n" ) f.write( f" template<class FLOAT=double> static constexpr FLOAT __integral2float({fqn(a.type)} i) " f"{{ return static_cast<FLOAT>(i)*__fixpointLsbValue+__fixpointOffsetValue; }}\n" ) else: f.write(" static constexpr bool __is_fixpoint = false;\n") else: f.write(" static constexpr bool __is_fixpoint = false;\n") insert_normal_meta_info(f, pdefs, a) if textx.textx_isinstance(a, mm["VariantAttribute"]): f.write( " template<class S, class F> // S may also be const\n" ) f.write( " static void __call_function_on_concrete_variant_type(S &s, F f) {\n" ) f.write( " switch(s.{}) {{\n".format(a.variant_selector.render_formula()) ) for m in a.mappings: f.write(" case {}: ".format(m.id)) assert not textx.textx_isinstance(m.type, mm["RawType"]) f.write( "f.template operator()<STRUCT::META::{}>(std::get<{}>(s.{})); break;\n".format( meta_name_of_variant_mapping(m), fqn(m.type), a.name ) ) f.write(' default: throw std::runtime_error("(unexpected id)");\n') f.write(" }\n") f.write(" }\n") f.write(" template<class S> // S may also be const\n") f.write( " static void __init_variant_type_if_type_is_not_matching(S &s) {\n" ) f.write( " switch(s.{}) {{\n".format(a.variant_selector.render_formula()) ) for m in a.mappings: f.write(" case {}: ".format(m.id)) f.write( "if (not std::holds_alternative<{}>(s.{})) {{ s.{}={}{{}}; }} break;\n".format( fqn(m.type), a.name, a.name, fqn(m.type), ) ) f.write(' default: throw std::runtime_error("unexpected id");\n') f.write(" }\n") f.write(" }\n") f.write(" static constexpr bool __is_scalar = true;\n") f.write(" static constexpr bool __is_variant = true;\n") f.write(" static constexpr bool __is_array = false;\n") f.write(" static constexpr bool __is_enumtype = false;\n") f.write(" static constexpr bool __is_rawtype = false;\n") f.write(" static constexpr bool __is_struct = true;\n") f.write( " static constexpr bool __is_container = {};\n".format( tf(a.is_container()) ) ) f.write( " static constexpr bool __is_embedded = {};\n".format( tf(a.is_embedded()) ) ) elif textx.textx_isinstance(a, mm["ScalarAttribute"]): f.write(" static constexpr bool __is_scalar = true;\n") f.write(" static constexpr bool __is_variant = false;\n") f.write(" static constexpr bool __is_array = false;\n") if textx.textx_isinstance(a.type, mm["Enum"]): f.write(" static constexpr bool __is_enumtype = true;\n") else: f.write(" static constexpr bool __is_enumtype = false;\n") if textx.textx_isinstance(a.type, mm["RawType"]): f.write(" static constexpr bool __is_rawtype = true;\n") else: f.write(" static constexpr bool __is_rawtype = false;\n") if textx.textx_isinstance(a.type, mm["Struct"]): f.write(" static constexpr bool __is_struct = true;\n") else: f.write(" static constexpr bool __is_struct = false;\n") f.write( " static constexpr bool __is_container = {};\n".format( tf(a.is_container()) ) ) f.write( " static constexpr bool __is_embedded = {};\n".format( tf(a.is_embedded()) ) ) if a.is_embedded(): start_end_bit = get_start_end_bit(a) f.write( " static constexpr size_t __embedded_bits = {};\n".format( get_bits(a.type) ) ) f.write( " static constexpr size_t __embedded_start_bit = {};\n".format( start_end_bit[0] ) ) f.write( " static constexpr size_t __embedded_end_bit = {};\n".format( start_end_bit[1] ) ) elif textx.textx_isinstance(a, mm["ArrayAttribute"]): f.write(" static constexpr bool __is_scalar = false;\n") f.write(" static constexpr bool __is_variant = false;\n") f.write(" static constexpr bool __is_array = true;\n") if a.has_fixed_size(): f.write(" static constexpr bool __is_dynamic_array = false;\n") else: f.write(" static constexpr bool __is_dynamic_array = true;\n") f.write( " static constexpr size_t __get_dim([[maybe_unused]] const {} &{}) {{ return {};}}\n".format( i.name, "s" if not a.has_fixed_size() else "", a.render_formula(prefix="s."), ) ) txt = f" static constexpr size_t __get_dim([[maybe_unused]] const {i.name}" txt += f"&{'s' if not a.has_fixed_size() else ''}, size_t _idx) {{\n" txt += " switch(_idx) {\n" for idx in range(len(a.dims)): txt += f" case {idx}: return {a.dims[idx].dim.render_formula(prefix='s.')};\n" txt += ' default: throw std::runtime_error("unexpected dimension");\n' txt += " }\n" txt += " }\n" f.write(txt) if textx.textx_isinstance(a.type, mm["Enum"]): f.write(" static constexpr bool __is_enumtype = true;\n") else: f.write(" static constexpr bool __is_enumtype = false;\n") if textx.textx_isinstance(a.type, mm["RawType"]): f.write(" static constexpr bool __is_rawtype = true;\n") else: f.write(" static constexpr bool __is_rawtype = false;\n") if textx.textx_isinstance(a.type, mm["Struct"]): f.write(" static constexpr bool __is_struct = true;\n") else: f.write(" static constexpr bool __is_struct = false;\n") f.write( " static constexpr bool __is_container = {};\n".format( tf(a.is_container()) ) ) f.write( " static constexpr bool __is_embedded = {};\n".format( tf(a.is_embedded()) ) ) if a.is_embedded(): start_end_bit = get_start_end_bit(a) f.write( " static constexpr size_t __embedded_bits = {};\n".format( get_bits(a.type) ) ) f.write( " static constexpr size_t __embedded_start_bit = {};\n".format( start_end_bit[0] ) ) f.write( " static constexpr size_t __embedded_end_bit = {};\n".format( start_end_bit[1] ) ) else: raise Exception("unexpected type constellation") f.write(" }}; // meta struct {}\n".format(a.name)) f.write(" }; //struct META\n\n") f.write("#endif // #ifndef SWIG\n\n") f.write(f" {i.name}() {{\n") f.write(" mdsd::init_default_values(*this);\n") f.write(" }\n") if _extra_init_required(i): f.write(f" {i.name}({_get_ctor_params(i)}) {{\n") f.write(f" {_get_ctor_body(i)};\n") f.write(" }\n") f.write( " static std::shared_ptr<{}> item_create() {{ return std::make_shared<{}>(); }}\n".format( i.name, i.name ) ) f.write("}}; //struct {}\n".format(i.name)) for a in i.attributes: if a.is_embedded(): value_type = get_cpp_return_type(a.type) signed_info = get_signed_or_unsigned(a.type) container_name = get_container(a).name if textx.textx_isinstance(a, mm["ScalarAttribute"]): f.write( " inline {} {}::{}() const {{\n".format(value_type, i.name, a.name) ) f.write( f" return mdsd::read_{signed_info}_from_container<{value_type}>({container_name}," f" META::{a.name}::__embedded_start_bit, META::{a.name}::__embedded_end_bit);\n" ) f.write(" }\n") else: f.write( " inline {} {}::{}(size_t idx) const {{\n".format( value_type, i.name, a.name ) ) f.write( f" return mdsd::read_{signed_info}_from_container<{value_type}>({container_name}," f" META::{a.name}::__embedded_start_bit-idx*META::{a.name}::__embedded_bits," f" META::{a.name}::__embedded_start_bit+1-(idx+1)*META::{a.name}::__embedded_bits);\n" ) f.write(" }\n") if textx.textx_isinstance(a, mm["ScalarAttribute"]): f.write( " inline void {}::{}({} val) {{\n".format( i.name, a.name, value_type ) ) f.write( f" {container_name} = mdsd::write_to_container({container_name}," f" META::{a.name}::__embedded_start_bit, META::{a.name}::__embedded_end_bit, val);\n" ) f.write(" }\n") else: f.write( " inline void {}::{}(size_t idx, {} val) {{\n".format( i.name, a.name, value_type ) ) f.write( f" {container_name} = mdsd::write_to_container({container_name}," f" META::{a.name}::__embedded_start_bit-idx*META::{a.name}::__embedded_bits," f" META::{a.name}::__embedded_start_bit+1-(idx+1)*META::{a.name}::__embedded_bits, val);\n" ) f.write(" }\n") f.write("#ifndef SWIG\n") # ---------------------------------------- f.write( "template<class VISITOR, class STRUCT> // enable accept for this struct: \n" ) f.write( "std::enable_if_t<std::is_same_v<std::remove_const_t<STRUCT>,{}>> accept(VISITOR &&v, STRUCT &s) {{\n".format( i.name ) ) f.write(" STRUCT::META::template __accept_varargs<STRUCT>(v, s);\n") f.write("}\n") # ---------------------------------------- f.write("#endif // #ifndef SWIG\n") f.write("} // close namespace\n") f.write("// swig helper:\n") for a in i.attributes: if textx.textx_isinstance(a, mm["VariantAttribute"]): f.write(define_swig_variant_access(i, a))
def _is(x, rule): return textx_isinstance(x, calc_mm[rule])
def __call__(self, obj, attr, obj_ref): if textx_isinstance(obj.parent, self.meta["Start"]): return self.pStart(obj, attr, obj_ref) else: return self.pEvent1(obj, attr, obj_ref)
def is_applicable_for(parent, definition): mm = get_metamodel(parent) appl = definition.applicable_for if len(appl) == 0: # not apply ATTRTYPE properties for structs if (textx_isinstance(parent, mm["Struct"]) or textx_isinstance(parent, mm["EnumEntry"]) or textx_isinstance(parent, mm["VariantMapping"]) or (hasattr(parent, "type") and textx_isinstance(parent.type, mm["Struct"])) ) and definition.internaltype == "ATTRTYPE": raise Exception( "ATTRTYPE only applicable for rawtype/enum scalar/array attributes" ) return True attr = parent assert (textx_isinstance(attr, mm["Attribute"]) or textx_isinstance(attr, mm["VariantMapping"]) or textx_isinstance(attr, mm["EnumEntry"]) or textx_isinstance(attr, mm["Struct"])) if "array" in appl or "scalar" in appl: if "struct_definition" not in appl and textx_isinstance( attr, mm["Struct"]): return False elif "array" not in appl and textx_isinstance(attr, mm["ArrayAttribute"]): return False elif "scalar" not in appl and ( textx_isinstance(attr, mm["ScalarAttribute"]) or textx_isinstance(attr, mm["VariantMapping"])): return False appl = list(filter(lambda x: x not in ["scalar", "array"], appl)) if len(appl) == 0: return True if textx_isinstance(attr, mm["Struct"]) and "struct_definition" in appl: return True if textx_isinstance(attr, mm["VariantAttribute"]) and "variant" in appl: return True if textx_isinstance(attr, mm["EnumEntry"]) and "enum_value" in appl: return True if textx_isinstance(attr, mm["VariantMapping"]): if "struct" in appl: return True else: return False if textx_isinstance(attr, mm["ArrayAttribute"]) or textx_isinstance( attr, mm["ScalarAttribute"]): if textx_isinstance(attr.type, mm["Enum"]) and "enum" in appl: return True if textx_isinstance(attr.type, mm["Struct"]) and "struct" in appl: return True if textx_isinstance(attr.type, mm["RawType"]): rt_appl = list( filter( lambda x: textx_isinstance(x, mm["ApplicableForRawType"]), appl)) if len(rt_appl) == 0: return False allowed = list( reduce(lambda x, y: x.extend(y), map(lambda x: x.concrete_types, rt_appl))) if len(allowed) == 0: return True # all rawtypes allowed elif attr.type in allowed: return True return False
def resolve_one_step(self): """ Resolves model references. """ metamodel = self.parser.metamodel current_crossrefs = self.parser._crossrefs # print("DEBUG: Current crossrefs #: {}". # format(len(current_crossrefs))) new_crossrefs = [] self.delayed_crossrefs = [] resolved_crossref_count = 0 # ------------------------- # start of resolve-loop # ------------------------- default_scope = DefaultScopeProvider() for obj, attr, crossref in current_crossrefs: if (get_model(obj) == self.model): attr_value = getattr(obj, attr.name) attr_refs = [ obj.__class__.__name__ + "." + attr.name, "*." + attr.name, obj.__class__.__name__ + ".*", "*.*" ] if crossref.scope_provider is not None: resolved = crossref.scope_provider(obj, attr, crossref) else: for attr_ref in attr_refs: if attr_ref in metamodel.scope_providers: if self.parser.debug: self.parser.dprint( " FOUND {}".format(attr_ref)) resolved = metamodel.scope_providers[attr_ref]( obj, attr, crossref) break else: resolved = default_scope(obj, attr, crossref) # Collect cross-references for textx-tools if resolved is not None and not type(resolved) is Postponed: if metamodel.textx_tools_support: self.pos_crossref_list.append( RefRulePosition( name=crossref.obj_name, ref_pos_start=crossref.position, ref_pos_end=crossref.position + len(resolved.name), def_pos_start=resolved._tx_position, def_pos_end=resolved._tx_position_end)) if resolved is None: # As a fall-back search builtins if given if metamodel.builtins: if crossref.obj_name in metamodel.builtins: from textx import textx_isinstance if textx_isinstance( metamodel.builtins[crossref.obj_name], crossref.cls): resolved = metamodel.builtins[ crossref.obj_name] if resolved is None: line, col = self.parser.pos_to_linecol(crossref.position) raise TextXSemanticError( message='Unknown object "{}" of class "{}"'.format( crossref.obj_name, crossref.cls.__name__), line=line, col=col, err_type=UNKNOWN_OBJ_ERROR, expected_obj_cls=crossref.cls, filename=self.model._tx_filename) if type(resolved) is Postponed: self.delayed_crossrefs.append((obj, attr, crossref)) new_crossrefs.append((obj, attr, crossref)) else: resolved_crossref_count += 1 if attr.mult in [MULT_ONEORMORE, MULT_ZEROORMORE]: attr_value.append(resolved) else: setattr(obj, attr.name, resolved) else: # crossref not in model new_crossrefs.append((obj, attr, crossref)) # ------------------------- # end of resolve-loop # ------------------------- # store cross-refs from other models in the parser list (for later # processing) self.parser._crossrefs = new_crossrefs # print("DEBUG: Next crossrefs #: {}".format(len(new_crossrefs))) return (resolved_crossref_count, self.delayed_crossrefs)
def test_metamodel_provider_advanced_test3_global(): """ Advanced test for ExtRelativeName and PlainNameGlobalRepo. Here we have a global model repository shared between different meta models. The meta models interact (refer to each other, different directions). """ ################################# # META MODEL DEF ################################# this_folder = dirname(abspath(__file__)) def get_meta_model(global_repo, grammar_file_name): mm = metamodel_from_file(join(this_folder, grammar_file_name), debug=False, classes=[Cls, Obj]) mm.register_scope_providers({ "*.*": global_repo, }) return mm global_repo_provider = scoping_providers.PlainNameGlobalRepo() global_repo_provider.register_models( join(this_folder, "metamodel_provider3", "circular", "*.a")) global_repo_provider.register_models( join(this_folder, "metamodel_provider3", "circular", "*.b")) global_repo_provider.register_models( join(this_folder, "metamodel_provider3", "circular", "*.c")) a_mm = get_meta_model( global_repo_provider, join(this_folder, "metamodel_provider3", "A.tx")) b_mm = get_meta_model( global_repo_provider, join(this_folder, "metamodel_provider3", "B.tx")) c_mm = get_meta_model( global_repo_provider, join(this_folder, "metamodel_provider3", "C.tx")) clear_language_registrations() register_language( 'a-dsl', pattern='*.a', description='Test Lang A', metamodel=a_mm) register_language( 'b-dsl', pattern='*.b', description='Test Lang B', metamodel=b_mm) register_language( 'c-dsl', pattern='*.c', description='Test Lang C', metamodel=c_mm) ################################# # MODEL PARSING ################################# model_repo = global_repo_provider.load_models_in_model_repo().all_models ################################# # TEST MODEL ################################# def get_all(model_repo, what): lst = [] for m in model_repo.filename_to_model.values(): lst = lst + get_children_of_type(what, m) return lst lst = get_all(model_repo, "Obj") # print(lst) assert len(lst) == 3 # check some references to be resolved (!=None) for a in lst: assert a.ref # check meta classes assert a_mm["Cls"]._tx_fqn == b_mm["Cls"]._tx_fqn # more checks from textx import textx_isinstance for a in lst: assert textx_isinstance(a, a_mm["Obj"]) assert textx_isinstance(a, b_mm["Obj"]) assert textx_isinstance(a, c_mm["Obj"]) ################################# # END ################################# clear_language_registrations()
def get_property(attr, prop_name): def get_value(res, internaltype): if internaltype == "STRING": textx_assert(res.textValue is not None, attr, prop_name + " must be a STRING") return res.textValue.x elif internaltype == "INT": textx_assert(res.numberValue is not None, attr, prop_name + " must be an NUMBER/INT") elif internaltype == "UINT": textx_assert(res.numberValue is not None, attr, prop_name + " must be an NUMBER/UINT") elif internaltype == "BOOL": textx_assert( res.numberValue is not None, attr, prop_name + " must be an NUMBER/BOOL as int", ) elif internaltype == "FLOAT": textx_assert(res.numberValue is not None, attr, prop_name + " must be an NUMBER") assert res.numberValue is not None elif internaltype == "ENUM": textx_assert(res.numberValue is not None, attr, prop_name + " must be an ENUM") assert res.numberValue is not None else: return None return compute_formula_for_internaltype(res.numberValue.x, internaltype, prop_name) res = list( filter(lambda x: x.definition.name == prop_name, attr.properties)) if len(res) == 0: return None else: mm = get_metamodel(attr) textx_assert(len(res) == 1, attr, prop_name + " must be unique") res = res[0] internaltype = res.definition.internaltype if internaltype == "ATTRTYPE": textx_assert( not textx_isinstance(attr, mm["VariantAttribute"]), attr, prop_name + " not supported for variants", ) correct_instance = textx_isinstance( attr.type, mm["RawType"]) or textx_isinstance( attr.type, mm["Enum"]) textx_assert( correct_instance, attr, prop_name + " only applicable for rawtypes/enums", ) internaltype = attr.type.internaltype value = get_value(res, internaltype) textx_assert( value is not None, attr, prop_name + " could not be interpreted (unexpected)", ) return value
def generate_py_for_struct(struct_obj, output_file): mm = get_metamodel(struct_obj) if obj_is_newer_than_file(struct_obj, output_file): with open(output_file, "w") as f: f.write("""# generated code from dataclasses import dataclass, field import numpy as np import mdsd.item_support as support from mdsd.item.init_values import init_default_values from mdsd.common import get_embedded_from_uint, ArrayLike from mdsd.common import set_embedded_in_uint from mdsd.common import ArrayLike, str2array, array2str from mdsd.common import int2float_fixpoint_value, float2int_fixpoint_value, FixpointArrayLike from typing import Sequence, Union from functools import reduce """) for r in get_referenced_elements_of_struct(struct_obj): f.write("import {}\n".format(module_name(r))) f.write("\n") i = struct_obj for c in i.constant_entries: f.write( f"{c.name} = {fqn(c.type)}({c.value.render_formula(**fp(i))})\n" ) f.write("\n@dataclass(eq=False)\n") f.write("class {}:\n".format(i.name)) for a in i.attributes: if a.is_embedded(): rawtype = a.type if textx_isinstance(a.type, mm["Enum"]): rawtype = a.type.type if textx_isinstance(a, mm["ScalarAttribute"]): # SCALAR EMBEDDED # -------------------------------------------------------------- start_end_bit = get_start_end_bit(a) c = get_container(a) f.write(f" @property\n") f.write(f" def {a.name}(self):\n") f.write( f" ret = get_embedded_from_uint({fqn(rawtype)}, self.{c.name},[{start_end_bit[0]},{start_end_bit[1]}])\n" ) if textx_isinstance(a.type, mm["Enum"]): f.write(f" ret = {fqn(a.type)}(ret)\n") f.write(f" return ret\n") f.write(f"\n") f.write(f" @{a.name}.setter\n") f.write(f" def {a.name}(self, v):\n") if textx_isinstance(a.type, mm["Enum"]): f.write(f" v = v.value\n") f.write( f" assert isinstance(v, {fqn(rawtype)})\n") f.write( f" self.{c.name} = set_embedded_in_uint(v, self.{c.name},[{start_end_bit[0]},{start_end_bit[1]}])\n" ) f.write(f"\n") # -------------------------------------------------------------- elif textx_isinstance(a, mm["ArrayAttribute"]): # ARRAY EMBEDDED # -------------------------------------------------------------- start_end_bit = get_start_end_bit(a) c = get_container(a) f.write(f" @property\n") f.write(f" def {a.name}(self):\n") f.write(f" def getter(idx):\n") f.write(f" assert idx >= 0\n") f.write( f" assert idx < reduce(lambda a, b: a * b, {i.name}._meta['{a.name}']['_get_dim_nd'](self))\n" ) f.write( f" ret = get_embedded_from_uint({fqn(rawtype)}, self.{c.name},[{start_end_bit[0]}-idx*{rawtype.bits},{start_end_bit[0]}+1-(idx+1)*{rawtype.bits}])\n" ) if textx_isinstance(a.type, mm["Enum"]): f.write(f" ret = {fqn(a.type)}(ret)\n") f.write(f" return ret\n") f.write(f" def setter(idx, v):\n") f.write(f" assert idx >= 0\n") f.write( f" assert idx < reduce(lambda a, b: a * b, {i.name}._meta['{a.name}']['_get_dim_nd'](self))\n" ) f.write( f" assert isinstance(v, {fqn(a.type)})\n" ) if textx_isinstance(a.type, mm["Enum"]): f.write(f" v = v.value\n") f.write( f" self.{c.name} = set_embedded_in_uint(v, self.{c.name},[{start_end_bit[0]}-idx*{rawtype.bits},{start_end_bit[0]}+1-(idx+1)*{rawtype.bits}])\n" ) f.write( f" return ArrayLike( getter=getter, setter=setter, mytype={fqn(a.type)}, shape={i.name}._meta['{a.name}']['_get_dim_nd'](self) )\n" ) f.write(f"\n") f.write(f" @{a.name}.setter\n") f.write(f" def {a.name}(self, v):\n") f.write(f" self.{a.name}.copy_from(v)\n") f.write(f"\n") # -------------------------------------------------------------- pass else: raise Exception("unexpected type") else: # not embedded if textx_isinstance(a, mm["ScalarAttribute"]): if textx_isinstance(a.type, mm["RawType"]): f.write(" {} : {}={}()\n".format( a.name, fqn(a.type), fqn(a.type))) else: if textx_isinstance(a.type, mm["Enum"]): f.write(" {} : {} = {}.{}\n".format( a.name, fqn(a.type), fqn(a.type), a.type.enum_entries[0].name, )) else: f.write( " {} : {}= field( default_factory=lambda: {}() )\n" .format(a.name, fqn(a.type), fqn(a.type))) if hasattr(a, "type") and a.type.name == "char": f.write(f" @property\n") f.write(f" def {a.name}_as_str(self):\n") f.write(f" return chr(self.{a.name})\n") f.write(f"\n") f.write(f" @{a.name}_as_str.setter\n") f.write(f" def {a.name}_as_str(self, v):\n") f.write( f" self.{a.name} = np.uint8(ord(v))\n") f.write(f"\n") elif textx_isinstance(a, mm["ArrayAttribute"]): if textx_isinstance(a.type, mm["RawType"]): f.write(" {} : np.ndarray=None\n".format( a.name)) else: f.write(" {} : Sequence[{}]=None\n".format( a.name, fqn(a.type))) if hasattr(a, "type") and a.type.name == "char": f.write(f" @property\n") f.write(f" def {a.name}_as_str(self):\n") f.write( f" return array2str(self.{a.name})\n") f.write(f"\n") f.write(f" @{a.name}_as_str.setter\n") f.write(f" def {a.name}_as_str(self, v):\n") f.write( f" self.{a.name} = str2array(v, len(self.{a.name}))\n" ) f.write(f"\n") elif textx_isinstance(a, mm["VariantAttribute"]): f.write(" {} : Union[{}]=None\n".format( a.name, get_variant_types(a))) else: raise Exception("unexpected type") pdefs = get_all_possible_properties(a) pdefs = sorted(pdefs.keys()) if "fixpointLsbValue" in pdefs: if textx_isinstance(a, mm["ScalarAttribute"]): if has_fixpoint(a): f.write(f" @property\n") f.write( f" def {'item_fixpoint_'+a.name}(self):\n") f.write( f" return int2float_fixpoint_value(self, '{a.name}', self.{a.name})\n" ) f.write(f" @{'item_fixpoint_'+a.name}.setter\n") f.write( f" def {'item_fixpoint_'+a.name}(self, v):\n" ) f.write( f" self.{a.name} = float2int_fixpoint_value(self, '{a.name}', v)\n" ) elif textx_isinstance(a, mm["ArrayAttribute"]): if has_fixpoint(a): f.write(f" @property\n") f.write( f" def {'item_fixpoint_'+a.name}(self):\n") f.write( f" return FixpointArrayLike(self, '{a.name}')\n" ) f.write(f" @{'item_fixpoint_'+a.name}.setter\n") f.write( f" def {'item_fixpoint_'+a.name}(self, v):\n" ) f.write( f" self.{a.name} = float2int_fixpoint_value(self, '{a.name}', v)\n" ) f.write("\n def __post_init__(self):\n") f.write(" init_default_values(self)\n") f.write(f""" def __setattr__(self, attribute, value): if not attribute in self._meta: raise Exception("Illegal field {{}} in {{}}".format(attribute,self.__class__.__name__)) else: if len(self._meta[attribute])==0: super({i.name}, self).__setattr__(attribute, value) elif self._meta[attribute]["_is_embedded"]: super({i.name}, self).__setattr__(attribute, value) elif value is None: self.__dict__[attribute] = value elif self._meta[attribute]["_is_variant"]: if isinstance(value, self._meta[attribute]["_get_type"]()): self.__dict__[attribute] = value else: raise Exception("Illegal value of type {{}} for field {{}}".format(value.__class__.__name__,attribute)) elif self._meta[attribute]["_is_scalar"]: if isinstance(value, self._meta[attribute]["_get_type"]()): self.__dict__[attribute] = value elif self._meta[attribute]["_is_rawtype"]: self.__dict__[attribute] = self._meta[attribute]["_get_type"]()(value) else: raise Exception("Illegal value of type {{}} for field {{}}".format(value.__class__.__name__,attribute)) else: self.__dict__[attribute] = np.array(value, dtype=self._meta[attribute]["_get_type"]()) """) f.write("\n _meta_order = [\n") for a in i.attributes: f.write(f" '{a.name}',\n") f.write("\n ]\n") f.write("\n _meta = {\n") for a in i.attributes: pdefs = get_all_possible_properties(a) pdefs = sorted(pdefs.keys()) if "fixpointLsbValue" in pdefs: if has_fixpoint(a): f.write(' "item_fixpoint_{}": {{}},'.format( a.name)) if hasattr(a, "type") and a.type.name == "char": f.write(f' "{a.name}_as_str": {{}},\n') if a.is_variant(): for m in a.mappings: m_pdefs = get_all_possible_properties(m) m_pdefs = sorted(m_pdefs.keys()) f.write(f' "{meta_name_for_mapping(m)}": ') f.write("{") output_properties(f, m, m_pdefs) f.write("},\n") f.write(' "{}": {{ '.format(a.name)) f.write('"_name":"{}",'.format(a.name)) if a.if_attr is None: f.write('"_has_if_restriction":False,') f.write('"_if_restriction":lambda _: True,') else: f.write('"_has_if_restriction":True,') f.write('"_if_restriction":lambda s:{},'.format( a.if_attr.predicate.render_formula(prefix="s."))) if textx_isinstance(a, mm["VariantAttribute"]): f.write('"_get_type_for": lambda s: {}[s.{}], '.format( get_variant_type_map(a), a.variant_selector.render_formula(**fp(struct_obj)), )) f.write('"_get_meta_for": lambda s: {}[s.{}], '.format( get_variant_meta_map(struct_obj, a), a.variant_selector.render_formula(**fp(struct_obj)), )) f.write('"_is_scalar":True,') f.write('"_is_variant":True,') f.write('"_is_array":False,') f.write('"_is_rawtype":False,') f.write('"_is_enum":False,') f.write('"_is_struct":True,') f.write('"_is_embedded":False,') f.write('"_get_type": lambda: ({}), '.format( get_variant_types(a))) elif textx_isinstance(a, mm["ScalarAttribute"]): f.write(f'"_is_container":{a.is_container()},') f.write('"_is_scalar":True,') f.write('"_is_variant":False,') f.write('"_is_array":False,') if textx_isinstance(a.type, mm["RawType"]): f.write('"_is_rawtype":True,') else: f.write('"_is_rawtype":False,') if textx_isinstance(a.type, mm["Struct"]): f.write('"_is_struct":True,') else: f.write('"_is_struct":False,') if textx_isinstance(a.type, mm["Enum"]): f.write('"_is_enum":True,') else: f.write('"_is_enum":False,') f.write(f'"_is_embedded":{tf(a.is_embedded())},') f.write('"_get_type": lambda: {}, '.format(fqn(a.type))) if textx_isinstance(a.type, mm["Enum"]): f.write('"_get_underlying_type": lambda: {}, '.format( fqn(a.type.type))) if hasattr(a, "type") and a.type.name == "char": f.write('"_has_char_content":True,') else: f.write('"_has_char_content":False,') elif textx_isinstance(a, mm["ArrayAttribute"]): f.write('"_is_scalar":False,') f.write('"_is_variant":False,') f.write('"_is_array":True,') if a.has_fixed_size(): f.write('"_is_dynamic_array":False,') else: f.write('"_is_dynamic_array":True,') f.write('"_get_dim":lambda x:({}),'.format( a.render_formula(prefix="x.", **fp(struct_obj)))) f.write('"_get_dim_nd":lambda x:({},),'.format( a.render_formula_comma_separated(prefix="x.", **fp(struct_obj)))) if textx_isinstance(a.type, mm["RawType"]): f.write('"_is_rawtype":True,') else: f.write('"_is_rawtype":False,') if textx_isinstance(a.type, mm["Struct"]): f.write('"_is_struct":True,') else: f.write('"_is_struct":False,') if textx_isinstance(a.type, mm["Enum"]): f.write('"_is_enum":True,') else: f.write('"_is_enum":False,') f.write(f'"_is_embedded":{tf(a.is_embedded())},') f.write('"_get_type": lambda: {}, '.format(fqn(a.type))) if textx_isinstance(a.type, mm["Enum"]): f.write('"_get_underlying_type": lambda: {}, '.format( fqn(a.type.type))) if hasattr(a, "type") and a.type.name == "char": f.write('"_has_char_content":True,') else: f.write('"_has_char_content":False,') else: raise Exception("unexpected type constellation") pdefs = get_all_possible_properties(a) pdefs = sorted(pdefs.keys()) if "fixpointLsbValue" in pdefs: if has_fixpoint(a): f.write(f'"_is_fixpoint":True,') f.write( f'"_fixpointLsbValue": {get_fixpoint_LSB_value(a)},' ) f.write( f'"_fixpointOffsetValue": {get_fixpoint_offset_value(a)},' ) else: f.write(f'"_is_fixpoint":False,') else: f.write(f'"_is_fixpoint":False,') output_properties(f, a, pdefs) f.write("},\n") f.write(" } # end of _meta\n") f.write(" _meta_struct={\n") for up in get_all_unique_properties(i): f.write( f" 'item_get_unique_{up[0].name}':lambda i:i.{'.'.join(map(lambda x:x.name, up[1]))},\n" ) f.write( f" 'item_set_unique_{up[0].name}':lambda i,v:setattr({'.'.join(['i']+list(map(lambda x: x.name, up[1][:-1])))}, '{up[1][-1].name}',v),\n" ) f.write(" } # end of _meta_struct\n")
def test_rrel_basic_lookup(): """ This is a basic test for the find function: we use a model with some structure and query this structure with RREL expressions. """ ################################# # META MODEL DEF ################################# my_metamodel = metamodel_from_str(metamodel_str) ################################# # MODEL PARSING ################################# my_model = my_metamodel.model_from_str(modeltext) ################################# # TEST ################################# P2 = find(my_model, "P2", "packages") assert P2.name == "P2" Part2 = find(my_model, "P2.Part2", "packages.classes") assert Part2.name == "Part2" rec = find(my_model, "P2.Part2.rec", "packages.classes.attributes") rec_with_fixed_name = find(my_model, "P2.rec", "packages.'Part2'~classes.attributes") assert rec_with_fixed_name is rec assert rec.name == "rec" assert rec.parent == Part2 P2 = find(my_model, "P2", "(packages)") assert P2.name == "P2" from textx import get_model assert get_model(my_model) is my_model P2 = find(my_model, "P2", "packages*") assert P2.name == "P2" Part2 = find(my_model, "P2.Part2", "packages*.classes") assert Part2.name == "Part2" rec = find(my_model, "P2.Part2.rec", "packages*.classes.attributes") assert rec.name == "rec" assert rec.parent == Part2 Part2_tst = find(rec, "", "..") assert Part2_tst is Part2 P2_from_inner_node = find(rec, "P2", "(packages)") assert P2_from_inner_node is P2 P2_tst = find(rec, "", "parent(Package)") assert P2_tst is P2 P2_tst = find(rec, "", "...") assert P2_tst is P2 P2_tst = find(rec, "", ".(..).(..)") assert P2_tst is P2 P2_tst = find(rec, "", "(..).(..)") assert P2_tst is P2 P2_tst = find(rec, "", "...(.).(.)") assert P2_tst is P2 P2_tst = find(rec, "", "..(.).(..)") assert P2_tst is P2 P2_tst = find(rec, "", "..((.)*)*.(..)") assert P2_tst is P2 none = find(my_model, "", "..") assert none is None m = find(my_model, "", ".") # '.' references the current element assert m is my_model inner = find(my_model, "inner", "~packages.~packages.~classes.attributes") assert inner.name == "inner" package_Inner = find(inner, "Inner", "parent(OBJECT)*.packages") assert textx_isinstance(package_Inner, my_metamodel["Package"]) assert not textx_isinstance(package_Inner, my_metamodel["Class"]) assert None is find(inner, "P2", "parent(Class)*.packages") # expensive version of a "Plain Name" scope provider: inner = find(my_model, "inner", "~packages*.~classes.attributes") assert inner.name == "inner" rec2 = find(my_model, "P2.Part2.rec", "other1,other2,packages*.classes.attributes") assert rec2 is rec rec2 = find(my_model, "P2.Part2.rec", "other1,packages*.classes.attributes,other2") assert rec2 is rec rec2 = find(my_model, "P2::Part2::rec", "other1,packages*.classes.attributes,other2", split_string="::") assert rec2 is rec rec2 = find(my_model, "P2.Part2.rec", "other1,other2,other3") assert rec2 is None rec2 = find(my_model, "P2.Part2.rec", "(packages,classes,attributes)*") assert rec2 is rec rec2 = find(my_model, "P2.Part2.rec", "(packages,(classes,attributes)*)*.attributes") assert rec2 is rec rec2 = find(my_model, "rec", "(~packages,~classes,attributes,classes)*") assert rec2.name == "rec" rec2 = find(my_model, "rec", "(~packages,~classes,attributes,classes)*", my_metamodel["OBJECT"]) assert rec2.name == "rec" rec2 = find(my_model, "rec", "(~packages,~classes,attributes,classes)*", my_metamodel["Attribute"]) assert rec2 is rec rec2 = find(my_model, "rec", "(~packages,~classes,attributes,classes)*", my_metamodel["Package"]) assert rec2 is None rec2 = find(my_model, "rec", "(~packages,classes,attributes,~classes)*", my_metamodel["Class"]) assert rec2.name == "rec" assert rec2 is not rec # it is the class... rec2 = find(my_model, "rec", "(~packages,~classes,attributes,classes)*", my_metamodel["Class"]) assert rec2.name == "rec" assert rec2 is not rec # it is the class... t = find(my_model, "", ".") assert t is my_model t = find(my_model, "", "(.)") assert t is my_model t = find(my_model, "", "(.)*") assert t is my_model t = find(my_model, "", "(.)*.no_existent") # inifite recursion stopper assert t is None rec2 = find(my_model, "rec", "(.)*.(~packages,~classes,attributes,classes)*", my_metamodel["Class"]) assert rec2.name == "rec" assert rec2 is not rec # it is the class... # Here, we test the start_from_root/start_locally logic: P2t = find(rec, "P2", "(.)*.packages") assert P2t is None P2t = find(rec, "P2", "(.,not_existent_but_root)*.packages") assert P2t is P2 rect = find(rec, "rec", "(~packages)*.(..).attributes") assert rect is None rect = find(rec, "rec", "(.,~packages)*.(..).attributes") assert rect is rec
def __call__(self, obj, attr, obj_ref): """ the default scope provider Args: obj: unused (used for multi_metamodel_support) attr: unused obj_ref: the cross reference to be resolved Returns: the resolved reference or None """ from textx.const import RULE_COMMON, RULE_ABSTRACT from textx.model import ObjCrossRef from textx.scoping.tools import get_parser if obj_ref is None: return None # an error! (see model.py: resolve_refs (TODO check) assert type(obj_ref) is ObjCrossRef, type(obj_ref) if get_parser(obj).debug: get_parser(obj).dprint("Resolving obj crossref: {}:{}" .format(obj_ref.cls, obj_ref.obj_name)) def _inner_resolve_link_rule_ref(cls, obj_name): """ Depth-first resolving of link rule reference. """ if cls._tx_type is RULE_ABSTRACT: for inherited in cls._tx_inh_by: result = _inner_resolve_link_rule_ref(inherited, obj_name) if result: return result elif cls._tx_type == RULE_COMMON: # TODO make this code exchangable # allow to know the current attribute (model location for # namespace) and to navigate through the whole model... # OR (with another scope provider) to make custom lookups in # the model # # Scopeprovider # - needs: .current reference (in the model) # .the model (?) # - provides: the resolved object or None if id(cls) in get_parser(obj)._instances: objs = get_parser(obj)._instances[id(cls)] return objs.get(obj_name) if self.multi_metamodel_support: from textx import get_model, get_children from textx import textx_isinstance result_lst = get_children( lambda x: _hasattr(x, "name") and _getattr(x, "name") == obj_ref.obj_name and textx_isinstance(x, obj_ref.cls), get_model(obj)) if len(result_lst) == 1: result = result_lst[0] elif len(result_lst) > 1: line, col = get_parser(obj).pos_to_linecol(obj_ref.position) raise TextXSemanticError( "name {} is not unique.".format(obj_ref.obj_name), line=line, col=col, filename=get_model(obj)._tx_filename) else: result = None else: result = _inner_resolve_link_rule_ref(obj_ref.cls, obj_ref.obj_name) if result: return result return None # error handled outside
def test_metamodel_provider_advanced_test3_global_single_metamodel(): """ simplified test with only one meta model """ ################################# # META MODEL DEF ################################# this_folder = dirname(abspath(__file__)) def get_meta_model(global_repo, grammar_file_name): mm = metamodel_from_file(join(this_folder, grammar_file_name), debug=False, classes=[Cls, Obj]) mm.register_scope_providers({ "*.*": global_repo, }) return mm global_repo_provider = scoping_providers.PlainNameGlobalRepo() global_repo_provider.register_models( join(this_folder, "metamodel_provider3", "single", "*.a")) a_mm = get_meta_model( global_repo_provider, join(this_folder, "metamodel_provider3", "A.tx")) clear_language_registrations() register_language( 'a-dsl', pattern='*.a', description='Test Lang A', metamodel=a_mm) ################################# # MODEL PARSING ################################# model_repo = global_repo_provider.load_models_in_model_repo().all_models ################################# # TEST MODEL ################################# def get_all(model_repo, what): lst = [] for m in model_repo.filename_to_model.values(): lst = lst + get_children_of_type(what, m) return lst lst = get_all(model_repo, "Obj") # print(lst) assert len(lst) == 3 # check some references to be resolved (!=None) for a in lst: assert a.ref # check meta classes assert a_mm["Cls"]._tx_fqn == a_mm["Cls"]._tx_fqn # more checks from textx import textx_isinstance for a in lst: assert textx_isinstance(a, a_mm["Obj"]) assert textx_isinstance(a, a_mm["Obj"]) assert textx_isinstance(a, a_mm["Obj"]) ################################# # END ################################# clear_language_registrations()