コード例 #1
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()))
コード例 #2
0
def length(coll_expr):
    """
    Expression that will return the length of a collection.

    :param AbstractExpression coll_expr: The expression representing the
        collection to get from.
    """
    return BuiltinCallExpr("Length", LongType,
                           [construct(coll_expr, lambda t: t.is_collection())])
コード例 #3
0
def env_orphan(env_expr):
    """
    Expression that will create a lexical environment copy with no parent.

    :param AbstractExpression env_expr: Expression that will return a
        lexical environment.
    """
    return BuiltinCallExpr('AST_Envs.Orphan', LexicalEnvType,
                           [construct(env_expr, LexicalEnvType)], 'Orphan_Env')
コード例 #4
0
def get_value(logic_var):
    """
    Expression that'll extract the value out of a logic variable. The type is
    always the root grammar class.

    :param AbstractExpression logic_var: The logic var from which we want to
        extract the value.
    """
    return BuiltinCallExpr(
        "Eq_Node.Refs.GetL", T.root_node.env_el(),
        [construct(logic_var, LogicVarType)]
    )
コード例 #5
0
def env_group(env_array_expr):
    """
    Expression that will return a lexical environment that logically groups
    together multiple lexical environments from an array of lexical
    environments.

    :param AbstractExpression env_array_expr: Expression that will return
        an array of lexical environments. If this array is empty, the empty
        environment is returned.
    """
    return BuiltinCallExpr(
        'Group', LexicalEnvType,
        [construct(env_array_expr, LexicalEnvType.array_type())], 'Group_Env')
コード例 #6
0
    def construct(self):
        """
        Construct a resolved expression for this.

        :rtype: IfExpr
        """
        then = construct(self.then)
        else_then = construct(self.else_then)
        check_source_language(
            then.type.matches(else_then.type),
            "Mismatching types in If expression: {} and {}".format(
                then.type.name().camel,
                else_then.type.name().camel))
        rtype = then.type.unify(else_then.type)

        # If then/else_then have actually subtypes of the unified result type,
        # we need to perform a conversion for the Ada code generation.
        if then != rtype:
            then = BuiltinCallExpr(rtype.name(), rtype, [then])
        if else_then != rtype:
            else_then = BuiltinCallExpr(rtype.name(), rtype, [else_then])

        return If.Expr(construct(self.cond, BoolType), then, else_then, rtype)
コード例 #7
0
def solve(equation):
    """
    Expression that will call solve on an instance of EquationType,
    and return whether any solution was found or not. The solutions are not
    returned, instead, logic variables are bound to their values in the
    current solution.

    TODO: For the moment, since properties returning equations will
    reconstruct them everytime, there is no way to get the second solution
    if there is one. Also you cannot do that manually either since a
    property exposing equations cannot be public at the moment.

    :param AbstractExpression equation: The equation to solve.
    """
    return BuiltinCallExpr("Solve", BoolType,
                           [construct(equation, EquationType)])
コード例 #8
0
def is_visible_from(referenced_env, base_env):
    """
    Expression that will return whether an env's associated compilation unit is
    visible from another env's compilation unit.

    TODO: This is mainly exposed on envs because the CompilationUnit type is
    not exposed in the DSL yet. We might want to change that eventually if
    there are other compelling reasons to do it.

    :param AbstractExpression base_env: The environment from which we want
        to check visibility.
    :param AbstractExpression referenced_env: The environment referenced
        from base_env, for which we want to check visibility.
    """
    return BuiltinCallExpr('Is_Visible_From', BoolType, [
        construct(base_env, LexicalEnvType),
        construct(referenced_env, LexicalEnvType)
    ])
コード例 #9
0
    def construct(self):
        array_1 = construct(self.array_1)
        array_2 = construct(self.array_2)

        # TODO: We don't use the type param to construct because construct will
        # try to cast arrays to the base array type. Would be better if
        # construct handled that correctly.
        check_type(array_1.type, ArrayType)
        check_type(array_2.type, ArrayType)

        check_multiple([
            (array_1.type == array_2.type,
             "Got different array element types in concat: {} and {}".format(
                 array_1.type.element_type().name(),
                 array_2.type.element_type().name())),
        ])

        return BuiltinCallExpr("Concat", array_1.type, [array_1, array_2],
                               "Concat_Result")
コード例 #10
0
def collection_get(coll_expr, index_expr, or_null=True):
    """
    Expression that will get an element from a collection.

    :param AbstractExpression coll_expr: The expression representing the
        collection to get from.
    :param AbstractExpression index_expr: The expression representing the
        index of the element to get.
    :param bool or_null: If true, the expression will return null if the
        index is not valid for the collection. If False, it will raise an
        exception.
    """
    # index_expr yields a 0-based index and all the Get primitives expect
    # 0-based indexes, so there is no need to fiddle indexes here.
    index_expr = construct(index_expr, LongType)

    coll_expr = construct(coll_expr, lambda t: t.is_collection())
    or_null = construct(or_null)
    return BuiltinCallExpr('Get', coll_expr.type.element_type(),
                           [coll_expr, index_expr, or_null], 'Get_Result')
コード例 #11
0
    def construct(self):
        # 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),
                 "The property passed to bind must return a subtype "
                 "of {}".format(T.root_node.name().camel)),

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

        # 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.explicit_arguments
            check_multiple([
                (self.eq_prop.type == BoolType,
                 "Equality property must return boolean"),

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

                (len(args) == 1,
                 "Expected 1 argument for eq_prop, got {}".format(len(args))),

            ])
            check_source_language(
                args[0].type == self.eq_prop.struct,
                "Self and first argument should be of the same type"
            )

        cprop_uid = (self.conv_prop.uid if self.conv_prop else "Default")
        eprop_uid = (self.eq_prop.uid if self.eq_prop else "Default")
        pred_func = untyped_literal_expr(
            "Logic_Converter_{}'(Env => {})".format(
                cprop_uid, construct(Env).render_expr()
            )
            if self.conv_prop
            else "No_Logic_Converter_Default"
        )

        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

        lhs = construct_operand(self.from_expr)
        rhs = construct_operand(self.to_expr)

        return BuiltinCallExpr(
            "Bind_{}_{}.Create".format(cprop_uid, eprop_uid),
            EquationType,
            [lhs, rhs, pred_func],
            "Bind_Result"
        )
コード例 #12
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"
        )
コード例 #13
0
 def construct(self):
     env_exprs = [construct(e, LexicalEnvType) for e in self.env_exprs]
     return BuiltinCallExpr('Group', LexicalEnvType,
                            [ArrayExpr(env_exprs, LexicalEnvType)],
                            'Group_Env')