package de.dhbwstuttgart.target.tree.expression;

import de.dhbwstuttgart.target.tree.expression.TargetExpression;
import de.dhbwstuttgart.target.tree.type.TargetType;

public sealed interface TargetBinaryOp extends TargetExpression {
    TargetExpression left();

    TargetExpression right();

    // Arithmetic
    record Add(TargetType type, TargetExpression left, TargetExpression right) implements TargetBinaryOp {
    }

    record Sub(TargetType type, TargetExpression left, TargetExpression right) implements TargetBinaryOp {
    }

    record Div(TargetType type, TargetExpression left, TargetExpression right) implements TargetBinaryOp {
    }

    record Mul(TargetType type, TargetExpression left, TargetExpression right) implements TargetBinaryOp {
    }

    record Rem(TargetType type, TargetExpression left, TargetExpression right) implements TargetBinaryOp {
    }

    // Bitwise
    record BAnd(TargetType type, TargetExpression left, TargetExpression right) implements TargetBinaryOp {
    }

    record BOr(TargetType type, TargetExpression left, TargetExpression right) implements TargetBinaryOp {
    }

    record XOr(TargetType type, TargetExpression left, TargetExpression right) implements TargetBinaryOp {
    }

    record Shl(TargetType type, TargetExpression left, TargetExpression right) implements TargetBinaryOp {
    }

    record Shr(TargetType type, TargetExpression left, TargetExpression right) implements TargetBinaryOp {
    }

    record UShr(TargetType type, TargetExpression left, TargetExpression right) implements TargetBinaryOp {
    }

    // Conditional
    record And(TargetType type, TargetExpression left, TargetExpression right) implements TargetBinaryOp {
    }

    record Or(TargetType type, TargetExpression left, TargetExpression right) implements TargetBinaryOp {
    }

    record Instof(TargetType type, TargetExpression left, TargetExpression right) implements TargetBinaryOp {
    }

    sealed interface TargetRelationalOp extends TargetBinaryOp {
        @Override
        default TargetType type() {
            return TargetType.Boolean;
        }

        TargetType exprType();
    }

    // Comparison
    // exprType is the type that both arguments get converted to before comparison
    record Equal(TargetType exprType, TargetExpression left, TargetExpression right) implements TargetRelationalOp {
    }

    record Greater(TargetType exprType, TargetExpression left, TargetExpression right) implements TargetRelationalOp {
    }

    record GreaterOrEqual(TargetType exprType, TargetExpression left, TargetExpression right) implements TargetRelationalOp {
    }

    record Less(TargetType exprType, TargetExpression left, TargetExpression right) implements TargetRelationalOp {
    }

    record LessOrEqual(TargetType exprType, TargetExpression left, TargetExpression right) implements TargetRelationalOp {
    }

    record NotEqual(TargetType exprType, TargetExpression left, TargetExpression right) implements TargetRelationalOp {
    }

}
