All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.micronaut.sourcegen.bytecode.AbstractConditionalWriter Maven / Gradle / Ivy

There is a newer version: 1.5.3
Show newest version
/*
 * Copyright 2017-2024 original authors
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package io.micronaut.sourcegen.bytecode;

import io.micronaut.core.annotation.Internal;
import io.micronaut.sourcegen.bytecode.expression.ExpressionWriter;
import io.micronaut.sourcegen.model.ExpressionDef;
import io.micronaut.sourcegen.model.JavaIdioms;
import io.micronaut.sourcegen.model.TypeDef;
import org.objectweb.asm.Label;
import org.objectweb.asm.Type;
import org.objectweb.asm.commons.GeneratorAdapter;

/**
 * The common condition writer methods.
 *
 * @author Denis Stepanov
 * @since 1.5
 */
@Internal
public abstract class AbstractConditionalWriter {

    protected static void pushElseConditionalExpression(GeneratorAdapter generatorAdapter,
                                                        MethodContext context,
                                                        ExpressionDef expressionDef,
                                                        Label elseLabel) {
        if (expressionDef instanceof ExpressionDef.ConditionExpressionDef conditionExpressionDef) {
            if (expressionDef instanceof ExpressionDef.InstanceOf instanceOf) {
                ExpressionWriter.writeExpression(generatorAdapter, context, instanceOf.expression());
                generatorAdapter.instanceOf(TypeUtils.getType(instanceOf.instanceType(), context.objectDef()));
                generatorAdapter.push(true);
                generatorAdapter.ifCmp(Type.BOOLEAN_TYPE, GeneratorAdapter.NE, elseLabel);
                return;
            }
            if (conditionExpressionDef instanceof ExpressionDef.And andExpressionDef) {
                pushElseConditionalExpression(generatorAdapter, context, andExpressionDef.left(), elseLabel);
                pushElseConditionalExpression(generatorAdapter, context, andExpressionDef.right(), elseLabel);
                return;
            }
            if (conditionExpressionDef instanceof ExpressionDef.Or orExpressionDef) {
                Label ifLabel = new Label();
                pushIfConditionalExpression(generatorAdapter, context, orExpressionDef.left(), ifLabel);
                pushIfConditionalExpression(generatorAdapter, context, orExpressionDef.right(), ifLabel);
                generatorAdapter.goTo(elseLabel);
                generatorAdapter.visitLabel(ifLabel);
                return;
            }
            if (conditionExpressionDef instanceof ExpressionDef.Condition condition) {
                ExpressionWriter.writeExpression(generatorAdapter, context, condition.left());
                ExpressionWriter.writeExpression(generatorAdapter, context, condition.right());
                Type conditionType = TypeUtils.getType(condition.left().type(), context.objectDef());
                generatorAdapter.ifCmp(conditionType, getInvertConditionOp(condition.operator()), elseLabel);
                return;
            }
            if (conditionExpressionDef instanceof ExpressionDef.IsNull isNull) {
                ExpressionWriter.writeExpression(generatorAdapter, context, isNull.expression());
                generatorAdapter.ifNonNull(elseLabel);
                return;
            }
            if (conditionExpressionDef instanceof ExpressionDef.IsNotNull isNotNull) {
                ExpressionWriter.writeExpression(generatorAdapter, context, isNotNull.expression());
                generatorAdapter.ifNull(elseLabel);
                return;
            }
            if (conditionExpressionDef instanceof ExpressionDef.IsTrue isTrue) {
                ExpressionWriter.writeExpression(generatorAdapter, context, isTrue.expression());
                generatorAdapter.push(true);
                generatorAdapter.ifCmp(Type.BOOLEAN_TYPE, GeneratorAdapter.NE, elseLabel);
                return;
            }
            if (conditionExpressionDef instanceof ExpressionDef.IsFalse isFalse) {
                ExpressionWriter.writeExpression(generatorAdapter, context, isFalse.expression());
                generatorAdapter.push(true);
                generatorAdapter.ifCmp(Type.BOOLEAN_TYPE, GeneratorAdapter.EQ, elseLabel);
                return;
            }
            if (conditionExpressionDef instanceof ExpressionDef.EqualsReferentially equalsReferentially) {
                pushEqualsReferentially(generatorAdapter, context, equalsReferentially, elseLabel, GeneratorAdapter.NE);
                return;
            }
            if (expressionDef instanceof ExpressionDef.EqualsStructurally equalsStructurally) {
                pushEqualsStructurally(generatorAdapter, context, equalsStructurally, elseLabel, GeneratorAdapter.NE);
                return;
            }
            throw new UnsupportedOperationException("Unrecognized conditional expression: " + conditionExpressionDef);
        }
        if (!expressionDef.type().equals(TypeDef.Primitive.BOOLEAN) && !expressionDef.type().equals(TypeDef.Primitive.BOOLEAN.wrapperType())) {
            throw new IllegalStateException("Conditional expression should produce a boolean: " + expressionDef);
        }
        ExpressionWriter.writeExpressionCheckCast(generatorAdapter, context, expressionDef, TypeDef.Primitive.BOOLEAN);
        generatorAdapter.push(true);
        generatorAdapter.ifCmp(Type.BOOLEAN_TYPE, GeneratorAdapter.NE, elseLabel);
    }

    private static void pushIfConditionalExpression(GeneratorAdapter generatorAdapter,
                                                    MethodContext context,
                                                    ExpressionDef expressionDef,
                                                    Label ifLabel) {
        if (expressionDef instanceof ExpressionDef.ConditionExpressionDef conditionExpressionDef) {
            if (expressionDef instanceof ExpressionDef.InstanceOf instanceOf) {
                ExpressionWriter.writeExpression(generatorAdapter, context, instanceOf.expression());
                generatorAdapter.instanceOf(TypeUtils.getType(instanceOf.instanceType(), context.objectDef()));
                generatorAdapter.push(true);
                generatorAdapter.ifCmp(Type.BOOLEAN_TYPE, GeneratorAdapter.EQ, ifLabel);
                return;
            }
            if (conditionExpressionDef instanceof ExpressionDef.And andExpressionDef) {
                Label elseLabel = new Label();
                pushElseConditionalExpression(generatorAdapter, context, andExpressionDef.left(), elseLabel);
                pushElseConditionalExpression(generatorAdapter, context, andExpressionDef.right(), elseLabel);
                generatorAdapter.goTo(ifLabel);
                generatorAdapter.visitLabel(elseLabel);
                return;
            }
            if (conditionExpressionDef instanceof ExpressionDef.Or orExpressionDef) {
                pushIfConditionalExpression(generatorAdapter, context, orExpressionDef.left(), ifLabel);
                pushIfConditionalExpression(generatorAdapter, context, orExpressionDef.right(), ifLabel);
                return;
            }
            if (conditionExpressionDef instanceof ExpressionDef.Condition condition) {
                ExpressionWriter.writeExpression(generatorAdapter, context, condition.left());
                ExpressionWriter.writeExpression(generatorAdapter, context, condition.right());
                Type conditionType = TypeUtils.getType(condition.left().type(), context.objectDef());
                generatorAdapter.ifCmp(conditionType, getConditionOp(condition.operator()), ifLabel);
                return;
            }
            if (conditionExpressionDef instanceof ExpressionDef.IsNull isNull) {
                ExpressionWriter.writeExpression(generatorAdapter, context, isNull.expression());
                generatorAdapter.ifNull(ifLabel);
                return;
            }
            if (conditionExpressionDef instanceof ExpressionDef.IsNotNull isNotNull) {
                ExpressionWriter.writeExpression(generatorAdapter, context, isNotNull.expression());
                generatorAdapter.ifNonNull(ifLabel);
                return;
            }
            if (conditionExpressionDef instanceof ExpressionDef.IsTrue isTrue) {
                ExpressionWriter.writeExpression(generatorAdapter, context, isTrue.expression());
                generatorAdapter.push(true);
                generatorAdapter.ifCmp(Type.BOOLEAN_TYPE, GeneratorAdapter.EQ, ifLabel);
                return;
            }
            if (conditionExpressionDef instanceof ExpressionDef.IsFalse isFalse) {
                ExpressionWriter.writeExpression(generatorAdapter, context, isFalse.expression());
                generatorAdapter.push(true);
                generatorAdapter.ifCmp(Type.BOOLEAN_TYPE, GeneratorAdapter.NE, ifLabel);
                return;
            }
            if (conditionExpressionDef instanceof ExpressionDef.EqualsReferentially equalsReferentially) {
                pushEqualsReferentially(generatorAdapter, context, equalsReferentially, ifLabel, GeneratorAdapter.EQ);
                return;
            }
            if (expressionDef instanceof ExpressionDef.EqualsStructurally equalsStructurally) {
                pushEqualsStructurally(generatorAdapter, context, equalsStructurally, ifLabel, GeneratorAdapter.EQ);
                return;
            }
            throw new UnsupportedOperationException("Unrecognized conditional expression: " + conditionExpressionDef);
        }
        if (!expressionDef.type().equals(TypeDef.Primitive.BOOLEAN) && !expressionDef.type().equals(TypeDef.Primitive.BOOLEAN.wrapperType())) {
            throw new IllegalStateException("Conditional expression should produce a boolean: " + expressionDef);
        }
        ExpressionWriter.writeExpressionCheckCast(generatorAdapter, context, expressionDef, TypeDef.Primitive.BOOLEAN);
        generatorAdapter.push(true);
        generatorAdapter.ifCmp(Type.BOOLEAN_TYPE, GeneratorAdapter.EQ, ifLabel);
    }

    private static void pushEqualsStructurally(GeneratorAdapter generatorAdapter, MethodContext context, ExpressionDef.EqualsStructurally equalsStructurally, Label ifLabel, int op) {
        TypeDef leftType = equalsStructurally.instance().type();
        TypeDef rightType = equalsStructurally.other().type();
        if (leftType.isPrimitive()) {
            pushEqualsReferentially(generatorAdapter, context, equalsStructurally.instance(), equalsStructurally.other().cast(leftType), ifLabel, op);
            return;
        }
        if (rightType.isPrimitive()) {
            pushEqualsReferentially(generatorAdapter, context, equalsStructurally.instance().cast(rightType), equalsStructurally.other(), ifLabel, op);
            return;
        }
        pushEqualsStructurally(generatorAdapter, context, equalsStructurally);
        generatorAdapter.push(true);
        generatorAdapter.ifCmp(Type.BOOLEAN_TYPE, op, ifLabel);
    }

    private static void pushEqualsReferentially(GeneratorAdapter generatorAdapter, MethodContext context,
                                                ExpressionDef.EqualsReferentially equalsReferentially,
                                                Label label, int op) {
        ExpressionDef left = equalsReferentially.instance();
        ExpressionDef right = equalsReferentially.other();
        pushEqualsReferentially(generatorAdapter, context, left, right, label, op);
    }

    private static void pushEqualsReferentially(GeneratorAdapter generatorAdapter,
                                                MethodContext context,
                                                ExpressionDef left,
                                                ExpressionDef right,
                                                Label label,
                                                int op) {
        TypeDef leftType = left.type();
        ExpressionWriter.writeExpression(generatorAdapter, context, left);
        TypeDef rightType = right.type();
        ExpressionWriter.writeExpression(generatorAdapter, context, right);
        if (leftType instanceof TypeDef.Primitive p1 && rightType instanceof TypeDef.Primitive) {
            generatorAdapter.ifCmp(TypeUtils.getType(p1), op, label);
        } else {
            generatorAdapter.ifCmp(TypeUtils.OBJECT_TYPE, op, label);
        }
    }

    private static void pushEqualsStructurally(GeneratorAdapter generatorAdapter, MethodContext context, ExpressionDef.EqualsStructurally equalsStructurally) {
        ExpressionWriter.writeExpressionCheckCast(generatorAdapter, context, JavaIdioms.equalsStructurally(equalsStructurally), TypeDef.Primitive.BOOLEAN);
    }

    private static int getInvertConditionOp(String op) {
        int conditionOp = getConditionOp(op);
        return switch (conditionOp) {
            case GeneratorAdapter.EQ -> GeneratorAdapter.NE;
            case GeneratorAdapter.NE -> GeneratorAdapter.EQ;
            default ->
                throw new UnsupportedOperationException("Unrecognized condition operator: " + conditionOp);
        };
    }

    private static int getConditionOp(String op) {
        return switch (op.trim()) {
            case "==" -> GeneratorAdapter.EQ;
            case "!=" -> GeneratorAdapter.NE;
            default ->
                throw new UnsupportedOperationException("Unrecognized condition operator: " + op);
        };
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy