Operator.java

/*
* Copyright 2014 Frank Asseg
*
* 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
*
*    http://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 net.objecthunter.exp4j.operator;

import java.io.Serial;
import java.io.Serializable;

/**
 * Class representing operators that can be used in an expression
 */
public abstract class Operator implements Serializable {
    @Serial
    private static final long serialVersionUID = -2212179357073818713L;

    /**
     * The precedence value for the addition operation (default: {@value})
     */
    public static final int PRECEDENCE_ADDITION = 500;
    /**
     * The precedence value for the subtraction operation (default: {@value})
     */
    public static final int PRECEDENCE_SUBTRACTION = PRECEDENCE_ADDITION;
    /**
     * The precedence value for the multiplication operation (default: {@value})
     */
    public static final int PRECEDENCE_MULTIPLICATION = 1000;
    /**
     * The precedence value for the division operation (default: {@value})
     */
    public static final int PRECEDENCE_DIVISION = PRECEDENCE_MULTIPLICATION;
    /**
     * The precedence value for the modulo operation (default: {@value})
     */
    public static final int PRECEDENCE_MODULO = PRECEDENCE_DIVISION;
    /**
     * The precedence value for the power operation (default: {@value})
     */
    public static final int PRECEDENCE_POWER = 10000;
    /**
     * The precedence value for the unary minus operation (default: {@value})
     */
    public static final int PRECEDENCE_UNARY_MINUS = 5000;
    /**
     * The precedence value for the unary plus operation (default: {@value})
     */
    public static final int PRECEDENCE_UNARY_PLUS = PRECEDENCE_UNARY_MINUS;
    /**
     * The precedence value for the boolean not (default: {@value})
     */
    public static final int PRECEDENCE_NOT = PRECEDENCE_ADDITION - 200;
    /**
     * The precedence value for the boolean and (default: {@value})
     */
    public static final int PRECEDENCE_AND = PRECEDENCE_ADDITION - 300;
    /**
     * The precedence value for the boolean or (default: {@value})
     */
    public static final int PRECEDENCE_OR  = PRECEDENCE_ADDITION - 400;
    /**
     * This is the threshold used to consider {@code false} values false, it has a default value
     * of {@value}
     */
    public static final double BOOLEAN_THRESHOLD = 1.0E-12;

    /**
     * The set of allowed operator chars
     */
    private static final char[] ALLOWED_OPERATOR_CHARS = {
        '+', '-', '*', '/', '%',
        '^', '!', '#', '§', '$',
        '&', ';', ':', '~', '<',
        '>', '|', '=', '¬'
    };

    private final int numOperands;
    private final boolean leftAssociative;
    private final String symbol;
    private final int precedence;

    /**
     * Create a new operator for use in expressions
     * @param symbol the symbol of the operator
     * @param numberOfOperands the number of operands the operator takes (1 or 2)
     * @param leftAssociative set to true if the operator is left associative, false if it is right
     * associative
     * @param precedence the precedence value of the operator
     */
    public Operator(String symbol, int numberOfOperands, boolean leftAssociative,
                    int precedence) {
        super();
        this.numOperands = numberOfOperands;
        this.leftAssociative = leftAssociative;
        this.symbol = symbol;
        this.precedence = precedence;
    }

    /**
     * Check if a character is an allowed operator char
     * @param ch the char to check
     * @return true if the char is allowed an operator symbol, false otherwise
     */
    public static boolean isAllowedOperatorChar(char ch) {
        for (char allowed: ALLOWED_OPERATOR_CHARS) {
            if (ch == allowed) {
                return true;
            }
        }
        return false;
    }

    /**
     * Check if the operator is left associative
     * @return true os the operator is left associative, false otherwise
     */
    public boolean isLeftAssociative() {
        return leftAssociative;
    }

    /**
     * Check the precedence value for the operator
     * @return the precedence value
     */
    public int getPrecedence() {
        return precedence;
    }

    /**
     * Apply the operation on the given operands
     * @param args the operands for the operation
     * @return the calculated result of the operation
     */
    public abstract double apply(double ... args);

    /**
     * Get the operator symbol
     * @return the symbol
     */
    public String getSymbol() {
        return symbol;
    }

    /**
     * Get the number of operands
     * @return the number of operands
     */
    public int getNumOperands() {
        return numOperands;
    }
}