def resume( self, requires: typing.Dict[object, object], resolver: Resolver, queue: QueueScheduler, target: ResultVariable ) -> None: root_object = self.rootobject.execute(requires, resolver, queue) if not isinstance(root_object, Instance): raise TypingException(self, "short index lookup is only possible one objects, %s is not an object" % root_object) from_entity = root_object.get_type() relation = from_entity.get_attribute(self.relation) if not isinstance(relation, RelationAttribute): raise TypingException(self, "short index lookup is only possible on relations, %s is an attribute" % relation) if relation.end is None: raise TypingException( self, "short index lookup is only possible on bi-drectional relations, %s is unidirectional" % relation ) self.type = relation.type self.type.lookup_index( list( chain( [(relation.end.name, root_object)], ((k, v.execute(requires, resolver, queue)) for (k, v) in self.querypart), ((k, v) for kwargs in self.wrapped_querypart for (k, v) in kwargs.execute(requires, resolver, queue)), ) ), self, target, )
def resume(self, requires: typing.Dict[object, ResultVariable], resolver: Resolver, queue: QueueScheduler, target: ResultVariable) -> None: root_object = self.rootobject.execute(requires, resolver, queue) if not isinstance(root_object, Instance): raise TypingException( self, "short index lookup is only possible one objects, %s is not an object" % root_object) from_entity = root_object.get_type() relation = from_entity.get_attribute(self.relation) if not isinstance(relation, RelationAttribute): raise TypingException( self, "short index lookup is only possible on relations, %s is an attribute" % relation) self.type = relation.get_type() self.type.lookup_index([(relation.end.name, root_object)] + [(k, v.execute(requires, resolver, queue)) for (k, v) in self.querypart], self, target)
def evaluate(self): """ Add this relation to the participating ends """ try: left = self.namespace.get_type(self.left[0]) except TypeNotFoundException as e: e.set_location(self.location) raise e if isinstance(left, Default): raise TypingException( self, "Can not define relation on a default constructor %s, use base type instead: %s " % ( left.name, left.get_entity().get_full_name()) ) if left.get_attribute_from_related(self.right[1]) is not None: raise DuplicateException(self, left.get_attribute_from_related(self.right[1]), ("Attribute name %s is already defined in %s, unable to define relationship") % (self.right[1], left.name)) try: right = self.namespace.get_type(self.right[0]) except TypeNotFoundException as e: e.set_location(self.location) raise e if isinstance(right, Default): raise TypingException( self, "Can not define relation on a default constructor %s, use base type instead: %s " % ( right.name, right.get_entity().get_full_name()) ) if right.get_attribute_from_related(self.left[1]) is not None: raise DuplicateException(self, right.get_attribute_from_related(self.left[1]), ("Attribute name %s is already defined in %s, unable to define relationship") % (self.left[1], right.name)) if self.left[1] is not None: left_end = RelationAttribute(right, left, self.left[1]) left_end.set_multiplicity(self.left[2]) left_end.comment = self.comment self.copy_location(left_end) else: left_end = None if self.right[1] is not None: right_end = RelationAttribute(left, right, self.right[1]) right_end.set_multiplicity(self.right[2]) right_end.comment = self.comment self.copy_location(right_end) else: right_end = None if left_end is not None and right_end is not None: left_end.end = right_end right_end.end = left_end
def evaluate(self) -> None: """ Evaluate this statement. """ try: entity_type = self.type entity_type.comment = self.comment add_attributes = {} for attribute in self.attributes: attr_type = self.namespace.get_type(attribute.type) if not isinstance(attr_type, (Type, type)): raise TypingException(self, "Attributes can only be a type. Entities need to be defined as relations.") attr_obj = Attribute(entity_type, attr_type, attribute.name, attribute.multi, attribute.nullable) attribute.copy_location(attr_obj) add_attributes[attribute.name] = attr_obj if attribute.default is not None: entity_type.add_default_value(attribute.name, attribute.default) elif attribute.remove_default: entity_type.add_default_value(attribute.name, None) if len(set(self.parents)) != len(self.parents): raise TypingException(self, "same parent defined twice") for parent in self.parents: parent_type = self.namespace.get_type(str(parent)) if parent_type is self.type: raise TypingException(self, "Entity can not be its own parent (%s) " % parent) if not isinstance(parent_type, Entity): raise TypingException(self, "Parents of an entity need to be entities. " "Default constructors are not supported. %s is not an entity" % parent) entity_type.parent_entities.append(parent_type) parent_type.child_entities.append(entity_type) for parent_type in entity_type.get_all_parent_entities(): for attr_name, other_attr in parent_type.attributes.items(): if attr_name not in add_attributes: add_attributes[attr_name] = other_attr else: # allow compatible attributes my_attr = add_attributes[attr_name] if my_attr.type == other_attr.type: add_attributes[attr_name] = other_attr else: raise DuplicateException( my_attr, other_attr, "Incompatible attributes") # verify all attribute compatibility except TypeNotFoundException as e: e.set_statement(self) raise e
def execute(self, requires: typing.Dict[object, object], resolver: Resolver, queue: QueueScheduler) -> object: mapv = self.themap.execute(requires, resolver, queue) if not isinstance(mapv, dict): raise TypingException(self, "dict lookup is only possible on dicts, %s is not an object" % mapv) keyv = self.key.execute(requires, resolver, queue) if not isinstance(keyv, str): raise TypingException(self, "dict keys must be string, %s is not a string" % keyv) if keyv not in mapv: raise KeyException(self, "key %s not found in dict, options are [%s]" % (keyv, ",".join(mapv.keys()))) return mapv[keyv]
def evaluate(self) -> None: """ Evaluate this statement. """ try: entity_type = self.namespace.get_type(self.entity) if not isinstance(entity_type, EntityLike): raise TypingException( self, "Implementation can only be define for an Entity, but %s is a %s" % (self.entity, entity_type)) entity_type = entity_type.get_entity() # If one implements statement has parent declared, set to true entity_type.implements_inherits |= self.inherit implement = Implement() implement.comment = self.comment implement.constraint = self.select implement.location = self.entity_location i = 0 for _impl in self.implementations: i += 1 # check if the implementation has the correct type impl_obj = self.namespace.get_type(_impl) assert isinstance( impl_obj, Implementation), "%s is not an implementation" % (_impl) if impl_obj.entity is not None and not ( entity_type is impl_obj.entity or entity_type.is_parent(impl_obj.entity)): raise TypingException( self, "Type mismatch: cannot use %s as implementation for " " %s because its implementing type is %s" % (impl_obj.name, entity_type, impl_obj.entity), ) # add it implement.implementations.append(impl_obj) entity_type.add_implement(implement) except TypeNotFoundException as e: e.set_statement(self) raise e
def evaluate(self) -> None: """ Evaluate this statement. """ # the base class type_class = self.namespace.get_type(self.ctor.class_type) if not isinstance(type_class, EntityLike): raise TypingException( self, "Default can only be define for an Entity, but %s is a %s" % (self.ctor.class_type, self.ctor.class_type)) inmanta_warnings.warn( CompilerDeprecationWarning( self, "Default constructors are deprecated. Use inheritance instead." )) self.type.comment = self.comment default = self.type default.set_entity(type_class) for name, value in self.ctor.get_attributes().items(): default.add_default(name, value)
def _bin_op(self, arg1: object, arg2: object) -> object: """ @see Operator#_op """ if not isinstance(arg1, (int, float)) or not isinstance(arg2, (int, float)): raise TypingException(self, "Can only compare numbers.") return arg1 >= arg2
def execute(self, requires: Dict[object, object], resolver: Resolver, queue: QueueScheduler) -> List[Tuple[str, object]]: dct: object = self.dictionary.execute(requires, resolver, queue) if not isinstance(dct, Dict): raise TypingException( self, "The ** operator can only be applied to dictionaries") return list(dct.items())
def final(self, excns: List[Exception]) -> None: for rv in self.source_annotations: try: if isinstance(rv.get_value(), Unknown): excns.append( TypingException( self, "Relation annotation can not be Unknown")) except RuntimeException as e: excns.append(e) for rv in self.target_annotations: try: if isinstance(rv.get_value(), Unknown): excns.append( TypingException( self, "Relation annotation can not be Unknown")) except RuntimeException as e: excns.append(e)
def _bin_op(self, arg1: object, arg2: object) -> object: """ @see Operator#_op """ assert arg2 == self.regex if not isinstance(arg1, str): raise TypingException(self, "Regex can only be match with strings. %s is of type %s" % (arg1, type(arg1))) return self.regex.match(arg1) is not None
def _bin_op(self, arg1, arg2): """ @see Operator#_op """ if not isinstance(arg1, str): raise TypingException( self, "Regex can only be match with strings. %s is of type %s" % arg1) return arg2.match(arg1) is not None
def normalize(self) -> None: mytype: "EntityLike" = self.namespace.get_type(self.class_type) self.type = mytype for (k, v) in self.__attributes.items(): v.normalize() for wrapped_kwargs in self.wrapped_kwargs: wrapped_kwargs.normalize() inindex = set() all_attributes = dict(self.type.get_default_values()) all_attributes.update(self.__attributes) # now check that all variables that have indexes on them, are already # defined and add the instance to the index for index in self.type.get_entity().get_indices(): for attr in index: if attr not in all_attributes: self.required_kwargs.append(attr) continue inindex.add(attr) if self.required_kwargs and not self.wrapped_kwargs: raise TypingException( self, "attributes %s are part of an index and should be set in the constructor." % ",".join(self.required_kwargs), ) for (k, v) in all_attributes.items(): attribute = self.type.get_entity().get_attribute(k) if attribute is None: raise TypingException( self, "no attribute %s on type %s" % (k, self.type.get_full_name())) if k not in inindex: self._indirect_attributes[k] = v else: self._direct_attributes[k] = v
def _bin_op(self, arg1: object, arg2: object) -> object: """ @see Operator#_op """ if isinstance(arg2, dict): return arg1 in arg2 elif isinstance(arg2, list): for arg in arg2: if arg == arg1: return True else: raise TypingException(self, "Operand two of 'in' can only be a list or dict (%s)" % arg2) return False
def resume( self, requires: typing.Dict[object, object], resolver: Resolver, queue: QueueScheduler, target: ResultVariable ) -> None: instance = self.instance.execute(requires, resolver, queue) if not isinstance(instance, Instance): raise TypingException( self, "The object at %s is not an Entity but a %s with value %s" % (self.instance, type(instance), instance) ) var = instance.get_attribute(self.attribute_name) if self.list_only and not var.is_multi(): raise TypingException(self, "Can not use += on relations with multiplicity 1") if var.is_multi(): # gradual only for multi # to preserve order on lists used in attributes # while allowing gradual execution on relations reqs = self.value.requires_emit_gradual( resolver, queue, GradualSetAttributeHelper(self, instance, self.attribute_name, var) ) else: reqs = self.value.requires_emit(resolver, queue) SetAttributeHelper(queue, resolver, var, reqs, self.value, self, instance, self.attribute_name)
def normalize(self) -> None: self.type = self.namespace.get_type(self.class_type) for (k, v) in self.__attributes.items(): v.normalize() inindex = set() # now check that all variables that have indexes on them, are already # defined and add the instance to the index for index in self.type.get_entity().get_indices(): for attr in index: if attr not in self.attributes: raise TypingException(self, "%s is part of an index and should be set in the constructor." % attr) inindex.add(attr) for (k, v) in self.__attributes.items(): attribute = self.type.get_entity().get_attribute(k) if attribute is None: raise TypingException(self, "no attribute %s on type %s" % (k, self.type.get_full_name())) if isinstance(attribute, RelationAttribute) and k not in inindex: self._indirect_attributes[k] = v else: self._direct_attributes[k] = v
def evaluate(self) -> None: """ Evaluate this statement in the given scope """ try: cls = self.namespace.get_type(self.entity) if not isinstance(cls, Entity): raise TypingException( self, "Implementation can only be define for an Entity, but %s is a %s" % (self.entity, cls) ) self.type.set_type(cls) self.copy_location(self.type) except TypeNotFoundException as e: e.set_statement(self) raise e
def set_expression(self, expression: ExpressionStatement) -> None: """ Set the expression that constrains the basetype. This expression should reference the value that will be assign to a variable of this type. This variable has the same name as the type. """ contains_var = False if hasattr(expression, "arguments"): # some sort of function call expression = Equals(expression, Literal(True)) for var in expression.requires(): if var == self.name or var == "self": contains_var = True if not contains_var: raise TypingException(self, "typedef expressions should reference the self variable") self.__expression = expression
def execute(self, requires: Dict[object, object], resolver: Resolver, queue: QueueScheduler) -> object: """ Evaluate this statement. """ var = self.base.execute(requires, resolver, queue) if isinstance(var, Unknown): return None if not isinstance(var, list): raise TypingException( self, "A for loop can only be applied to lists and relations") helper = requires[self] for loop_var in var: # generate a subscope/namespace for each loop helper.receive_result(loop_var, self.location) return None
def evaluate(self) -> None: """ Add this relation to the participating ends """ try: left = self.namespace.get_type(self.left[0]) except TypeNotFoundException as e: e.set_location(self.location) raise e if isinstance(left, Default): raise TypingException( self, "Can not define relation on a default constructor %s, use base type instead: %s " % (left.name, left.get_entity().get_full_name()), ) assert isinstance(left, Entity), "%s is not an entity" % left # Duplicate checking is in entity.normalize # Because here we don't know if all entities have been defined try: right = self.namespace.get_type(self.right[0]) except TypeNotFoundException as e: e.set_location(self.location) raise e if isinstance(right, Default): raise TypingException( self, "Can not define relation on a default constructor %s, use base type instead: %s " % (right.name, right.get_entity().get_full_name()), ) assert isinstance(right, Entity), "%s is not an entity" % right # Duplicate checking is in entity.normalize # Because here we don't know if all entities have been defined left_end: Optional[RelationAttribute] if self.left[1] is not None: left_end = RelationAttribute(right, left, str(self.left[1]), self.left[1].get_location()) left_end.target_annotations = self.annotations left_end.set_multiplicity(self.left[2]) left_end.comment = self.comment else: left_end = None right_end: Optional[RelationAttribute] if self.right[1] is not None: if right == left and str(self.left[1]) == str(self.right[1]): # relation is its own inverse right_end = left_end else: right_end = RelationAttribute(left, right, str(self.right[1]), self.right[1].get_location()) right_end.source_annotations = self.annotations right_end.set_multiplicity(self.right[2]) right_end.comment = self.comment else: right_end = None if left_end is not None and right_end is not None: left_end.end = right_end right_end.end = left_end
def evaluate(self) -> None: """ Add this relation to the participating ends """ try: left = self.namespace.get_type(self.left[0]) except TypeNotFoundException as e: e.set_location(self.location) raise e if isinstance(left, Default): raise TypingException( self, "Can not define relation on a default constructor %s, use base type instead: %s " % (left.name, left.get_entity().get_full_name()), ) assert isinstance(left, Entity), "%s is not an entity" % left if left.get_attribute_from_related(str(self.right[1])) is not None: raise DuplicateException( self, left.get_attribute_from_related(str(self.right[1])), ("Attribute name %s is already defined in %s, unable to define relationship" ) % (str(self.right[1]), left.name), ) try: right = self.namespace.get_type(self.right[0]) except TypeNotFoundException as e: e.set_location(self.location) raise e if isinstance(right, Default): raise TypingException( self, "Can not define relation on a default constructor %s, use base type instead: %s " % (right.name, right.get_entity().get_full_name()), ) assert isinstance(right, Entity), "%s is not an entity" % right if right.get_attribute_from_related(str(self.left[1])) is not None: raise DuplicateException( self, right.get_attribute_from_related(str(self.left[1])), ("Attribute name %s is already defined in %s, unable to define relationship" ) % (str(self.left[1]), right.name), ) left_end: Optional[RelationAttribute] if self.left[1] is not None: left_end = RelationAttribute(right, left, str(self.left[1]), self.left[1].get_location()) left_end.target_annotations = self.annotations left_end.set_multiplicity(self.left[2]) left_end.comment = self.comment else: left_end = None right_end: Optional[RelationAttribute] if self.right[1] is not None: if right == left and str(self.left[1]) == str(self.right[1]): # relation is its own inverse right_end = left_end else: right_end = RelationAttribute(left, right, str(self.right[1]), self.right[1].get_location()) right_end.source_annotations = self.annotations right_end.set_multiplicity(self.right[2]) right_end.comment = self.comment else: right_end = None if left_end is not None and right_end is not None: left_end.end = right_end right_end.end = left_end
def execute(self, requires: Dict[object, object], resolver: Resolver, queue: QueueScheduler): """ Evaluate this statement. """ LOGGER.log(LOG_LEVEL_TRACE, "executing constructor for %s at %s", self.class_type, self.location) # the type to construct type_class = self.type.get_entity() # kwargs kwarg_attrs: Dict[str, object] = {} for kwargs in self.wrapped_kwargs: for (k, v) in kwargs.execute(requires, resolver, queue): if k in self.attributes or k in kwarg_attrs: raise RuntimeException( self, "The attribute %s is set twice in the constructor call of %s." % (k, self.class_type)) attribute = self.type.get_entity().get_attribute(k) if attribute is None: raise TypingException( self, "no attribute %s on type %s" % (k, self.type.get_full_name())) kwarg_attrs[k] = v missing_attrs: List[str] = [ attr for attr in self.required_kwargs if attr not in kwarg_attrs ] if missing_attrs: raise IndexAttributeMissingInConstructorException( self, type_class, missing_attrs) # Schedule all direct attributes for direct execution. The kwarg keys and the direct_attributes keys are disjoint # because a RuntimeException is raised above when they are not. direct_attributes: Dict[str, object] = { k: v.execute(requires, resolver, queue) for (k, v) in self._direct_attributes.items() } direct_attributes.update(kwarg_attrs) # Override defaults with kwargs. The kwarg keys and the indirect_attributes keys are disjoint because a RuntimeException # is raised above when they are not. indirect_attributes: Dict[str, ExpressionStatement] = { k: v for k, v in self._indirect_attributes.items() if k not in kwarg_attrs } # check if the instance already exists in the index (if there is one) instances: List[Instance] = [] for index in type_class.get_indices(): params = [] for attr in index: params.append((attr, direct_attributes[attr])) obj: Optional[Instance] = type_class.lookup_index(params, self) if obj is not None: if obj.get_type().get_entity() != type_class: raise DuplicateException( self, obj, "Type found in index is not an exact match") instances.append(obj) graph: Optional[DataflowGraph] = resolver.dataflow_graph if len(instances) > 0: if graph is not None: graph.add_index_match( chain( [self.get_dataflow_node(graph)], (i.instance_node for i in instances if i.instance_node is not None), )) # ensure that instances are all the same objects first = instances[0] for i in instances[1:]: if i != first: raise Exception("Inconsistent indexes detected!") object_instance = first self.copy_location(object_instance) for k, v in direct_attributes.items(): object_instance.set_attribute(k, v, self.location) else: # create the instance object_instance = type_class.get_instance( direct_attributes, resolver, queue, self.location, self.get_dataflow_node(graph) if graph is not None else None) # deferred execution for indirect attributes for attributename, valueexpression in indirect_attributes.items(): var = object_instance.get_attribute(attributename) if var.is_multi(): # gradual only for multi # to preserve order on lists used in attributes # while allowing gradual execution on relations reqs = valueexpression.requires_emit_gradual( resolver, queue, GradualSetAttributeHelper(self, object_instance, attributename, var)) else: reqs = valueexpression.requires_emit(resolver, queue) SetAttributeHelper(queue, resolver, var, reqs, valueexpression, self, object_instance, attributename) # generate an implementation for stmt in type_class.get_sub_constructor(): stmt.emit(object_instance, queue) object_instance.trackers.append(queue.get_tracker()) return object_instance