def ref_scope(refItem, myattr, 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 = list(map(lambda x: id(x), reference.refs)).index(id(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, myattr.cls): print(x) return None return x
def lookup(obj): if needs_to_be_resolved(obj, self.name): return Postponed(), lookup_list, matched_path if hasattr(obj, self.name): target = getattr(obj, self.name) if not self.consume_name and self.fixed_name is None: return target, lookup_list, matched_path # return list else: if not isinstance(target, list): target = [target] if self.fixed_name is not None: lst = list( filter( lambda x: hasattr(x, "name") and getattr( x, "name") == self.fixed_name, target)) if len(lst) > 0: return lst[0], lookup_list, matched_path + [ lst[0] ] # return obj else: return None, lookup_list, matched_path # return None else: lst = list( filter( lambda x: hasattr(x, "name") and getattr( x, "name") == lookup_list[0], target)) if len(lst) > 0: return lst[0], lookup_list[1:], matched_path + [ lst[0] ] # return obj else: return None, lookup_list, matched_path # return None else: return None, lookup_list, matched_path
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 generic_scope_provider(obj, attr, attr_ref): if not obj.pyobj: from textx.scoping import Postponed return Postponed() if not hasattr(obj.pyobj, "data"): import json obj.pyobj.data = json.load( open(abspath(dirname(__file__)) + "/" + obj.pyobj.filename)) if attr_ref.obj_name in obj.pyobj.data: return obj.pyobj.data[attr_ref.obj_name] else: raise Exception("{} not found".format(attr_ref.obj_name))
def __call__(self, obj, attr, attr_ref): if attr.name == "pyobj": if attr_ref.obj_name in self.dict_with_objects: return self.dict_with_objects[attr_ref.obj_name] else: raise Exception("{} not found".format(attr_ref.obj_name)) else: if not obj.pyobj: from textx.scoping import Postponed return Postponed() if hasattr(obj.pyobj, attr_ref.obj_name): return getattr(obj.pyobj, attr_ref.obj_name) else: raise Exception("{} not found".format(attr_ref.obj_name))
def apply(self, obj, lookup_list, matched_path, first_element): """ Args: obj: model object lookup_list: non-empty name list Returns: The object indicated by the navigation object, Postponed, None, or a list (if a list has to be processed). """ from textx.scoping.tools import needs_to_be_resolved from textx.scoping import Postponed if first_element: from textx import get_model obj = get_model(obj) if len(lookup_list) == 0 and self.consume_name: return None, lookup_list, matched_path if needs_to_be_resolved(obj, self.name): return Postponed(), lookup_list, matched_path if hasattr(obj, self.name): target = getattr(obj, self.name) if not self.consume_name and self.fixed_name is None: return target, lookup_list, matched_path # return list else: if not isinstance(target, list): target = [target] if self.fixed_name is not None: lst = list( filter( lambda x: hasattr(x, "name") and getattr( x, "name") == self.fixed_name, target)) if len(lst) > 0: return lst[0], lookup_list, matched_path + [ lst[0] ] # return obj else: return None, lookup_list, matched_path # return None else: lst = list( filter( lambda x: hasattr(x, "name") and getattr( x, "name") == lookup_list[0], target)) if len(lst) > 0: return lst[0], lookup_list[1:], matched_path + [ lst[0] ] # return obj else: return None, lookup_list, matched_path # return None else: return None, lookup_list, matched_path
def json_scope_provider(obj, attr, attr_ref): if not obj.pyobj: from textx.scoping import Postponed return Postponed() if not hasattr(obj.pyobj, "data"): import json obj.pyobj.data = json.load( open( os.path.join( os.path.abspath( os.path.dirname(get_model(obj)._tx_filename)), obj.pyobj.filename))) if attr_ref.obj_name in obj.pyobj.data: return obj.pyobj.data[attr_ref.obj_name] else: raise TextXSemanticError("{} not found".format(attr_ref.obj_name))
def ref_scope(refItem, attr, attr_ref): from textx.scoping.tools import get_referenced_object from textx.scoping import Postponed reference = refItem.parent if reference is None: return Postponed() index = reference.refs.index(refItem) assert (index >= 0) if index == 0: return get_referenced_object( None, reference, "instance.type.vals.{}".format(attr_ref.obj_name), attr_ref.cls) else: return get_referenced_object( None, reference.refs[index - 1], "valref.type.vals.{}".format(attr_ref.obj_name), attr_ref.cls)
def __call__(self, *args, **kwargs): ret = self.base(*args, **kwargs) if ret is None: return Postponed() else: return ret
def resolve_model_path(obj, dot_separated_name, follow_named_element_in_lists=False): """ Get a model object based on a model-path starting from some model object. It can be used in the same way you would navigate through a normal instance of a model object, except: - "parent(TYPE)" can be used to navigate to the parent of an element repeatedly, until a certain type is reached (see unittest). - lists of named objects (e.g. lists of named packages) can be traversed, as if the named objects were part of the model grammar (see unittest: Syntax, "name_of_model_list.name_of_named_obj_in_list"). - None/Postponed values are intercepted and lead to an overall return value None/Postponed. A use case for this function is, when a model path needs to be stored and executed on a previously unknown object and/or the Postpone/None-logic is required. Args: obj: the current object dot_separated_name: the attribute name "a.b.c.d" starting from obj Note: the attribute "parent(TYPE)" is a shortcut to jump to the parent of type "TYPE" (exact match of type name). follow_named_element_in_lists: follow named elements in list if True override_unresolved_lists: try to follow unresolved lists, if True Returns: the object if found, or Postponed() if some postponed refs are found on the path / or obj is not found """ from textx.scoping import Postponed names = dot_separated_name.split(".") match = re.match(r'parent\((\w+)\)', names[0]) if obj is None or type(obj) is Postponed: return obj elif type(obj) is list: if follow_named_element_in_lists: next_obj = get_named_obj_in_list(obj, names[0]) else: from textx.exceptions import TextXError raise TextXError( "unexpected: got list in path for get_referenced_object") elif match: next_obj = obj desired_parent_typename = match.group(1) next_obj = get_recursive_parent_with_typename( next_obj, desired_parent_typename) if type(next_obj) is Postponed: return next_obj elif next_obj is not None: return resolve_model_path(next_obj, ".".join(names[1:]), follow_named_element_in_lists) else: return None else: next_obj = getattr(obj, names[0]) if needs_to_be_resolved(obj, names[0]): return Postponed() elif next_obj is None: return None if len(names) > 1: return resolve_model_path(next_obj, ".".join( names[1:]), follow_named_element_in_lists) return next_obj
def get_referenced_object(prev_obj, obj, dot_separated_name, desired_type=None): """ get objects based on a path Args: prev_obj: the object containing obj (req. is obj is a list) obj: the current object dot_separated_name: the attribute name "a.b.c.d" starting from obj Note: the attribute "parent(TYPE)" is a shortcut to jump to the parent of type "TYPE" (exact match of type name). desired_type: (optional) Returns: the object if found, None if not found or Postponed() if some postponed refs are found on the path """ from textx.scoping import Postponed assert prev_obj or not type(obj) is list names = dot_separated_name.split(".") match = re.match(r'parent\((\w+)\)', names[0]) if match: next_obj = obj desired_parent_typename = match.group(1) next_obj = get_recursive_parent_with_typename(next_obj, desired_parent_typename) if next_obj: return get_referenced_object(None, next_obj, ".".join(names[1:]), desired_type) else: return None elif type(obj) is list: next_obj = None for res in obj: if hasattr(res, "name") and getattr(res, "name") == names[0]: if desired_type is None or textx_isinstance(res, desired_type): next_obj = res else: raise TypeError("{} has type {} instead of {}.".format( names[0], type(res).__name__, desired_type.__name__)) if not next_obj: # if prev_obj needs to be resolved: return Postponed. if needs_to_be_resolved(prev_obj, names[0]): return Postponed() else: return None elif type(obj) is Postponed: return Postponed() else: next_obj = getattr(obj, names[0]) if not next_obj: # if obj in in crossref return Postponed, else None if needs_to_be_resolved(obj, names[0]): return Postponed() else: return None if len(names) > 1: return get_referenced_object(obj, next_obj, ".".join(names[1:]), desired_type) if type(next_obj) is list and needs_to_be_resolved(obj, names[0]): return Postponed() return next_obj