def resolve_refs(model): """ Resolves model references. """ metamodel = parser.metamodel current_crossrefs = parser._crossrefs new_crossrefs = [] delayed_crossrefs = [] resolved_crossref_count = 0 # ------------------------- # start of resolve-loop # ------------------------- default_scope = DefaultScopeProvider() for obj, attr, crossref in current_crossrefs: if (get_model(obj) == model): attr_value = getattr(obj, attr.name) attr_refs = [ obj.__class__.__name__ + "." + attr.name, "*." + attr.name, obj.__class__.__name__ + ".*", "*.*" ] for attr_ref in attr_refs: if attr_ref in metamodel.scope_providers: if parser.debug: parser.dprint(" FOUND {}".format(attr_ref)) resolved = metamodel.scope_providers[attr_ref]( parser, obj, attr, crossref) break else: resolved = default_scope(parser, obj, attr, crossref) # Collect cross-references for textx-tools if resolved and not type(resolved) is Postponed: if metamodel.textx_tools_support: 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 not resolved: # As a fall-back search builtins if given if metamodel.builtins: if crossref.obj_name in metamodel.builtins: # TODO: Classes must match resolved = metamodel.builtins[crossref.obj_name] if not resolved: line, col = parser.pos_to_linecol(crossref.position) raise TextXSemanticError( message='Unknown object "{}" of class "{}" at {}'. format(crossref.obj_name, crossref.cls.__name__, (line, col)), line=line, col=col, err_type=UNKNOWN_OBJ_ERROR, expected_obj_cls=crossref.cls) if type(resolved) is Postponed: 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) this happens when other models are loaded while parsing # one model. parser._crossrefs = new_crossrefs return (resolved_crossref_count, delayed_crossrefs)
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)