コード例 #1
0
ファイル: structs.py プロジェクト: AdaCore/langkit
    def construct(self):
        """
        Construct a resolved expression for this.

        :rtype: EqExpr
        """
        cexpr = construct(self.expr)
        return Eq.make_expr(
            cexpr, LiteralExpr(cexpr.type.nullexpr(), cexpr.type)
        )
コード例 #2
0
 def construct_static(cls, cexpr, abstract_expr=None):
     result = (cls.construct_node(cexpr) if cexpr.type.is_ast_node
               or cexpr.type.is_entity_type else Eq.make_expr(
                   cexpr, NullExpr(cexpr.type)))
     result.abstract_expr = abstract_expr
     return result
コード例 #3
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])
        )
コード例 #4
0
 def construct_static(cexpr):
     return Eq.make_expr(
         cexpr, LiteralExpr(cexpr.type.nullexpr(), cexpr.type)
     )
コード例 #5
0
ファイル: structs.py プロジェクト: AdaCore/langkit
    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