Example #1
0
def get_value(self, logic_var):
    """
    Extract the value out of a logic variable. The returned type is always the
    root entity type. If the variable is not defined, return a null entity.

    :param AbstractExpression logic_var: The logic var from which we want to
        extract the value.
    """
    from langkit.expressions import If

    PropertyDef.get()._gets_logic_var_value = True

    rtype = T.root_node.entity

    logic_var_expr = construct(logic_var, T.LogicVarType)
    logic_var_ref = logic_var_expr.create_result_var('Logic_Var_Value')

    return If.Expr(cond=CallExpr('Is_Logic_Var_Defined',
                                 'Eq_Node.Refs.Is_Defined', T.BoolType,
                                 [logic_var_expr]),
                   then=CallExpr('Eq_Solution', 'Eq_Node.Refs.Get_Value',
                                 rtype, [logic_var_ref]),
                   else_then=NullExpr(T.root_node.entity),
                   rtype=rtype,
                   abstract_expr=self)
Example #2
0
    def construct(self) -> ResolvedExpression:
        array_1 = construct(self.array_1)
        array_2 = construct(self.array_2)

        # Handle strings as a special case
        if array_1.type.is_string_type:
            check_source_language(
                array_2.type.is_string_type,
                "String type expected, got {}".format(array_2.type.dsl_name)
            )
            return CallExpr(
                "Concat_Result", "Concat_String", T.String, [array_1, array_2],
                abstract_expr=self,
            )

        def check_array(typ: CompiledType) -> None:
            check_source_language(
                typ.is_array_type,
                "Expected array type, got {}".format(typ.dsl_name)
            )

        check_array(array_1.type)
        check_array(array_2.type)

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

        return CallExpr('Concat_Result', 'Concat', array_1.type,
                        [array_1, array_2],
                        abstract_expr=self)
Example #3
0
def collection_get(self, collection, index, or_null):
    """
    Get the `index`\\ -th element from `collection`.

    Indexes are 0-based. As in Python, `index` can be negative, to retrieve
    elements in reverse order. For instance, ``expr.at(-1)`` will return the
    last element.

    :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 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, T.Int)

    coll_expr = construct(collection)
    as_entity = coll_expr.type.is_entity_type
    if as_entity:
        saved_coll_expr, coll_expr, entity_info = (
            coll_expr.destructure_entity()
        )

    check_source_language(
        coll_expr.type.is_collection,
        '.at prefix must be a collection: got {} instead'.format(
            coll_expr.type.dsl_name
        )
    )

    # We process null list nodes as empty lists, so insert a null check before
    # getting the collection item only if asked to raise an exception.
    if not or_null:
        if coll_expr.type.is_ast_node:
            coll_expr = NullCheckExpr(coll_expr)
        elif coll_expr.type.is_entity_type:
            coll_expr = NullCheckExpr(coll_expr, implicit_deref=True)

    coll_expr, element_type = canonicalize_list(coll_expr, to_root_list=True)

    or_null = construct(or_null)
    result = CallExpr('Get_Result', 'Get', element_type,
                      [coll_expr, index_expr, or_null])

    if as_entity:
        result = SequenceExpr(saved_coll_expr,
                              make_as_entity(result, entity_info))

    result.abstract_expr = self
    return result
Example #4
0
def make_to_iterator(
        prefix: ResolvedExpression,
        node_data: AbstractNodeData,
        args: List[Optional[ResolvedExpression]],
        abstract_expr: Optional[AbstractExpression] = None
) -> ResolvedExpression:
    """
    Turn an array into an iterator.

    :param prefix: Expression for the array to turn into an iterator.
    :param node_data: "to_iterator" property that this expression calls in the
        DSL.
    :param args: Arguments for the "to_iterator" property (i.e. an empty list).
    :param abstract_expr: See ResolvedExpression's constructor.
    :return: Resolved expression for the iterator creator.
    """
    assert not args
    elt_type = prefix.type.element_type

    # Make sure we generate code for this iterator type
    elt_type.create_iterator(used=True)

    return CallExpr(
        result_var_name="Iter",
        name=node_data.name,
        type=elt_type.iterator,
        exprs=[prefix, "Self.Unit.Context"],
        shadow_args=[node_data],
        abstract_expr=abstract_expr,
    )
Example #5
0
def parents_access_constructor(
        prefix: ResolvedExpression,
        node_data: AbstractNodeData,
        args: List[Optional[ResolvedExpression]],
        abstract_expr: Optional[AbstractExpression] = None
) -> ResolvedExpression:
    """
    Return an access to the "fields" parents, whether called on a node or an
    entity.

    .. todo::

        Implement rebindings shedding.
    """
    # We expect exactly one argument: with_self. If not provided, use the
    # default value.
    assert len(args) == 1
    with_self: ResolvedExpression = (args[0] or construct(
        node_data.natural_arguments[0].abstract_default_value))

    cons_args = [with_self]

    return build_field_access(
        prefix,
        'parents',
        cons_args,
        lambda: CallExpr(
            'Node_Parents',
            'Parents',
            T.root_node.array,
            [cast(ResolvedExpression, NullCheckExpr(prefix))] + cons_args,
            abstract_expr=abstract_expr,
        ),
        abstract_expr=abstract_expr,
    )
Example #6
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)
Example #7
0
def parents(self, node):
    """
    Return an array that contains the lexical parents (this node included).
    Nearer parents are first in the list.

    This works on both bare nodes and entities.

    .. todo::

        Implement rebindings shedding.
    """
    node_expr = construct(node)
    check_source_language(
        node_expr.type.is_ast_node or node_expr.type.is_entity_type,
        'Invalid prefix for "parents": got {} but AST node or entity'
        ' expected'.format(node_expr.type.dsl_name))

    if node_expr.type.is_entity_type:
        return FieldAccess.Expr(node_expr,
                                get_builtin_field('parents'), [],
                                implicit_deref=True,
                                abstract_expr=self)
    else:
        return CallExpr('Node_Parents',
                        'Parents',
                        T.root_node.array, [node_expr],
                        abstract_expr=self)
Example #8
0
 def construct(self):
     separator = construct(self.separator, T.String)
     strings = construct(self.strings, T.String.array)
     return CallExpr("Join_Result",
                     "Join_Strings",
                     T.String, [separator, strings],
                     abstract_expr=self)
Example #9
0
def unique(self, array):
    """
    Return a copy of `array` with duplicated elements removed.
    """
    from langkit.compile_context import ADA_BODY

    array_expr = construct(array)
    array_type = array_expr.type
    check_source_language(
        array_type.is_array_type,
        'Array expected but got {} instead'.format(array_type.dsl_name))
    element_type = array_type.element_type
    check_source_language(
        element_type.hashable,
        'Element type (here {}) must be hashable'.format(
            element_type.dsl_name))

    # Enable the generation of the function that does the actual work
    get_context().add_with_clause('Implementation', ADA_BODY,
                                  'Ada.Containers.Hashed_Sets')
    array_type.require_unique_function()

    return CallExpr('Unique_Array',
                    'Make_Unique',
                    array_type, [array_expr],
                    abstract_expr=self)
Example #10
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)
Example #11
0
def rebind_env(self, env, rebindings):
    """
    Return a new environment based on `env` to include the given `rebindings`.
    """
    return CallExpr('Rebound_Env', 'Rebind_Env', T.LexicalEnv,
                    [construct(env, T.LexicalEnv),
                     construct(rebindings, T.EnvRebindings)],
                    abstract_expr=self)
Example #12
0
def env_node(self, env):
    """
    Return the node associated to the `env` environment.

    :param AbstractExpression env: The source environment.
    """
    return CallExpr('Env_Node', 'AST_Envs.Env_Node', T.root_node,
                    [construct(env, T.LexicalEnv)],
                    abstract_expr=self)
Example #13
0
def length(self, collection):
    """
    Compute the length of `collection`.
    """
    return CallExpr('Len',
                    'Length',
                    T.LongType,
                    [construct(collection, lambda t: t.is_collection)],
                    abstract_expr=self)
Example #14
0
 def make_expr(cls, lhs, rhs, abstract_expr=None):
     if lhs.type.is_entity_type:
         return cls.make_expr_for_entities(lhs, rhs, abstract_expr)
     elif lhs.type.has_equivalent_function:
         return CallExpr('Is_Equal', 'Equivalent', T.Bool, [lhs, rhs],
                         abstract_expr=abstract_expr)
     else:
         return BasicExpr('Is_Equal', '{} = {}', T.Bool, [lhs, rhs],
                          abstract_expr=abstract_expr)
Example #15
0
    def make_expr_for_entities(lhs, rhs, abstract_expr=None):
        from langkit.expressions.structs import Cast

        if lhs.type != T.entity:
            lhs = Cast.Expr(lhs, T.entity)
        if rhs.type != T.entity:
            rhs = Cast.Expr(rhs, T.entity)
        return CallExpr('Is_Equiv', 'Equivalent', T.Bool, [lhs, rhs],
                        abstract_expr=abstract_expr)
Example #16
0
def concat_rebindings(self, lhs, rhs):
    """
    Combine rebindings from the `lhs` and `rhs` environment rebindings.
    """
    return CallExpr('Rebinding', 'AST_Envs.Combine',
                    T.EnvRebindings,
                    [construct(lhs, T.EnvRebindings),
                     construct(rhs, T.EnvRebindings)],
                    abstract_expr=self)
Example #17
0
def env_orphan(self, env):
    """
    Return a copy of the `env` lexical environment which has no parent.

    :param AbstractExpression env: Expression that will return a
        lexical environment.
    """
    return CallExpr('Orphan_Env', 'AST_Envs.Orphan', T.LexicalEnv,
                    [construct(env, T.LexicalEnv)],
                    abstract_expr=self)
Example #18
0
    def construct(self):
        # The equation constructor takes an Ada array as a paramater, not our
        # access to record: unwrap it.
        relation_array = untyped_literal_expr(
            'Relation_Array ({}.Items)',
            [construct(self.equation_array, T.EquationType.array)])

        return CallExpr('Logic_Boolean_Op',
                        'Logic_{}'.format(self.kind_name),
                        T.EquationType, [relation_array],
                        abstract_expr=self)
Example #19
0
def env_parent(self, env):
    """
    Return the parent of the `env` lexical environment.

    :param AbstractExpression env: The source environment.
    """
    return CallExpr(
        'Env_Parent', 'AST_Envs.Parent', T.LexicalEnv,
        [construct(env, T.LexicalEnv)],
        abstract_expr=self,
    )
Example #20
0
    def construct(self):
        # The equation constructor takes an Ada array as a parameter, not our
        # access to record: unwrap it.
        relation_array = untyped_literal_expr(
            'Relation_Array ({}.Items)',
            [construct(self.equation_array, T.Equation.array)])

        return CallExpr(
            "Logic_Boolean_Op",
            f"Solver.Create_{self.kind_name}",
            T.Equation,
            [relation_array, sloc_info_arg(self.location)],
            abstract_expr=self)
Example #21
0
def collection_get(self, collection, index, or_null):
    """
    Get the `index`\ -th element from `collection`.

    Indexes are 0-based. As in Python, `index` can be negative, to retrieve
    elements in reverse order. For instance, ``expr.at(-1)`` will return the
    last element.

    :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 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, T.LongType)

    coll_expr = construct(collection)
    as_entity = coll_expr.type.is_entity_type
    if as_entity:
        saved_coll_expr, coll_expr, entity_info = (
            coll_expr.destructure_entity())

    check_source_language(
        coll_expr.type.is_collection,
        '.at prefix must be a collection: got {} instead'.format(
            coll_expr.type.dsl_name))

    or_null = construct(or_null)
    result = CallExpr('Get_Result', 'Get', coll_expr.type.element_type,
                      [coll_expr, index_expr, or_null])

    if as_entity:
        result = SequenceExpr(saved_coll_expr,
                              make_as_entity(result, entity_info))

    result.abstract_expr = self
    return result
Example #22
0
def length(self, collection):
    """
    Compute the length of `collection`.
    """
    coll_expr = construct(collection)
    orig_type = coll_expr.type

    if coll_expr.type.is_entity_type:
        coll_expr = FieldAccessExpr(coll_expr,
                                    'Node',
                                    coll_expr.type.astnode,
                                    do_explicit_incref=False)
    check_source_language(
        coll_expr.type.is_collection,
        'Collection expected but got {} instead'.format(orig_type.dsl_name))

    return CallExpr('Len', 'Length', T.Int, [coll_expr], abstract_expr=self)
Example #23
0
def children(self, node):
    """
    Return `node`'s children in the AST.

    This works on both bare nodes and entities.
    """
    node_expr = construct(node)
    check_source_language(
        node_expr.type.is_ast_node or node_expr.type.is_entity_type,
        'Invalid prefix for "children": got {} but AST node or entity'
        ' expected'.format(node_expr.type.dsl_name))

    return build_field_access(
        self, node_expr, 'children', lambda node_expr, abstract_expr: CallExpr(
            'Node_Children',
            'Children',
            T.root_node.array, [node_expr],
            abstract_expr=self))
Example #24
0
def children(self, node):
    """
    Return `node`'s children in the AST.

    This works on both bare nodes and entities.
    """
    node_expr = construct(node)
    check_source_language(
        node_expr.type.is_ast_node or node_expr.type.is_entity_type,
        'Invalid prefix for "children": got {} but AST node or entity'
        ' expected'.format(node_expr.type.dsl_name)
    )

    if node_expr.type.is_entity_type:
        return FieldAccess.Expr(node_expr, get_builtin_field('children'),
                                [], implicit_deref=True, abstract_expr=self)
    else:
        return CallExpr('Node_Children', 'Children', T.root_node.array,
                        [node_expr], abstract_expr=self)
Example #25
0
def length(self: AbstractExpression,
           collection: AbstractExpression) -> ResolvedExpression:
    """
    Compute the length of `collection`.
    """
    coll_expr = construct(collection)
    orig_type = coll_expr.type

    # Automatically unwrap entities
    if coll_expr.type.is_entity_type:
        coll_expr = FieldAccessExpr(coll_expr, 'Node', coll_expr.type.astnode,
                                    do_explicit_incref=False)

    check_source_language(
        coll_expr.type.is_collection,
        'Collection expected but got {} instead'.format(orig_type.dsl_name))

    coll_expr, _ = canonicalize_list(coll_expr)
    return CallExpr('Len', 'Length', T.Int, [coll_expr], abstract_expr=self)
Example #26
0
def solve(self, equation):
    """
    Call ``solve`` on the given `equation` 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.
    """
    PropertyDef.get()._solves_equation = True
    return CallExpr('Solve_Success', 'Solve_Wrapper', T.BoolType,
                    [construct(equation, T.EquationType),
                     construct(Self, T.root_node)],
                    abstract_expr=self)
Example #27
0
def env_group(self, env_array, with_md=None):
    """
    Return a new lexical environment that logically groups together multiple
    environments. `env_array` must be an array that contains the environments
    to be grouped. If it is empty, the empty environment is returned.

    If provided, `with_md` must be a metadata structure: it will be made the
    default metadata for this lexical environment.

    :type env_array: AbstractExpression
    :type with_md: AbstractExpression
    """
    from langkit.expressions import No

    if not with_md:
        with_md = No(T.env_md)

    return CallExpr('Group_Env', 'Group', T.LexicalEnv,
                    [construct(env_array, T.LexicalEnv.array),
                     construct(with_md, T.env_md)],
                    abstract_expr=self)
Example #28
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 CallExpr('Concat_Result',
                        'Concat',
                        array_1.type, [array_1, array_2],
                        abstract_expr=self)
Example #29
0
    def construct(self):
        """
        Construct a resolved expression for this.

        :rtype: OrderingTest.Expr
        """
        lhs, rhs = construct(self.lhs), construct(self.rhs)
        check_source_language(
            lhs.type.is_long_type or
            lhs.type.is_big_integer_type or
            lhs.type.is_ast_node,
            'Comparisons only work on {}, {} or nodes not {}'
            .format(T.Int.dsl_name, T.BigInt.dsl_name,
                    lhs.type.dsl_name)
        )

        # If we are comparing two nodes, just use the dedicated helper
        if lhs.type.is_ast_node:
            check_source_language(
                rhs.type.is_ast_node,
                'A node can only be compared to another node (got {} and {})'
                .format(lhs.type.dsl_name, rhs.type.dsl_name)
            )
            relation = {self.LT: 'Less_Than',
                        self.LE: 'Less_Or_Equal',
                        self.GT: 'Greater_Than',
                        self.GE: 'Greater_Or_Equal'}[self.operator]
            return CallExpr('Node_Comp', 'Compare', T.Bool,
                            [lhs, rhs, relation], abstract_expr=self)

        # Otherwise, expect strict equality for both operands and use the
        # native comparison operator for code generation.
        check_source_language(
            lhs.type == rhs.type,
            'Comparisons require the same type for both operands'
            ' (got {} and {})'.format(lhs.type.dsl_name, rhs.type.dsl_name)
        )
        return OrderingTest.Expr(self.operator, lhs, rhs)
Example #30
0
    def construct(self):
        array_1 = construct(self.array_1)
        array_2 = construct(self.array_2)

        def check_array(typ):
            check_source_language(
                typ.is_array_type,
                "Expected array type, got {}".format(typ.dsl_name))

        check_array(array_1.type)
        check_array(array_2.type)

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

        return CallExpr('Concat_Result',
                        'Concat',
                        array_1.type, [array_1, array_2],
                        abstract_expr=self)