def construct_operand(op): from langkit.expressions import Cast, New expr = construct(op) check_source_language( expr.type == LogicVarType or expr.type.matches(T.root_node) or expr.type.matches(T.root_node.env_el()), "Operands to a logic bind operator should be either " "a logic variable or an ASTNode, got {}".format(expr.type) ) if expr.type.matches(T.root_node.env_el()): if expr.type is not T.root_node.env_el(): expr = Cast.Expr(expr, T.root_node.env_el()) elif expr.type.matches(T.root_node): # Cast the ast node type if necessary if expr.type is not T.root_node: expr = Cast.Expr(expr, T.root_node) # If the expression is a root node, implicitly construct an # env_element from it. expr = New.StructExpr(T.root_node.env_el(), { Name('El'): expr, Name('MD'): LiteralExpr('<>', None), Name('Parents_Bindings'): LiteralExpr('null', None) }) return expr
def construct(self): # Resolve the converter property, make sure it has an acceptable # signature and generate a functor for it. self.conv_prop = self._resolve_property("Bind's conv_prop", self.conv_prop, 1) # Left operand must be a logic variable. Make sure the resulting # equation will work on a clean logic variable. lhs = self._construct_logic_var(self.from_expr) # Second one can be either a logic variable or an entity (or an AST # node that is promoted to an entity). rhs = construct(self.to_expr) if rhs.type.matches(T.LogicVar): # The second operand is a logic variable: this is a Propagate or a # Unify equation depending on whether we have a conversion # property. # For this operand too, make sure it will work on a clean logic # variable. rhs = ResetLogicVar(rhs) return ( PropagateExpr(lhs, [rhs], self.conv_prop, abstract_expr=self) if self.conv_prop else UnifyExpr(lhs, rhs, abstract_expr=self)) else: # The second operand is a value: this is an Assign equation if rhs.type.matches(T.root_node): from langkit.expressions import make_as_entity rhs = make_as_entity(rhs) else: check_source_language( rhs.type.matches(T.root_node.entity) or rhs.type.matches(T.LogicVar), "Right operand must be either a logic variable or an" f" entity, got {rhs.type.dsl_name}") # Because of Ada OOP typing rules, for code generation to work # properly, make sure the type of `rhs` is the root node entity. if rhs.type is not T.root_node.entity: from langkit.expressions import Cast rhs = Cast.Expr(rhs, T.root_node.entity) return AssignExpr(lhs, rhs, self.conv_prop, abstract_expr=self)
def construct(self): from langkit.compile_context import get_context self.resolve_props() get_context().do_generate_logic_binder(self.conv_prop, self.eq_prop) # We have to wait for the construct pass for the following checks # because they rely on type information, which is not supposed to be # computed before this pass. if self.conv_prop: check_multiple([ (self.conv_prop.type.matches(T.root_node.entity), 'Bind property must return a subtype of {}'.format( T.root_node.entity.dsl_name)), (self.conv_prop.struct.matches(T.root_node), 'Bind property must belong to a subtype of {}'.format( T.root_node.dsl_name)), ]) DynamicVariable.check_call_bindings(self.conv_prop, "In Bind's conv_prop {prop}") # Those checks are run in construct, because we need the eq_prop to be # prepared already, which is not certain in do_prepare (order # dependent). if self.eq_prop: args = self.eq_prop.natural_arguments check_multiple([ (self.eq_prop.type == T.Bool, 'Equality property must return boolean'), (self.eq_prop.struct.matches(T.root_node), 'Equality property must belong to a subtype of {}'.format( T.root_node.dsl_name)), (len(args) == 1, 'Equality property: expected 1 argument, got {}'.format( len(args))), ]) other_type = args[0].type check_source_language( other_type.is_entity_type, "First arg of equality property should be an entity type") check_source_language( other_type.element_type == self.eq_prop.struct, "Self and first argument should be of the same type") DynamicVariable.check_call_bindings(self.eq_prop, "In Bind's eq_prop {prop}") cprop_uid = (self.conv_prop.uid if self.conv_prop else "Default") eprop_uid = (self.eq_prop.uid if self.eq_prop else "Default") if self.conv_prop: pred_func = Bind.Expr.dynamic_vars_to_holder( self.conv_prop, 'Logic_Converter_{}'.format(cprop_uid)) else: pred_func = untyped_literal_expr('No_Logic_Converter_Default') # Left operand must be a logic variable. Make sure the resulting # equation will work on a clean logic variable. lhs = ResetLogicVar(construct(self.from_expr, T.LogicVar)) # Second one can be either a logic variable or an entity (or an AST # node that is promoted to an entity). rhs = construct(self.to_expr) if rhs.type.matches(T.LogicVar): # For this operand too, make sure it will work on a clean logic # variable. rhs = ResetLogicVar(rhs) elif rhs.type.matches(T.root_node): from langkit.expressions import make_as_entity rhs = make_as_entity(rhs) else: check_source_language( rhs.type.matches(T.root_node.entity), 'Right operand must be either a logic variable or an entity,' ' got {}'.format(rhs.type.dsl_name)) # Because of Ada OOP typing rules, for code generation to work # properly, make sure the type of `rhs` is the root node entity. if (rhs.type.matches(T.root_node.entity) and rhs.type is not T.root_node.entity): from langkit.expressions import Cast rhs = Cast.Expr(rhs, T.root_node.entity) return Bind.Expr(self.conv_prop, self.eq_prop, cprop_uid, eprop_uid, lhs, rhs, pred_func, abstract_expr=self)