예제 #1
0
    def functor_expr(type_name: str,
                     prop: PropertyDef,
                     arity: Optional[int] = None) -> LiteralExpr:
        """
        Return an expression to create a functor for ``Prop``.

        :param type_name: Name of the functor derived type.
        :param prop: Property called by the functor.
        :param arity: If the functor type handles variadic functions, this
            should be the number of entity arguments to pass to "prop".
        """
        assocs: List[Tuple[str, LiteralExpr]] = []

        if arity is not None:
            assocs.append(("N", IntegerLiteralExpr(arity)))

        assocs.extend([
            ("Ref_Count", IntegerLiteralExpr(1)),
            ("Cache_Set", LiteralExpr("False", None)),
            ("Cache_Key", LiteralExpr("<>", None)),
            ("Cache_Value", LiteralExpr("<>", None)),
        ])

        assocs.extend([(dynvar.argument_name, construct(dynvar))
                       for dynvar in prop.dynamic_vars])

        return aggregate_expr(type_name, assocs)
예제 #2
0
    def construct(self):
        """
        Construct a resolved expression for this.

        :rtype: IfExpr
        """
        def construct_op(op):
            return construct(
                op, lambda t: t in (T.BoolType, T.EquationType),
                "Operands of binary logic operator must be of "
                "boolean or equation type, got {expr_type}")

        lhs, rhs = map(construct_op, [self.lhs, self.rhs])

        check_source_language(
            lhs.type is rhs.type, "Left and right operands to binary logic "
            "operator should have the same type")

        if lhs.type is T.BoolType:
            # Boolean case
            if self.kind == self.AND:
                then = rhs
                else_then = LiteralExpr('False', T.BoolType)
            else:
                then = LiteralExpr('True', T.BoolType)
                else_then = rhs
            return If.Expr(lhs, then, else_then, T.BoolType)

        else:
            # Equation case
            kind_name = self.kind.capitalize()
            return CallExpr('{}_Pred'.format(kind_name),
                            'Logic_{}'.format(kind_name),
                            T.EquationType, [lhs, rhs],
                            abstract_expr=self)
예제 #3
0
    def construct(self):
        """
        Construct a resolved expression for this.

        :rtype: IfExpr
        """
        def construct_op(op):
            return construct(
                op, lambda t: t in (BoolType, EquationType),
                "Operands of binary logic operator must be of "
                "boolean or equation type, got {expr_type}")

        lhs, rhs = map(construct_op, [self.lhs, self.rhs])

        check_source_language(
            lhs.type is rhs.type, "Left and right operands to binary logic "
            "operator should have the same type")

        if lhs.type is BoolType:
            # Boolean case
            if self.kind == self.AND:
                then = rhs
                else_then = LiteralExpr('False', BoolType)
            else:
                then = LiteralExpr('True', BoolType)
                else_then = rhs
            return If.Expr(lhs, then, else_then, BoolType)
        else:
            # Equation case
            return BuiltinCallExpr(
                names.Name("Logic") + names.Name.from_lower(self.kind),
                EquationType, [lhs, rhs],
                '{}_Pred'.format(self.kind.capitalize()))
예제 #4
0
        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
예제 #5
0
 def construct(self):
     env_exprs = [construct(e, T.LexicalEnvType) for e in self.env_exprs]
     array_arg = LiteralExpr(array_aggr(['{}' for _ in env_exprs]),
                             no_compiled_type, env_exprs)
     return CallExpr('Group_Env',
                     'Group',
                     T.LexicalEnvType, [array_arg],
                     abstract_expr=self)
예제 #6
0
def untyped_literal_expr(expr_str):
    """
    Create an untyped LiteralExpr instance for "expr_str" and return it.

    This is a helper for code that generates expressions which have no
    corresponding CompiledType in Langkit. Materializing such values in
    ResolvedExpression trees can be useful anayway to leverage BuiltinCallExpr
    code generation capabilities, in particular temporary creation for the
    result. We can do this because BuiltinCallExpr does not need its operands'
    types to be valid.

    :param str expr_str: The generated code for this literal expression.
    :rtype: LiteralExpr
    """
    return LiteralExpr(expr_str, None)
예제 #7
0
    def construct(self):
        # Add var_expr to the scope for this Then expression
        PropertyDef.get_scope().add(self.var_expr.local_var)

        # Accept as a prefix:
        # * any pointer, since it can be checked against "null";
        # * any Struct, since its "Is_Null" field can be checked.
        expr = construct(self.expr,
                         lambda cls: cls.is_ptr or issubclass(cls, Struct))
        self.var_expr.set_type(expr.type)

        then_expr = construct(self.then_expr)

        # Affect default value to the fallback expression. For the moment,
        # only booleans and structs are handled.
        if self.default_val is None:
            if then_expr.type.matches(BoolType):
                default_expr = construct(False)
            elif issubclass(then_expr.type, Struct):
                default_expr = construct(
                    No(
                        # Because we're doing issubclass instead of isinstance,
                        # PyCharm do not understand that then_exp.type is a Struct,
                        # so the following is necessary not to have warnings.
                        assert_type(then_expr.type, Struct)))
            elif then_expr.type.matches(LexicalEnvType):
                default_expr = construct(EmptyEnv)
            elif then_expr.type.matches(Symbol):
                default_expr = LiteralExpr(Symbol.nullexpr(), Symbol)
            else:
                # The following is not actually used but PyCharm's typer
                # requires it.
                default_expr = None

                check_source_language(
                    False,
                    "Then expression should have a default value provided, "
                    "in cases where the provided function's return type is "
                    "not Bool, here {}".format(then_expr.type.name().camel))
        else:
            default_expr = construct(self.default_val, then_expr.type)

        return Then.Expr(expr, construct(self.var_expr), then_expr,
                         default_expr)
예제 #8
0
    def construct(self):
        """
        Construct a resolved expression for this.

        :rtype: ResolvedExpression
        """
        # Add the variables created for this expression to the current scope
        scope = PropertyDef.get_scope()
        for _, var, _ in self.matchers:
            scope.add(var.local_var)

        matched_expr = construct(self.matched_expr)
        check_source_language(issubclass(matched_expr.type, ASTNode)
                              or matched_expr.type.is_env_element_type,
                              'Match expressions can only work on AST nodes '
                              'or env elements')

        # Create a local variable so that in the generated code, we don't have
        # to re-compute the prefix for each type check.
        matched_abstract_var = AbstractVariable(
            names.Name('Match_Prefix'),
            type=matched_expr.type,
            create_local=True
        )
        PropertyDef.get_scope().add(matched_abstract_var.local_var)
        matched_var = construct(matched_abstract_var)

        constructed_matchers = []

        # Check (i.e. raise an error if no true) the set of matchers is valid:

        # * all matchers must target allowed types, i.e. input type subclasses;
        for typ, var, expr in self.matchers:
            if typ is not None:
                check_source_language(
                    typ.matches(matched_expr.type),
                    'Cannot match {} (input type is {})'.format(
                        typ.name().camel,
                        matched_expr.type.name().camel
                    )
                )
            else:
                # The default matcher (if any) matches the most general type,
                # which is the input type.
                var.set_type(matched_expr.type)
            constructed_matchers.append((construct(var), construct(expr)))

        # * all possible input types must have at least one matcher. Also warn
        #   if some matchers are unreachable.
        self._check_match_coverage(matched_expr.type)

        # Compute the return type as the unification of all branches
        _, expr = constructed_matchers[-1]
        rtype = expr.type
        for _, expr in constructed_matchers:
            check_source_language(
                expr.type.matches(rtype), "Wrong type for match result"
                " expression: got {} but expected {} or sub/supertype".format(
                    expr.type.name().camel, rtype.name().camel
                )
            )
            rtype = expr.type.unify(rtype)

        # This is the expression execution will reach if we have a bug in our
        # code (i.e. if matchers did not cover all cases).
        result = UnreachableExpr(rtype)

        # Wrap this "failing" expression with all the cases to match in the
        # appropriate order, so that in the end the first matchers are tested
        # first.
        for match_var, expr in reversed(constructed_matchers):
            casted = Cast.Expr(matched_var,
                               match_var.type,
                               result_var=match_var)
            guard = Not.make_expr(
                Eq.make_expr(
                    casted, LiteralExpr(casted.type.nullexpr(), casted.type)
                )
            )
            if expr.type != rtype:
                # We already checked that type matches, so only way this is
                # true is if expr.type is an ASTNode type derived from
                # rtype. In that case, we need an explicity upcast.
                expr = Cast.Expr(expr, rtype)

            result = If.Expr(guard, expr, result, rtype)

        return Let.Expr(
            [matched_var],
            [matched_expr],
            BindingScope(result,
                         [construct(var) for _, var, _ in self.matchers])
        )
예제 #9
0
 def construct_static(cexpr):
     return Eq.make_expr(
         cexpr, LiteralExpr(cexpr.type.nullexpr(), cexpr.type)
     )
예제 #10
0
 def construct(self):
     return LiteralExpr("False_Rel", type=EquationType,
                        result_var_name="Logic_False")
예제 #11
0
    def construct(self):
        check_multiple([
            (isinstance(self.pred_property, PropertyDef),
             "Needs a property reference, got {}".format(self.pred_property)),

            (self.pred_property.type.matches(BoolType),
             "The property passed to predicate must return a boolean, "
             "got {}".format(self.pred_property.type.name().camel)),

            (self.pred_property.struct.matches(T.root_node),
             "The property passed to bind must belong to a subtype "
             "of {}".format(T.root_node.name().camel))
        ])

        exprs = [construct(e) for e in self.exprs]

        prop_types = [self.pred_property.struct] + [
            a.type for a in self.pred_property.explicit_arguments
        ]

        # Separate logic variable expressions from extra argument expressions
        logic_var_exprs, closure_exprs = funcy.split_by(
            lambda e: e.type == LogicVarType, exprs
        )

        check_source_language(
            len(logic_var_exprs) > 0, "Predicate instantiation should have at "
            "least one logic variable expression"
        )

        check_source_language(
            all(e.type != LogicVarType for e in closure_exprs), "Logic "
            "variable expressions should be grouped at the beginning, and "
            "should not appear after non logic variable expressions"
        )

        for i, (expr, arg_type) in enumerate(zip(exprs, prop_types)):
            if expr.type == LogicVarType:
                check_source_language(
                    arg_type.matches(T.root_node), "Argument #{} of predicate "
                    "is a logic variable, the corresponding property formal "
                    "has type {}, but should be a descendent of {}".format(
                        i, arg_type.name().camel, T.root_node.name().camel
                    )
                )
            else:
                check_source_language(
                    expr.type.matches(arg_type), "Argument #{} of predicate "
                    "has type {}, should be {}".format(
                        i, expr.type.name().camel, arg_type.name().camel
                    )
                )

        pred_id = self.pred_property.do_generate_logic_predicate(*[
            e.type for e in closure_exprs
        ])

        closure_exprs.append(construct(Env))

        # Append the debug image for the predicate
        closure_exprs.append(LiteralExpr('"{}.{}"'.format(
            self.pred_property.name.camel_with_underscores,
            self.pred_property.struct.name().camel_with_underscores
        ), type=None))

        logic_var_exprs.append(
            BasicExpr("{}_Predicate_Caller'({})".format(
                pred_id, ", ".join(
                    ["{}" for _ in range(len(closure_exprs) - 2)]
                    + ["Env => {}, "
                       "Dbg_Img => (if Debug then new String'({})"
                       "            else null)"]
                )
            ), type=None, operands=closure_exprs)
        )

        return BuiltinCallExpr(
            "{}_Pred.Create".format(pred_id), EquationType, logic_var_exprs,
            result_var_name="Pred"
        )