コード例 #1
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)
コード例 #2
0
 def render_private_ada_constant(self):
     all_cats = get_context().ref_cats
     return '({})'.format(', '.join(sorted(
         '{} => {}'.format(name.camel_with_underscores,
                           name in self.cats)
         for name in all_cats
     )))
コード例 #3
0
ファイル: envs.py プロジェクト: eliericha/langkit
    def check(self):
        """
        Check that the resolver property is conforming.
        """
        ctx = get_context()
        ctx.has_ref_env = True

        if self.category:
            check_source_language(
                self.category != 'nocat',
                'Nocat is not a valid name for a referenced env category')

            self.category = names.Name.from_lower(self.category)
            ctx.ref_cats.add(self.category)

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

        check_source_language(
            self.resolver.type.matches(T.LexicalEnv),
            'Referenced environment resolver must return a lexical'
            ' environment (not {})'.format(self.resolver.type.dsl_name))
        check_source_language(
            not self.resolver.natural_arguments,
            'Referenced environment resolver must take no argument')
        check_source_language(
            not self.resolver.dynamic_vars,
            'Referenced environment resolver must have no dynamically bound'
            ' variable')
コード例 #4
0
ファイル: envs.py プロジェクト: briot/langkit
    def check(self):
        ctx = get_context()
        self.resolver = resolve_property(self.resolver)
        with self.mappings_prop.diagnostic_context:
            mapping_type = self.mappings_prop.type
            if mapping_type.matches(T.env_assoc):
                ctx.has_env_assoc = True
            elif mapping_type.matches(T.env_assoc.array):
                ctx.has_env_assoc = True
                ctx.has_env_assoc_array = True
            else:
                check_source_language(
                    False,
                    'The bindings expression in environment specification must'
                    ' must be either an env_assoc or an array of env_assocs:'
                    ' got {} instead'.format(mapping_type.dsl_name)
                )

            if self.resolver:
                # Ask for the creation of untyped wrappers for all
                # properties used as entity resolvers.
                self.resolver.require_untyped_wrapper()

                check_source_language(
                    self.resolver.type.matches(T.entity),
                    'Entity resolver properties must return entities'
                    ' (got {})'.format(self.resolver.type.dsl_name)
                )
                check_source_language(
                    not self.resolver.dynamic_vars,
                    'Entity resolver properties must have no dynamically'
                    ' bound variable'
                )
コード例 #5
0
ファイル: envs.py プロジェクト: briot/langkit
    def check(self):
        """
        Check that the resolver property is conforming.
        """
        get_context().has_ref_env = True

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

        check_source_language(
            self.resolver.type.matches(T.LexicalEnvType),
            'Referenced environment resolver must return a lexical'
            ' environment (not {})'.format(
                self.resolver.type.dsl_name
            )
        )
        check_source_language(
            not self.resolver.natural_arguments,
            'Referenced environment resolver must take no argument'
        )
        check_source_language(
            not self.resolver.dynamic_vars,
            'Referenced environment resolver must have no dynamically bound'
            ' variable'
        )
コード例 #6
0
ファイル: envs.py プロジェクト: geoffreycopin/langkit
    def construct(self):
        env_expr = construct(self.env, T.LexicalEnv)

        sym_expr = construct(self.symbol)

        if sym_expr.type.is_ast_node:
            check_source_language(
                sym_expr.type.is_token_node,
                'AST node type for key (here: {}) must be a token node'.format(
                    sym_expr.type.dsl_name))
            sym_expr = GetSymbol.construct_static(sym_expr)

        check_source_language(
            sym_expr.type == T.Symbol,
            'Invalid key type: {}'.format(sym_expr.type.dsl_name))

        from_expr = (construct(self.sequential_from, T.root_node)
                     if self.sequential_from is not None else None)

        lookup_kind_expr = construct(self.lookup_kind, T.LookupKind)

        ctx = get_context()

        if self.categories:
            check_source_language(isinstance(self.categories, dict),
                                  "Categories should be a dict")

            self.categories = {
                cat.lower(): val
                for cat, val in self.categories.items()
            }

            check_source_language(
                self.categories.get('others', None)
                or all(self.categories.get(cat, None) for cat in ctx.ref_cats),
                'Categories for env.get do not contain mappings for all'
                ' categories')

            check_source_language(
                all(isinstance(val, bool) for val in self.categories.values()),
                "Categories values should be bool")

            self.categories = {
                names.Name.from_lower(cat).camel_with_underscores
                if cat != 'others' else 'others': val
                for cat, val in self.categories.items()
            }

        return EnvGet.Expr(env_expr,
                           sym_expr,
                           lookup_kind_expr,
                           from_expr,
                           self.only_first,
                           abstract_expr=self,
                           categories=self.categories)
コード例 #7
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)
コード例 #8
0
def as_array(list_expr):
    """
    Turn an AST list node into an array for the same elements.

    This is basically a shortcut to a map operation with the identity function.

    :param AbstractExpression list_expr: The AST list to convert.
    :rtype: ResolvedExpression
    """
    abstract_result = list_expr.map(lambda x: x)
    abstract_result.prepare()
    result = construct(abstract_result)
    root_list_type = get_context().root_grammar_class.list_type()
    check_source_language(issubclass(result.collection.type, root_list_type),
                          '.as_array input must be an AST list')
    return result
コード例 #9
0
def canonicalize_list(coll_expr, to_root_list=False):
    """
    If `coll_expr` returns a bare node, return an expression that converts it
    to the generic list type (if to_root_list=False) or the root list type (if
    to_root_list=True). Also return the element type for this collection.

    :type coll_expr: ResolvedExpression
    :rtype: (ResolvedExpression, CompiledType)
    """
    element_type = coll_expr.type.element_type
    if coll_expr.type.is_ast_node:
        # Compute the result's type according to to_root_list
        if to_root_list:
            dest_type = coll_expr.type
            while not dest_type.is_root_list_type:
                dest_type = dest_type.base
        else:
            dest_type = get_context().generic_list_type
    return (coll_expr, element_type)
コード例 #10
0
    def construct(self):
        check_source_language(isinstance(self.default, bool),
                              'Invalid categories default')

        all_cats = get_context().ref_cats
        cats = set(all_cats) if self.default else set()

        # Compute the list of requested categories
        for key, value in self.cat_map.items():
            name = names.Name.from_lower(key)
            check_source_language(name in all_cats,
                                  'Invalid category: {}'.format(key))
            check_source_language(isinstance(value, bool),
                                  'Invalid status for {}'.format(key))
            if value:
                cats.add(name)
            else:
                cats.discard(name)

        return self.Expr(cats, abstract_expr=self)
コード例 #11
0
    def from_parser(cls, parser):
        """
        Create a token unparser out of a parser, assumed to parse a token.
        If ``parser`` is None, return None.

        :param _Token|None parser: Token parser to analyze.
        :rtype: TokenUnparser|None
        """
        if parser is None:
            return None

        assert isinstance(parser, _Token)
        token = parser.val
        match_text = parser.match_text or None

        unparsers = get_context().unparsers
        key = (token, match_text)
        try:
            return unparsers.token_unparsers[key]
        except KeyError:
            result = cls(token, match_text)
            unparsers.token_unparsers[key] = result
            return result
コード例 #12
0
    def construct(self):
        env_expr = construct(self.env, T.LexicalEnv)

        sym_expr = construct(self.symbol)

        if sym_expr.type.is_ast_node:
            check_source_language(
                sym_expr.type.is_token_node,
                'AST node type for key (here: {}) must be a token node'.format(
                    sym_expr.type.dsl_name
                )
            )
            sym_expr = GetSymbol.construct_static(sym_expr)

        check_source_language(
            sym_expr.type == T.Symbol,
            'Invalid key type: {}'.format(sym_expr.type.dsl_name)
        )

        from_expr = (construct(self.sequential_from, T.root_node)
                     if self.sequential_from is not None else None)

        lookup_kind_expr = construct(self.lookup_kind, T.LookupKind)

        # If no category is provided, consider they are all requested
        if self.categories is None:
            categories = RefCategories.Expr(get_context().ref_cats)
        else:
            categories = construct(
                self.categories,
                T.RefCategories,
                'Invalid categories: {expected} expected but got {expr_type}'
            )

        return EnvGet.Expr(env_expr, sym_expr, lookup_kind_expr, categories,
                           from_expr, self.only_first,
                           abstract_expr=self)
コード例 #13
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)
コード例 #14
0
ファイル: collections.py プロジェクト: pmderodat/langkit
    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,
        )
コード例 #15
0
        def field_access_expr(self):
            """
            Return the code for the expression that evaluates the actual field
            access.

            :rtype: str
            """
            prefix = self.prefix

            if self.implicit_deref:
                prefix = '{}.Node'.format(prefix)

            # If we're calling a property, then pass the arguments
            if isinstance(self.node_data, PropertyDef):

                # Create a collection of name => expression for parameters.
                # First argument is the node itself.
                args = [
                    ('Node', prefix)
                ] + [(formal.name, actual.render_expr())
                     for actual, formal in zip(
                         self.arguments, self.node_data.natural_arguments)
                     if actual is not None]

                # If the property has dynamically bound variables, then pass
                # them along.
                for formal, actual in zip(self.node_data.dynamic_vars,
                                          self.dynamic_vars):
                    args.append((formal.argument_name, actual.render_expr()))

                # If the called property uses entity information, pass it
                # along.
                if self.node_data.uses_entity_info:
                    einfo_expr = self.entity_info_expr
                    if einfo_expr:
                        args.append(
                            (str(PropertyDef.entity_info_name), einfo_expr))

                # Use a fully qualified name for properties so that they don't
                # clash with local variables.
                call_name = "{}.Implementation.{}".format(
                    get_context().ada_api_settings.lib_name,
                    str(self.node_data.name))

                # Build the call
                ret = '{} ({})'.format(
                    call_name, ', '.join('{} => {}'.format(name, value)
                                         for name, value in args))

            else:
                # If we reach this point, we know that we are accessing a
                # struct field: make sure we return the public API type,
                # which may be different from the type thas is stored in the
                # struct.
                ret = self.node_data.type.extract_from_storage_expr(
                    prefix, '{}.{}'.format(prefix, self.node_data.name))

            if self.wrap_result_in_entity:
                ret = '{} (Node => {}, Info => {})'.format(
                    self.type.constructor_name, ret, self.entity_info_expr)

            return ret
コード例 #16
0
 def _render_pre(self):
     return render('properties/match_ada',
                   expr=self,
                   kind_set=get_context().astnode_kind_set)
コード例 #17
0
ファイル: structs.py プロジェクト: geoffreycopin/langkit
        def field_access_expr(self):
            """
            Return the code for the expression that evaluates the actual field
            access.

            :rtype: str
            """
            prefix = self.prefix
            node_data_struct = self.node_data.struct

            if self.implicit_deref:
                prefix = '{}.Node'.format(prefix)

            # If this is a node field/property, we must pass the precise type
            # it expects for "Self".
            if node_data_struct.is_ast_node:
                prefix = node_data_struct.internal_conversion(
                    self.receiver_expr.type, prefix)

            # If we're calling a property, then pass the arguments
            if isinstance(self.node_data, PropertyDef):

                # TODO: For the moment, the first argument is named Node for
                # properties on node & entity types, and Self for other
                # properties. For the moment, properties that are not on nodes
                # are necessarily built-in properties, so the inconsistency is
                # not too bothering, but long-term we want to rename *every*
                # self argument to Self.
                rec_type = self.receiver_expr.type
                first_arg_name = ('Node' if rec_type.is_ast_node
                                  or rec_type.is_entity_type else 'Self')

                # Create a collection of name => expression for parameters.
                # First argument is the node itself.
                args = [
                    (first_arg_name, prefix)
                ] + [(formal.name, actual.render_expr())
                     for actual, formal in zip(
                         self.arguments, self.node_data.natural_arguments)
                     if actual is not None]

                # If the property has dynamically bound variables, then pass
                # them along.
                for formal, actual in zip(self.node_data.dynamic_vars,
                                          self.dynamic_vars):
                    args.append((formal.argument_name, actual.render_expr()))

                # If the called property uses entity information, pass it
                # along.
                if self.node_data.uses_entity_info:
                    einfo_expr = self.entity_info_expr
                    if einfo_expr:
                        args.append(
                            (str(PropertyDef.entity_info_name), einfo_expr))

                # Use a fully qualified name for properties so that they don't
                # clash with local variables.
                call_name = "{}.Implementation.{}".format(
                    get_context().ada_api_settings.lib_name,
                    str(self.node_data.internal_name))

                # Build the call
                ret = '{} ({})'.format(
                    call_name, ', '.join('{} => {}'.format(name, value)
                                         for name, value in args))

            else:
                # If we reach this point, we know that we are accessing a
                # struct field: make sure we return the public API type,
                # which may be different from the type thas is stored in the
                # struct.
                ret = self.node_data.type.extract_from_storage_expr(
                    prefix, '{}.{}'.format(prefix,
                                           self.node_data.internal_name))

            if self.wrap_result_in_entity:
                ret = '{} (Node => {}, Info => {})'.format(
                    self.type.constructor_name, ret, self.entity_info_expr)

            return ret