Пример #1
0
    def construct_common(self):
        """
        Construct the expressions commonly needed by collection expression
        subclasses, and return them as a tuple constituted of:

        1. The resolved collection expression.
        2. The resolved expression function passed to CollectionExpression's
           constructor.
        3. The element variable as a resolved expression.
        4. The index variable as a resolved expression.
        5. The inner scope for the iteration.

        :rtype: (ResolvedExpression, ResolvedExpression,
                 ResolvedExpression, ResolvedExpression,
                 langkit.expressions.base.LocalVars.Scope)
        """
        collection_expr = construct(
            self.collection, lambda t: t.is_collection(),
            'Map cannot iterate on {expr_type}, which is not a collection'
        )

        with PropertyDef.get_scope().new_child() as iter_scope:
            if self.index_var:
                PropertyDef.get_scope().add(self.index_var.local_var)
            self.element_var.set_type(collection_expr.type.element_type())

            return (collection_expr,
                    construct(self.expr),
                    construct(self.element_var),
                    construct(self.index_var) if self.index_var else None,
                    iter_scope)
Пример #2
0
    def __init__(self, referenced_unit, base_unit, abstract_expr=None):
        super(IsReferencedFrom, self).__init__(
            'Is_Referenced', 'Is_Referenced_From', T.BoolType,
            [construct(referenced_unit, T.AnalysisUnitType),
             construct(base_unit, T.AnalysisUnitType)],
            abstract_expr=self
        )

        PropertyDef.get().set_uses_envs()
Пример #3
0
    def __init__(self, referenced_env, base_env, abstract_expr=None):
        super().__init__(
            'Is_Visible', 'Is_Visible_From', T.Bool,
            [construct(referenced_env, T.LexicalEnv),
             construct(base_env, T.LexicalEnv)],
            abstract_expr=abstract_expr
        )

        PropertyDef.get().set_uses_envs()
Пример #4
0
    def construct_common(self):
        """
        Construct the expressions commonly needed by collection expression
        subclasses, and return them as a tuple constituted of:

        1. The resolved collection expression.
        2. The resolved expression function passed to CollectionExpression's
           constructor.
        3. If the collection is an AST list, the iteration variable, whose type
           is the root grammar type. None otherwise.
        4. The element variable as a resolved expression. In the case of an AST
           list collection, this is just 3. converted to the specific type.
        5. The index variable as a resolved expression.
        6. The inner scope for the iteration.

        :rtype: (ResolvedExpression,
                 ResolvedExpression,
                 ResolvedExpression|None,
                 ResolvedExpression,
                 ResolvedExpression,
                 langkit.expressions.base.LocalVars.Scope)
        """
        collection_expr = construct(
            self.collection, lambda t: t.is_collection(),
            'Map cannot iterate on {expr_type}, which is not a collection')
        self.element_var.set_type(collection_expr.type.element_type())

        current_scope = PropertyDef.get_scope()

        # If we are iterating over an AST list, then we get root grammar typed
        # values. We need to convert them to the more specific type to get the
        # rest of the expression machinery work. For this, create a new
        # variable.
        if collection_expr.type.is_list_type:
            self.list_element_var = AbstractVariable(
                names.Name("List_Item_{}".format(
                    next(CollectionExpression._counter))),
                type=get_context().root_grammar_class)
            self.element_var.add_to_scope(current_scope)

        with current_scope.new_child() as iter_scope:
            if self.index_var:
                PropertyDef.get_scope().add(self.index_var.local_var)

            return (collection_expr, construct(self.expr), (construct(
                self.list_element_var) if self.list_element_var else None),
                    construct(self.element_var),
                    construct(self.index_var) if self.index_var else None,
                    iter_scope)
Пример #5
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)
Пример #6
0
        def __init__(self, expr, dest_type, do_raise=False, result_var=None):
            """
            :type expr: ResolvedExpression
            :type dest_type: ASTNode
            :type do_raise: bool

            :param ResolvedExpr result_var: If provided, the cast will use it
                to store the cast result. Otherwise, a dedicated variable is
                created for this.
            """
            self.do_raise = do_raise
            self.expr = expr
            self.static_type = dest_type

            p = PropertyDef.get()
            self.expr_var = p.vars.create('Cast_Expr', self.expr.type)
            self.result_var = (result_var or
                               p.vars.create('Cast_Result', dest_type))
            assert self.result_var.type == dest_type, (
                'Cast temporaries must have exactly the cast type: {} expected'
                ' but got {} instead'.format(
                    dest_type.name().camel,
                    self.result_var.type.name().camel
                )
            )

            super(Cast.Expr, self).__init__()
Пример #7
0
    def construct(self):
        # Accept as a prefix all types that can have a null value
        expr = construct(
            self.expr,
            lambda cls: cls.null_allowed,
            'Invalid prefix type for .then: {expr_type}'
        )
        self.var_expr.set_type(expr.type)

        # Create a then-expr specific scope to restrict the span of the "then"
        # variable in the debugger.
        with PropertyDef.get_scope().new_child() as then_scope:
            then_scope.add(self.var_expr.local_var)
            then_expr = construct(self.then_expr)
            var_expr = construct(self.var_expr)
        then_expr = BindingScope(then_expr, [var_expr], scope=then_scope)

        # Affect default value to the fallback expression
        then_expr, default_expr = expr_or_null(
            then_expr, self.default_val,
            'Then expression', "function's return type"
        )

        return Then.Expr(expr, construct(self.var_expr), then_expr,
                         default_expr, then_scope)
Пример #8
0
        def __init__(self, element_var, index_var, collection, expr,
                     iter_scope, filter=None, concat=False, take_while=None):
            """
            :type element_var: VarExpr
            :type index_var: None|VarExpr
            :type collection: ResolvedExpression
            :type expr: ResolvedExpression
            :type iter_scope: langkit.expressions.base.LocalVars.Scope
            :type filter: ResolvedExpression
            :type concat: bool
            :type take_while: ResolvedExpression
            """
            self.take_while = take_while
            self.element_var = element_var
            self.index_var = index_var
            self.collection = collection
            self.expr = expr
            self.filter = filter
            self.concat = concat
            self.iter_scope = iter_scope

            element_type = (self.expr.type.element_type()
                            if self.concat else
                            self.expr.type)
            self.static_type = element_type.array_type()
            self.static_type.add_to_context()

            self.array_var = PropertyDef.get().vars.create_scopeless(
                'Map', self.type
            )
            iter_scope.parent.add(self.array_var)

            super(Map.Expr, self).__init__()
Пример #9
0
    def construct(self):
        # Accept as a prefix:
        #
        #   * any pointer, since it can be checked against "null";
        #   * any StructType, since structs are nullable;
        #   * any LexicalEnvType, which has EmptyEnv as a null value.
        expr = construct(
            self.expr, lambda cls:
            (cls.is_ptr or cls.is_struct_type or cls.is_lexical_env_type),
            'Invalid prefix type for .then: {expr_type}')
        self.var_expr.set_type(expr.type)

        # Create a then-expr specific scope to restrict the span of the "then"
        # variable in the debugger.
        with PropertyDef.get_scope().new_child() as then_scope:
            then_scope.add(self.var_expr.local_var)
            then_expr = construct(self.then_expr)
            var_expr = construct(self.var_expr)
        then_expr = BindingScope(then_expr, [var_expr], scope=then_scope)

        # Affect default value to the fallback expression
        if self.default_val is None:
            check_source_language(
                then_expr.type.null_allowed or then_expr.type is T.BoolType,
                "Then expression should have a default value provided,"
                " in cases where the provided function's return type (here"
                " {}) does not have a default null value".format(
                    then_expr.type.dsl_name))
            default_expr = construct(No(then_expr.type))
        else:
            default_expr = construct(self.default_val, then_expr.type)

        return Then.Expr(expr, construct(self.var_expr), then_expr,
                         default_expr, then_scope)
Пример #10
0
    def __init__(self, unit_expr):
        super(AnalysisUnitRoot, self).__init__()

        self.static_type = T.root_node
        self.unit_expr = unit_expr
        self.prefix_var = PropertyDef.get().vars.create(
            'Unit', self.unit_expr.type)
Пример #11
0
    def construct(self) -> ResolvedExpression:
        # Make sure this expression is allowed in the current expression
        # context.
        current_prop = PropertyDef.get()
        check_source_language(
            current_prop.lazy_field,
            "Dynamic lexical environment creation can only happen inside a"
            " lazy field initializer"
        )

        # Sanitize the resolver: make sure we have a property reference, then
        # make sure it has the expected signature.

        resolver = resolve_property(self.resolver).root_property
        resolver.require_untyped_wrapper()

        expected_rtype = T.inner_env_assoc.array
        check_source_language(
            resolver.type.matches(expected_rtype),
            '"resolver" must return an array of {} (got {})'
            .format(expected_rtype.element_type.dsl_name,
                    resolver.type.dsl_name)
        )
        check_source_language(not resolver.arguments,
                              '"resolver" cannot accept arguments')

        # Should this environment has a transitive parent?
        transitive_parent = construct(self.transitive_parent, T.Bool)

        return self.Expr(resolver, transitive_parent, abstract_expr=self)
Пример #12
0
        def __init__(self, expr, astnode, do_raise=False, result_var=None):
            """
            :type expr: ResolvedExpression
            :type astnode: ASTNode
            :type do_raise: bool

            :param ResolvedExpr result_var: If provided, the cast will use it
                to store the cast result. Otherwise, a dedicated variable is
                created for this.
            """
            self.do_raise = do_raise
            self.expr = expr
            self.static_type = astnode

            p = PropertyDef.get()
            self.expr_var = p.vars.create('Cast_Expr', self.expr.type)
            self.result_var = (result_var or
                               p.vars.create('Cast_Result', astnode))
            assert self.result_var.type == astnode, (
                'Cast temporaries must have exactly the cast type: {} expected'
                ' but got {} instead'.format(
                    astnode.name().camel,
                    self.result_var.type.name().camel
                )
            )

            super(Cast.Expr, self).__init__()
Пример #13
0
        def __init__(self, env_expr, key_expr, lookup_kind_expr, categories,
                     sequential_from=None,
                     only_first=False, abstract_expr=None):
            self.env_expr = env_expr
            self.key_expr = key_expr
            self.lookup_kind_expr = lookup_kind_expr
            self.sequential_from = sequential_from
            self.categories = categories

            self.static_type = (
                T.root_node.entity if only_first
                else T.root_node.entity.array
            )

            self.only_first = only_first
            super().__init__('Env_Get_Result', abstract_expr=abstract_expr)

            PropertyDef.get().set_uses_envs()
Пример #14
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)
Пример #15
0
        def __init__(self, expr, var_expr, then_expr, default_expr):
            self.expr = expr
            self.var_expr = var_expr
            self.then_expr = then_expr
            self.default_expr = default_expr
            self.static_type = self.then_expr.type
            self.result_var = PropertyDef.get().vars.create("Result_Var",
                                                            self.type)

            super(Then.Expr, self).__init__()
Пример #16
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)
            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)
Пример #17
0
    def __init__(self, env_expr, to_eval_expr):
        self.to_eval_expr = to_eval_expr
        self.env_expr = env_expr

        # Declare a variable that will hold the value of the
        # bound environment.
        self.static_type = self.to_eval_expr.type
        self.env_var = PropertyDef.get().vars.create("New_Env", LexicalEnvType)

        super(EnvBindExpr, self).__init__()
Пример #18
0
        def __init__(self, expr, var_expr, then_expr, default_expr):
            self.expr = expr
            self.var_expr = var_expr
            self.then_expr = then_expr
            self.default_expr = default_expr
            self.static_type = self.then_expr.type
            self.result_var = PropertyDef.get().vars.create(
                "Result_Var", self.type)

            super(Then.Expr, self).__init__()
Пример #19
0
    def __init__(self, domain, logic_var_expr):
        self.domain = domain
        ":type: ResolvedExpression"

        self.logic_var_expr = logic_var_expr
        ":type: ResolvedExpression"

        self.res_var = PropertyDef.get().vars.create("Var", EquationType)

        super(DomainExpr, self).__init__()
Пример #20
0
    def __init__(self, domain, logic_var_expr):
        self.domain = domain
        ":type: ResolvedExpression"

        self.logic_var_expr = logic_var_expr
        ":type: ResolvedExpression"

        self.res_var = PropertyDef.get().vars.create("Var", EquationType)

        super(DomainExpr, self).__init__()
Пример #21
0
    def has_ambient_env(self):
        """
        Return whether ambient environment value is available.

        If there is one, this is either the implicit environment argument for
        the current property, or the currently bound environment (using
        eval_in_env).

        :rtype: bool
        """
        return PropertyDef.get().has_implicit_env or self.is_bound
Пример #22
0
    def __init__(self, env_expr, to_eval_expr):
        self.to_eval_expr = to_eval_expr
        self.env_expr = env_expr

        # Declare a variable that will hold the value of the
        # bound environment.
        self.static_type = self.to_eval_expr.type
        self.env_var = PropertyDef.get().vars.create("New_Env",
                                                     LexicalEnvType)

        super(EnvBindExpr, self).__init__()
Пример #23
0
    def construct(self):
        """
        :rtype: StructExpr
        """
        if issubclass(self.struct_type, ASTNode):
            check_source_language(
                not self.struct_type.is_list_type,
                'List node synthetization is not supported for now'
            )
            check_source_language(
                PropertyDef.get().memoized,
                'Node synthetization can only happen inside a memoized'
                ' property'
            )

        # Make sure the provided set of fields matches the one the struct
        # needs.
        def error_if_not_empty(name_set, message):
            check_source_language(not name_set, ('{}: {}'.format(
                message, ', '.join(name for name in name_set)
            )))

        # Create a dict of field names to fields in the struct type
        required_fields = {
            f._name.lower: f
            for f in self.struct_type.get_abstract_fields()
            if isinstance(f, (Field, UserField))
            and not isinstance(f, BuiltinField)
        }

        error_if_not_empty(
            set(required_fields) - set(self.field_values.keys()),
            'Values are missing for {} fields'.format(
                self.struct_type.name().camel
            )
        )
        error_if_not_empty(
            set(self.field_values.keys()) - set(required_fields),
            'Extraneous fields for {}'.format(self.struct_type.name().camel)
        )

        # At this stage, we know that the user has only provided fields that
        # are valid for the struct type.
        provided_fields = {required_fields[name].name: construct(
            value, required_fields[name].type,
            'Wrong type for field {}: expected {{expected}}, '
            'got {{expr_type}}'.format(name)
        ) for name, value in self.field_values.items()}

        expr_cls = (New.NodeExpr
                    if self.struct_type.is_ast_node() else
                    New.StructExpr)
        return expr_cls(self.struct_type, provided_fields)
Пример #24
0
        def __init__(self, expr):
            """
            :type expr: ResolvedExpression
            """
            self.expr = expr

            self.expr.type.array_type().add_to_context()
            self.static_type = self.expr.type.array_type()

            self.array_var = PropertyDef.get().vars.create('Singleton',
                                                           self.type)

            super(CollectionSingleton.Expr, self).__init__()
Пример #25
0
        def __init__(self,
                     env_expr,
                     key_expr,
                     recursive_expr,
                     sequential=False,
                     sequential_from=None,
                     only_first=False,
                     abstract_expr=None):
            self.env_expr = env_expr
            self.key_expr = key_expr
            self.recursive_expr = recursive_expr
            self.sequential = sequential
            self.sequential_from = sequential_from

            self.static_type = (T.root_node.entity
                                if only_first else T.root_node.entity.array)

            self.only_first = only_first
            super(EnvGet.Expr, self).__init__('Env_Get_Result',
                                              abstract_expr=abstract_expr)

            PropertyDef.get().set_uses_envs()
Пример #26
0
        def __init__(self, expr):
            """
            :type expr: ResolvedExpression
            """
            self.expr = expr

            self.expr.type.array_type().add_to_context()
            self.static_type = self.expr.type.array_type()

            self.array_var = PropertyDef.get().vars.create(
                'Singleton', self.type)

            super(CollectionSingleton.Expr, self).__init__()
Пример #27
0
def make_as_entity(node_expr,
                   entity_info=None,
                   null_check=True,
                   abstract_expr=None):
    """
    Helper for as_entity. Takes a resolved expression instead of an abstract
    one.

    :param ResolvedExpression node_expr: The AST node expression to wrap as an
        entity.
    :param ResolvedExpression|None entity_info: Expression to use as the entity
        information. If provided, its type must be T.entity_info. Otherwise,
        the ambient entity info is used.
    """
    from langkit.expressions import If, IsNull, New

    entity_type = node_expr.type.entity

    # If we use the ambient entity info, make the current property an entity
    # one.
    if entity_info is None:
        p = PropertyDef.get()
        p.set_uses_entity_info()
        entity_info = construct(p.entity_info_arg)

    # Expression tree sharing is forbidden, so if we need to reference the
    # result of the input node expression multiple times, create a variable to
    # hold the input node.
    node_ref = (node_expr.create_result_var('Node_For_Entity')
                if null_check else node_expr)

    entity_expr = New.StructExpr(
        entity_type,
        {
            names.Name('El'): node_ref,
            names.Name('Info'): entity_info
        },
        result_var_name=names.Name.from_lower('as_entity'),
    )

    result = If.Expr(
        IsNull.construct_static(node_expr),
        NullExpr(entity_type),
        entity_expr,
        entity_type,
        abstract_expr=abstract_expr) if null_check else entity_expr

    result.abstract_expr = abstract_expr
    return result
Пример #28
0
        def __init__(self, cond, then, else_then, rtype):
            """
            :param ResolvedExpression cond: A boolean expression.
            :param ResolvedExpression then: If "cond" is evaluated to true,
                this part is returned.
            :param ResolvedExpression else_then: If "cond" is evaluated to
                false, this part is returned.
            :param langkit.compiled_types.CompiledType rtype: Type parameter.
                The type that is returned by then and else_then.
            """
            self.cond = cond
            self.then = then
            self.else_then = else_then
            self.static_type = rtype
            self.result_var = PropertyDef.get().vars.create('Result', rtype)

            super(If.Expr, self).__init__()
Пример #29
0
        def __init__(self, cond, then, else_then, rtype):
            """
            :param ResolvedExpression cond: A boolean expression.
            :param ResolvedExpression then: If "cond" is evaluated to true,
                this part is returned.
            :param ResolvedExpression else_then: If "cond" is evaluated to
                false, this part is returned.
            :param langkit.compiled_types.CompiledType rtype: Type parameter.
                The type that is returned by then and else_then.
            """
            self.cond = cond
            self.then = then
            self.else_then = else_then
            self.static_type = rtype
            self.result_var = PropertyDef.get().vars.create('Result', rtype)

            super(If.Expr, self).__init__()
Пример #30
0
        def __init__(self, receiver_expr, node_data, arguments,
                     implicit_deref=False):
            """
            :param ResolvedExpression receiver_expr: The receiver of the field
                access.

            :param langkit.compiled_types.AbstracNodeData node_data: The
                accessed property or field.

            :param list[ResolvedExpression] arguments: If non-empty, this field
                access will actually be a primitive call.

            :param bool implicit_deref: Whether the receiver is an env element,
                and we want to access a field or property of the stored node.
            """
            self.receiver_expr = receiver_expr
            self.node_data = node_data
            self.static_type = self.node_data.type
            self.arguments = arguments
            self.simple_field_access = False
            self.implicit_deref = implicit_deref

            # After EnvSpec.create_properties has been run, expressions in
            # environment specifications only allow field accesses. These are
            # not evaluated in a property context, so they cannot create local
            # variables.
            #
            # TODO: in this context, it would still be useful to emit a null
            # check so that we raise a special exception instead of a
            # Storage_Error.

            p = PropertyDef.get()

            if p:
                self.prefix_var = p.vars.create('Pfx', self.receiver_expr.type)
            else:
                self.simple_field_access = True

            # Create a variable for all field accesses in properties. This is
            # needed because the property will return an owning reference, so
            # we need it to be attached to the scope. In other cases, this can
            # make debugging easier.
            super(FieldAccess.Expr, self).__init__(
                'Field_Access_Result' if p else None
            )
Пример #31
0
        def __init__(self, kind, collection, expr, list_element_var,
                     element_var, index_var, iter_scope):
            """
            :param str kind: Kind for this quantifier expression. 'all' will
                check that all items in "collection" fullfill "expr" while
                'any' will check that at least one of them does.

            :param ResolvedExpression expr: Expression to evaluate for each
                item in "collection".

            :param ResolvedExpression collection: Collection on which this map
                operation works.

            :param ResolvedExpression expr: A boolean expression to evaluate on
                the collection's items.

            :param list_element_var: When the collection is an AST list,
                variable that holds the element we are currently processing
                during the iteration, typed as root grammar type.  None
                otherwise.
            :type: ResolvedExpression|None

            :param element_var: Variable to use in "expr".
            :type element_var: ResolvedExpression

            :param index_var: Index variable to use in "expr".
            :type index_var: None|ResolvedExpression

            :param iter_scope: Scope for local variables internal to the
                iteration.
            :type iter_scope: langkit.expressions.base.LocalVars.Scope
            """
            self.kind = kind
            self.collection = collection
            self.expr = expr
            self.list_element_var = list_element_var
            self.element_var = element_var
            self.index_var = index_var
            self.iter_scope = iter_scope
            self.result_var = PropertyDef.get().vars.create_scopeless(
                'Quantifier_Result', BoolType)
            iter_scope.parent.add(self.result_var)

            super(Quantifier.Expr, self).__init__()
Пример #32
0
def as_entity(self, node):
    """
    Wrap `node` into an entity. This uses environment rebindings from the
    context.
    """

    p = PropertyDef.get()
    check_source_language(p, "as_entity has to be used in a property")

    check_source_language(
        p._uses_entity_info is not False,
        'This property has been explicitly tagged as not using entity info, so'
        ' .as_entity is invalid here')

    # We want to keep original type of node, so no downcast
    node_expr = construct(node, T.root_node, downcast=False)

    ret = make_as_entity(node_expr, abstract_expr=self)
    ret.create_result_var('Ent')
    return ret
Пример #33
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)
Пример #34
0
        def __init__(self,
                     list_element_var,
                     element_var,
                     index_var,
                     collection,
                     expr,
                     iter_scope,
                     filter=None,
                     concat=False,
                     take_while=None):
            """
            :type list_element_var: VarExpr|None
            :type element_var: VarExpr
            :type index_var: None|VarExpr
            :type collection: ResolvedExpression
            :type expr: ResolvedExpression
            :type iter_scope: langkit.expressions.base.LocalVars.Scope
            :type filter: ResolvedExpression
            :type concat: bool
            :type take_while: ResolvedExpression
            """
            self.take_while = take_while
            self.list_element_var = list_element_var
            self.element_var = element_var
            self.index_var = index_var
            self.collection = collection
            self.expr = expr
            self.filter = filter
            self.concat = concat
            self.iter_scope = iter_scope

            element_type = (self.expr.type.element_type()
                            if self.concat else self.expr.type)
            self.static_type = element_type.array_type()
            self.static_type.add_to_context()

            self.array_var = PropertyDef.get().vars.create_scopeless(
                'Map', self.type)
            iter_scope.parent.add(self.array_var)

            super(Map.Expr, self).__init__()
Пример #35
0
        def __init__(self, receiver_expr, node_data, arguments):
            """
            :param ResolvedExpression receiver_expr: The receiver of the field
                access.

            :param langkit.compiled_types.AbstracNodeData node_data: The
                accessed property or field.

            :param list[ResolvedExpression] arguments: If non-empty, this field
                access will actually be a primitive call.
            """
            self.receiver_expr = receiver_expr
            self.node_data = node_data
            self.static_type = self.node_data.type
            self.arguments = arguments
            self.simple_field_access = False

            # After EnvSpec.create_properties has been run, expressions in
            # environment specifications only allow field accesses. These are
            # not evaluated in a property context, so they cannot create local
            # variables.
            #
            # TODO: in this context, it would still be useful to emit a null
            # check so that we raise a special exception instead of a
            # Storage_Error.

            p = PropertyDef.get()

            if p:
                self.prefix_var = p.vars.create('Pfx', self.receiver_expr.type)
            else:
                self.simple_field_access = True

            # Create a variable for all field accesses in properties. This is
            # needed because the property will return an owning reference, so
            # we need it to be attached to the scope. In other cases, this can
            # make debugging easier.
            super(FieldAccess.Expr, self).__init__(
                'Field_Access_Result' if p else None
            )
Пример #36
0
        def __init__(self, kind, collection, expr, element_var, index_var,
                     iter_scope):
            """
            :param str kind: Kind for this quantifier expression. 'all' will
                check that all items in "collection" fullfill "expr" while
                'any' will check that at least one of them does.

            :param ResolvedExpression expr: Expression to evaluate for each
                item in "collection".

            :param ResolvedExpression collection: Collection on which this map
                operation works.

            :param ResolvedExpression expr: A boolean expression to evaluate on
                the collection's items.

            :param element_var: Variable to use in "expr".
            :type element_var: ResolvedExpression

            :param index_var: Index variable to use in "expr".
            :type index_var: None|ResolvedExpression

            :param iter_scope: Scope for local variables internal to the
                iteration.
            :type iter_scope: langkit.expressions.base.LocalVars.Scope
            """
            self.kind = kind
            self.collection = collection
            self.expr = expr
            self.element_var = element_var
            self.index_var = index_var
            self.iter_scope = iter_scope
            self.result_var = PropertyDef.get().vars.create_scopeless(
                'Quantifier_Result', BoolType
            )
            iter_scope.parent.add(self.result_var)

            super(Quantifier.Expr, self).__init__()
Пример #37
0
    def construct_common(self):
        """
        Construct and return the expressions commonly needed by collection
        expression subclasses.

        :rtype: CollectionExpression.ConstructCommonResult
        """
        current_scope = PropertyDef.get_scope()

        # First, build the collection expression. From the result, we can
        # deduce the type of the element variable.
        collection_expr = construct(self.collection)
        with_entities = collection_expr.type.is_entity_type
        if with_entities:
            saved_entity_coll_expr, collection_expr, entity_info = (
                collection_expr.destructure_entity())
            collection_expr = SequenceExpr(saved_entity_coll_expr,
                                           collection_expr)

        check_source_language(
            collection_expr.type.is_collection,
            'Cannot iterate on {}, which is not a collection'.format(
                collection_expr.type.dsl_name))

        elt_type = collection_expr.type.element_type
        if with_entities:
            elt_type = elt_type.entity
        self.element_var.set_type(elt_type)

        # List of "element" iteration variables
        elt_vars = [construct(self.element_var)]

        # List of initializing expressions for them
        elt_var_inits = []

        if with_entities:
            entity_var = elt_vars[-1]
            node_var = AbstractVariable(names.Name('Bare') +
                                        self.element_var._name,
                                        type=elt_type.element_type)
            elt_var_inits.append(
                make_as_entity(construct(node_var), entity_info=entity_info))
            elt_vars.append(construct(node_var))

        # If we are iterating over an AST list, then we get root grammar typed
        # values. We need to convert them to the more specific type to get the
        # rest of the expression machinery work.
        if collection_expr.type.is_list_type:
            typed_elt_var = elt_vars[-1]
            untyped_elt_var = AbstractVariable(
                names.Name('Untyped') + self.element_var._name,
                type=get_context().root_grammar_class)
            # Initialize the former last variable with a cast from the new last
            # variable and push the new last variable.
            elt_var_inits.append(
                UncheckedCastExpr(construct(untyped_elt_var),
                                  typed_elt_var.type))
            elt_vars.append(construct(untyped_elt_var))

        # Only then we can build the inner expression
        with current_scope.new_child() as inner_scope:
            inner_expr = construct(self.expr)

        if with_entities:
            entity_var.abstract_var.create_local_variable(inner_scope)
        if collection_expr.type.is_list_type:
            typed_elt_var.abstract_var.create_local_variable(inner_scope)

        if self.index_var:
            self.index_var.add_to_scope(inner_scope)

        elt_var_inits.append(None)

        return self.ConstructCommonResult(
            collection_expr, funcy.lzip(elt_vars, elt_var_inits),
            construct(self.index_var) if self.index_var else None, inner_expr,
            inner_scope)
Пример #38
0
    def construct_common(self) -> CollectionExpression.ConstructCommonResult:
        """
        Construct and return the expressions commonly needed by collection
        expression subclasses.
        """
        assert self.element_var is not None

        current_scope = PropertyDef.get_scope()

        # Because of the discrepancy between the storage type in list nodes
        # (always root nodes) and the element type that user code deals with
        # (non-root list elements and/or entities), we may need to introduce
        # variables and initializing expressions. This is what the code below
        # does.

        # First, build the collection expression. From the result, we can
        # deduce the type of the user element variable.
        collection_expr = construct(self.collection)

        # If the collection is actually an entity, unwrap the bare list node
        # and save the entity info for later.
        with_entities = collection_expr.type.is_entity_type
        if with_entities:
            saved_entity_coll_expr, collection_expr, entity_info = (
                collection_expr.destructure_entity()
            )
            collection_expr = SequenceExpr(saved_entity_coll_expr,
                                           collection_expr)

        check_source_language(
            collection_expr.type.is_collection,
            'Cannot iterate on {}, which is not a collection'.format(
                collection_expr.type.dsl_name
            )
        )

        # Now that potential entity types are unwrapped, we can look for its
        # element type.
        elt_type = collection_expr.type.element_type
        if with_entities:
            elt_type = elt_type.entity
        self.element_var.set_type(elt_type)
        user_element_var = construct(self.element_var)

        # List of element variables, and the associated initialization
        # expressions (when applicable).
        #
        # Start with the only element variable that exists at this point: the
        # one that the user code for each iteration uses directly. When
        # relevant, each step in the code below creates a new variable N and
        # initialize variable N-1 from it.
        element_vars: List[InitializedVar] = [InitializedVar(user_element_var)]

        # Node lists contain bare nodes: if the user code deals with entities,
        # create a variable to hold a bare node and initialize the user
        # variable using it.
        if with_entities:
            entity_var = element_vars[-1]
            node_var = AbstractVariable(
                names.Name('Bare') + self.element_var._name,
                type=elt_type.element_type
            )
            entity_var.init_expr = make_as_entity(
                construct(node_var), entity_info=entity_info
            )
            element_vars.append(InitializedVar(construct(node_var)))

        # Node lists contain root nodes: if the user code deals with non-root
        # nodes, create a variable to hold the root bare node and initialize
        # the non-root node using it.
        if (
            collection_expr.type.is_list_type
            and not collection_expr.type.is_root_node
        ):
            typed_elt_var = element_vars[-1]
            untyped_elt_var = AbstractVariable(
                names.Name('Untyped') + self.element_var._name,
                type=get_context().root_grammar_class
            )
            typed_elt_var.init_expr = UncheckedCastExpr(
                construct(untyped_elt_var), typed_elt_var.var.type
            )
            element_vars.append(InitializedVar(construct(untyped_elt_var)))

        # Keep track of the ultimate "codegen" element variable. Unlike all
        # other iteration variable, it is the only one that will be defined by
        # the "for" loop in Ada (the other ones must be declared as regular
        # local variables).
        codegen_element_var = element_vars[-1].var

        # Create a scope to contain the code that runs during an iteration and
        # lower the iteration expression.
        with current_scope.new_child() as inner_scope:
            inner_expr = construct(self.expr)

        # Build the list of all iteration variables
        iter_vars = list(element_vars)
        index_var = None
        if self.index_var:
            index_var = construct(self.index_var)
            iter_vars.append(InitializedVar(index_var))

        # Create local variables for all iteration variables that need it
        for v in iter_vars:
            if v.var != codegen_element_var:
                v.var.abstract_var.create_local_variable(inner_scope)

        return self.ConstructCommonResult(
            collection_expr,
            codegen_element_var,
            user_element_var,
            index_var,
            iter_vars,
            inner_expr,
            inner_scope,
        )
Пример #39
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 _, v, _ in self.matchers:
            scope.add(v.local_var)

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

        # Yes, the assertion below is what we just checked above, but unlike
        # check_source_language, assert_type provides type information to
        # PyCharm's static analyzer.
        matched_type = assert_type(matched_expr.type, ASTNode)

        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 t, v, e in self.matchers:
            if t is not None:
                check_source_language(
                    t.matches(matched_expr.type),
                    'Cannot match {} (input type is {})'.format(
                        t.name().camel,
                        matched_expr.type.name().camel
                    )
                )
            else:
                # The default matcher (if any) matches the most general type,
                # which is the input type.
                v.set_type(matched_expr.type)
            constructed_matchers.append((construct(v), construct(e)))

        # * all possible input types must have at least one matcher. Also warn
        #   if some matchers are unreachable.
        self._check_match_coverage(matched_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 expression : "
                "{}, 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_expr,
                               match_var.type,
                               result_var=match_var)
            guard = Not.make_expr(
                Eq.make_expr(casted, LiteralExpr('null', 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 result
Пример #40
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])
        )
Пример #41
0
        def __init__(self, astnode, assocs):
            p = PropertyDef.get()
            self.result_var = p.vars.create('New_Node', astnode)

            super(New.NodeExpr, self).__init__(astnode, assocs)