private Optional toTypedExpressionRec()

in drools-model/drools-model-codegen/src/main/java/org/drools/model/codegen/execmodel/generator/expressiontyper/ExpressionTyper.java [176:391]


    private Optional<TypedExpression> toTypedExpressionRec(Expression drlxExpr) {

        Class<?> typeCursor = patternType;

        if (drlxExpr instanceof FullyQualifiedInlineCastExpr ) {
            return toTypedExpressionRec( transformFullyQualifiedInlineCastExpr( ruleContext.getTypeResolver(), (FullyQualifiedInlineCastExpr) drlxExpr ) );
        }

        if (drlxExpr instanceof EnclosedExpr) {
            Expression inner = ((EnclosedExpr) drlxExpr).getInner();
            Optional<TypedExpression> typedExpression = toTypedExpressionRec(inner);
            return typedExpression.map(t -> t.cloneWithNewExpression(new EnclosedExpr(t.getExpression())));
        }

        if (drlxExpr instanceof MethodCallExpr methodExpr) {
            Expression expr = methodExpr;
            if (isEval(methodExpr.getNameAsString(), methodExpr.getScope(), methodExpr.getArguments())) {
                expr = methodExpr.getArgument(0);
            }
            drlxExpr = expr;
        }

        if (drlxExpr instanceof NullSafeMethodCallExpr methodExpr) {
            Expression expr = methodExpr;
            if (isEval(methodExpr.getNameAsString(), methodExpr.getScope(), methodExpr.getArguments())) {
                expr = methodExpr.getArgument(0);
            }
            drlxExpr = expr;
        }

        if (drlxExpr instanceof UnaryExpr unaryExpr) {
            Optional<TypedExpression> optTypedExpr = toTypedExpressionRec(unaryExpr.getExpression());
            return optTypedExpr.map(typedExpr -> new TypedExpression( new UnaryExpr( typedExpr.getExpression(), unaryExpr.getOperator() ), typedExpr.getType() ));
        }

        if (drlxExpr instanceof BinaryExpr binaryExpr) {

            BinaryExpr.Operator operator = binaryExpr.getOperator();

            Optional<TypedExpression> optLeft = toTypedExpressionRec(binaryExpr.getLeft());
            Optional<TypedExpression> optRight = toTypedExpressionRec(binaryExpr.getRight());

            if (optLeft.isEmpty() || optRight.isEmpty()) {
                return empty();
            }

            TypedExpression left = optLeft.get();
            TypedExpression right = optRight.get();

            final BinaryExpr combo;
            final Pair<TypedExpression, TypedExpression> numberAndStringCoercionResult =
                    NumberAndStringArithmeticOperationCoercion.coerceIfNeeded(operator, left, right);
            if (numberAndStringCoercionResult.hasLeft()) {
                left = numberAndStringCoercionResult.getLeft();
            }
            if (numberAndStringCoercionResult.hasRight()) {
                right = numberAndStringCoercionResult.getRight();
            }
            combo = new BinaryExpr(left.getExpression(), right.getExpression(), operator);

            if (shouldConvertArithmeticBinaryToMethodCall(operator, left.getType(), right.getType())) {
                Expression expression = convertArithmeticBinaryToMethodCall(combo, of(typeCursor), ruleContext);
                java.lang.reflect.Type binaryType = getBinaryTypeAfterConversion(left.getType(), right.getType());
                return of(new TypedExpression(expression, binaryType));
            } else {
                return of(new TypedExpression(combo, left.getType()));
            }
        }

        if (drlxExpr instanceof HalfBinaryExpr) {
            final Expression binaryExpr = trasformHalfBinaryToBinary(drlxExpr, Optional.of(ruleContext));
            if (binaryExpr instanceof BinaryExpr && ((BinaryExpr)binaryExpr).getLeft() == drlxExpr) {
                throw new CannotTypeExpressionException("left leaf is the same : drlxExpr = " + drlxExpr + ", originalExpression = " + context.getOriginalExpression());
            }
            return toTypedExpressionRec(binaryExpr);
        }

        if (drlxExpr instanceof LiteralExpr) {
            drlxExpr = normalizeDigit(drlxExpr);
            return of(new TypedExpression(drlxExpr, getLiteralExpressionType( ( LiteralExpr ) drlxExpr )));
        }

        if (drlxExpr instanceof ThisExpr || (drlxExpr instanceof NameExpr && THIS_PLACEHOLDER.equals(printNode(drlxExpr)))) {
            return of(new TypedExpression(new NameExpr(THIS_PLACEHOLDER), patternType, "this"));

        }

        if (drlxExpr instanceof CastExpr castExpr) {
            Optional<TypedExpression> optTypedExpr = toTypedExpressionRec(castExpr.getExpression());
            return optTypedExpr.map(typedExpr -> new TypedExpression(new CastExpr(castExpr.getType(), typedExpr.getExpression()), getClassFromContext(ruleContext.getTypeResolver(), castExpr.getType().asString())));
        }

        if (drlxExpr instanceof NameExpr) {
            return nameExpr(((NameExpr)drlxExpr).getNameAsString(), typeCursor);
        }

        if (drlxExpr instanceof FieldAccessExpr || drlxExpr instanceof MethodCallExpr || drlxExpr instanceof ObjectCreationExpr
                || drlxExpr instanceof NullSafeFieldAccessExpr || drlxExpr instanceof  NullSafeMethodCallExpr || drlxExpr instanceof MapCreationLiteralExpression || drlxExpr instanceof ListCreationLiteralExpression) {

            return toTypedExpressionFromMethodCallOrField(drlxExpr).getTypedExpression();
        }

        if (drlxExpr instanceof PointFreeExpr pointFreeExpr) {
            Optional<TypedExpression> optLeft = toTypedExpressionRec(pointFreeExpr.getLeft());
            Optional<TypedExpression> optRight = pointFreeExpr.getRight().size() == 1 ? toTypedExpressionRec(pointFreeExpr.getRight().get( 0 )) : Optional.empty();
            OperatorSpec opSpec = getOperatorSpec(pointFreeExpr.getRight(), pointFreeExpr.getOperator());

            return optLeft.map(left -> new TypedExpression(opSpec.getExpression( ruleContext, pointFreeExpr, left, this), left.getType())
                    .setStatic(opSpec.isStatic())
                    .setLeft(left)
                    .setRight( optRight.orElse( null ) ) );
        }

        if (drlxExpr instanceof HalfPointFreeExpr halfPointFreeExpr) {
            Expression parentLeft = findLeftLeafOfNameExprTraversingParent(halfPointFreeExpr);
            if (parentLeft == halfPointFreeExpr) {
                throw new CannotTypeExpressionException("left leaf is the same : halfPointFreeExpr = " + halfPointFreeExpr + ", originalExpression = " + context.getOriginalExpression());
            }
            Optional<TypedExpression> optLeft = toTypedExpressionRec(parentLeft);
            OperatorSpec opSpec = getOperatorSpec(halfPointFreeExpr.getRight(), halfPointFreeExpr.getOperator());

            final PointFreeExpr transformedToPointFree =
                    new PointFreeExpr(halfPointFreeExpr.getTokenRange().orElseThrow(() -> new IllegalStateException("Token range is not present!")),
                                      parentLeft,
                                      halfPointFreeExpr.getRight(),
                                      halfPointFreeExpr.getOperator(),
                                      halfPointFreeExpr.isNegated(),
                                      halfPointFreeExpr.getArg1(),
                                      halfPointFreeExpr.getArg2(),
                                      halfPointFreeExpr.getArg3(),
                                      halfPointFreeExpr.getArg4()
                    );

            return optLeft.map(left ->
                                new TypedExpression(opSpec.getExpression(ruleContext, transformedToPointFree, left, this), left.getType())
                                        .setStatic(opSpec.isStatic())
                                        .setLeft(left));

        }

        if (drlxExpr instanceof ArrayAccessExpr arrayAccessExpr) {
            if (Map.class.isAssignableFrom( typeCursor )) {
                return createMapAccessExpression(arrayAccessExpr.getIndex(), arrayAccessExpr.getName() instanceof ThisExpr ? new NameExpr(THIS_PLACEHOLDER) : arrayAccessExpr.getName(), Object.class);
            } else if (arrayAccessExpr.getName() instanceof FieldAccessExpr ) {
                Optional<TypedExpression> typedExpression = toTypedExpressionFromMethodCallOrField(drlxExpr).getTypedExpression();
                typedExpression.ifPresent(te -> {
                    final Expression originalExpression = te.getExpression();
                    DrlxParseUtil.removeRootNode(originalExpression);
                });
                return typedExpression;
            } else {
                Expression indexExpr = toTypedExpressionFromMethodCallOrField( arrayAccessExpr.getIndex() )
                        .getTypedExpression()
                        .orElseThrow(() -> new NoSuchElementException("TypedExpressionResult doesn't contain TypedExpression!"))
                        .getExpression();
                return toTypedExpressionRec(drlxExpr.asArrayAccessExpr().getName())
                        .flatMap( te -> transformToArrayOrMapExpressionWithType(indexExpr, te));
            }
        }

        if (drlxExpr instanceof InstanceOfExpr instanceOfExpr) {
            ruleContext.addInlineCastType(printNode(instanceOfExpr.getExpression()), instanceOfExpr.getType());
            return toTypedExpressionRec(instanceOfExpr.getExpression())
                    .map( e -> new TypedExpression(new InstanceOfExpr(e.getExpression(), instanceOfExpr.getType()), boolean.class) );

        }

        if (drlxExpr instanceof ClassExpr) {
            return of(new TypedExpression(drlxExpr, Class.class));
        }

        if (drlxExpr instanceof InlineCastExpr) {
            return toTypedExpressionFromMethodCallOrField(drlxExpr).getTypedExpression();
        }

        if (drlxExpr instanceof OOPathExpr) {
            Class<?> type = patternType;
            for (OOPathChunk chunk : ((OOPathExpr) drlxExpr).getChunks()) {
                final String fieldName = chunk.getField().toString();

                final TypedExpression callExpr = DrlxParseUtil.nameExprToMethodCallExpr(fieldName, type, null, ruleContext);
                if (callExpr == null) {
                    return empty();
                }
                Class<?> fieldType = (chunk.getInlineCast() != null)
                        ? DrlxParseUtil.getClassFromContext(ruleContext.getTypeResolver(), chunk.getInlineCast().toString())
                        : callExpr.getRawClass();

                if ( !chunk.isSingleValue() && Iterable.class.isAssignableFrom(fieldType) || isDataSource(fieldType) ) {
                    type = extractGenericType(type, ((MethodCallExpr) callExpr.getExpression()).getName().toString());
                } else {
                    type = fieldType;
                }
            }
            return of(new TypedExpression(drlxExpr, type));
        }

        if (drlxExpr instanceof ConditionalExpr) {
            return of(new TypedExpression(drlxExpr, Boolean.class));
        }

        if (drlxExpr.isAssignExpr()) {
            AssignExpr assignExpr = drlxExpr.asAssignExpr();

            final Expression rightSide = assignExpr.getValue();

            return toTypedExpressionRec(rightSide)
                    .map(e -> {
                        final AssignExpr newExpression = new AssignExpr(assignExpr.getTarget(), e.getExpression(), assignExpr.getOperator());
                        return new TypedExpression(newExpression, e.getType());
                    });

        }

        throw new UnsupportedOperationException();
    }