예제 #1
0
        def entity_info_expr(self):
            """
            Return the value of the entity info parameter along, compute its
            value. Return None otherwise.

            :rtype: str|None
            """
            # If the property that this field accesses requires entity info,
            # then the prefix is supposed to be an entity. There are only two
            # exceptions to this: either the entity info is actually optional,
            # either we are out of any property. In these cases, leave the
            # default entity info.
            #
            # See CompileCtx.compute_uses_entity_info_attr for how we check
            # that the assertion always holds.
            if not self.implicit_deref:
                assert (self.node_data.optional_entity_info
                        or PropertyDef.get() is None)
                return None

            # When it is required, entity info comes from the entity, if we're
            # calling the property on an entity.
            return '{}.Info'.format(self.prefix)
예제 #2
0
        def __init__(self, prefix_expr, matchers, abstract_expr=None):
            """
            :param ResolvedExpression prefix_expr: The expression on which the
                dispatch occurs. It must be either an AST node or an entity.
            :param list[Match.Matcher] matchers: List of matchers for this
                node.
            """
            assert (prefix_expr.type.is_ast_node
                    or prefix_expr.type.is_entity_type)
            self.prefix_expr = NullCheckExpr(
                prefix_expr, implicit_deref=prefix_expr.type.is_entity_type)

            # Variable to hold the value of which we do dispatching
            # (prefix_expr).
            self.prefix_var = PropertyDef.get().vars.create(
                'Match_Prefix', self.prefix_expr.type)

            # Compute the return type as the unification of all branches
            rtype = matchers[-1].match_expr.type
            for m in matchers:
                rtype = m.match_expr.type.unify(
                    rtype,
                    'Mismatching types in Match expression: got {self} but'
                    ' expected {other} or sub/supertype')
            self.static_type = rtype

            # Wrap each matcher expression so that all capture variables are
            # bound and initialized.
            self.matchers = []
            for m in matchers:
                # Initialize match_var. Note that assuming the code generation
                # is bug-free, this cast cannot fail, so don't generate type
                # check boilerplate.
                let_expr = Let.Expr(
                    [m.match_var],
                    [
                        Cast.Expr(self.prefix_var.ref_expr,
                                  m.match_var.type,
                                  unsafe=True)
                    ],

                    # ... and cast this matcher's result to the Match result's
                    # type, as required by OOP with access types in Ada.
                    (m.match_expr if m.match_expr.type == rtype else Cast.Expr(
                        m.match_expr, rtype)))

                # Now do the binding for static analysis and debugging
                self.matchers.append(
                    Match.Matcher(
                        m.match_var,
                        BindingScope(let_expr, [], scope=m.inner_scope),
                        m.inner_scope))

            # Determine for each matcher the set of concrete AST nodes it can
            # actually match.
            prefix_type = self.prefix_expr.type
            if prefix_type.is_entity_type:
                prefix_type = prefix_type.element_type
            matched_types, remainder = collapse_concrete_nodes(
                (prefix_type.element_type if prefix_type.is_entity_type else
                 prefix_type), [m.match_astnode_type for m in self.matchers])
            assert not remainder
            for matcher, matched in zip(self.matchers, matched_types):
                matcher.matched_concrete_nodes = matched

            super(Match.Expr, self).__init__('Match_Result',
                                             abstract_expr=abstract_expr)
예제 #3
0
        def __init__(self,
                     receiver_expr,
                     node_data,
                     arguments,
                     implicit_deref=False,
                     unsafe=False,
                     abstract_expr=None):
            """
            :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|None] arguments: If non-empty, this
                field access will actually be a primitive call. Each item is a
                ResolvedExpression for an actual to pass, or None for arguments
                to let them have their default value. List list must have the
                same size as `node_data.natural_arguments`.

            :param bool implicit_deref: Whether the receiver is an entity,
                and we want to access a field or property of the stored node.
                In the case of an entity prefix for an AST node field, return
                an entity with the same entity info.

            :param bool unsafe: If true, don't generate the null crheck before
                doing the field access. This is used to avoid noisy and useless
                null checks in generated code: these checks would fail only
                because of a bug in the code generator.

            :param AbstractExpression|None abstract_expr: See
                ResolvedExpression's constructor.
            """
            # When calling environment properties, the call itself happens are
            # outside a property. We cannot create a variable in this context,
            # and the field access is not supposed to require a "render_pre"
            # step.
            p = PropertyDef.get()
            self.simple_field_access = not p
            assert not self.simple_field_access or not implicit_deref

            self.implicit_deref = implicit_deref
            self.unsafe = unsafe

            self.original_receiver_expr = receiver_expr
            self.receiver_expr = (receiver_expr if self.simple_field_access
                                  or self.unsafe else NullCheckExpr(
                                      receiver_expr, implicit_deref))

            self.node_data = node_data

            # Keep the original node data for debugging purposes
            self.original_node_data = node_data

            # If this is a property call, take the root property
            if self.node_data.is_property:
                self.node_data = self.node_data.root_property

            self.arguments = arguments
            if self.arguments is not None:
                assert (len(self.arguments) == len(
                    self.node_data.natural_arguments))

            if isinstance(self.node_data, PropertyDef):
                self.dynamic_vars = [
                    construct(dynvar) for dynvar in self.node_data.dynamic_vars
                ]

            self.static_type = self.node_data.type
            if self.wrap_result_in_entity:
                self.static_type = self.static_type.entity

            # 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__(
                None if self.simple_field_access else 'Fld',
                abstract_expr=abstract_expr,
            )
예제 #4
0
    def construct(self):
        """
        :rtype: StructExpr
        """
        if self.struct_type.is_ast_node:
            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

        def is_required(f):
            if isinstance(f, BuiltinField):
                # BuiltinFields are actually stored fields only for structure
                # types (not for nodes).
                return self.struct_type.is_struct_type

            elif isinstance(f, Field):
                return not f.null

            else:
                return isinstance(f, UserField)

        required_fields = {
            f._name.lower: f
            for f in self.struct_type.get_abstract_node_data()
            if is_required(f)
        }

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

        # 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, abstract_expr=self)