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

com.github.bloodshura.x.utilities.eval.enumeration.Operator Maven / Gradle / Ivy

The newest version!
/*
 * Copyright (c) 2013-2018, João Vitor Verona Biazibetti - All Rights Reserved
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program. If not, see .
 *
 * https://www.github.com/BloodShura
 */

package com.github.bloodshura.x.utilities.eval.enumeration;

import com.github.bloodshura.x.collection.view.XView;
import com.github.bloodshura.x.enumeration.Enumerations;
import com.github.bloodshura.x.object.Base;
import com.github.bloodshura.x.util.XApi;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.math.BigDecimal;
import java.math.MathContext;
import java.util.function.Function;

public class Operator extends Base {
	public static final Operator ABS = new Operator("ABS", " abs ", 1, 4, 1, 1, operands -> operands[0].abs());
	public static final Operator ADD = new Operator("ADD", "+", 2, 2, 1, 1, operands -> operands[0].add(operands[1]));
	public static final Operator AND = new Operator("AND", "&&", 2, 0, 0, 0, operands -> operands[0].signum() != 0 && operands[1].signum() != 0);
	public static final Operator DIVIDE = new Operator("DIVIDE", "/", 2, 3, 1, 1, operands -> operands[0].divide(operands[1], MathContext.UNLIMITED));
	public static final Operator END = new Operator("END", "", 0, -1, Type.NONE, Type.NONE, operands -> null);
	public static final Operator EQUAL = new Operator("EQUAL", "==", 2, 1, 1, 0, operands -> operands[0].compareTo(operands[1]) == 0);
	public static final Operator GREATER_EQUAL = new Operator("GREATER_EQUAL", ">=", 2, 1, 1, 0, operands -> operands[0].compareTo(operands[1]) >= 0);
	public static final Operator GREATER_THAN = new Operator("GREATER_THAN", ">", 2, 1, 1, 0, operands -> operands[0].compareTo(operands[1]) > 0);
	public static final Operator INT = new Operator("INT", "int ", 1, 4, 1, 1, operands -> new BigDecimal(operands[0].toBigInteger()));
	public static final Operator LOWER_EQUAL = new Operator("LOWER_EQUAL", "<=", 2, 1, 1, 0, operands -> operands[0].compareTo(operands[1]) <= 0);
	public static final Operator LOWER_THAN = new Operator("LOWER_THAN", "<", 2, 1, 1, 0, operands -> operands[0].compareTo(operands[1]) < 0);
	public static final Operator MULTIPLY = new Operator("MULTIPLY", "*", 2, 3, 1, 1, operands -> operands[0].multiply(operands[1]));
	public static final Operator NEGATE = new Operator("NEGATE", "-", 1, 4, 1, 1, operands -> operands[0].negate());
	public static final Operator NOP = new Operator("NOP", "", 1, 4, 1, 1, operands -> operands[0]);
	public static final Operator NOT_EQUAL = new Operator("NOT_EQUAL", "!=", 2, 1, 1, 0, operands -> operands[0].compareTo(operands[1]) != 0);
	public static final Operator OR = new Operator("OR", "||", 2, 0, 0, 0, operands -> operands[0].signum() != 0 || operands[1].signum() != 0);
	public static final Operator PLUS = new Operator("PLUS", "+", 1, 4, 1, 1, operands -> operands[0]);
	public static final Operator POW = new Operator("POW", "^", 2, 3, 1, 1, operands -> operands[0].pow(operands[1].intValueExact()));
	public static final Operator REMAINDER = new Operator("REMAINDER", "%", 2, 3, 1, 1, operands -> operands[0].remainder(operands[1], MathContext.UNLIMITED));
	public static final Operator SUBTRACT = new Operator("SUBTRACT", "-", 2, 2, 1, 1, operands -> operands[0].subtract(operands[1]));
	public static final Operator TERNARY = new Operator("TERNARY", "?", 3, 0, Type.NONE, Type.NONE, operands -> operands[0].signum() != 0 ? operands[1] : operands[2]);

	private final Function function;
	private final String identifier;
	private final int operandCount;
	private final Type operandType;
	private final int precedence;
	private final Type resultType;
	private final String name;

	public Operator(@Nonnull String name, @Nonnull String identifier, int operandCount, int precedence, int operandType, int resultType, @Nonnull Function function) {
		this(name, identifier, operandCount, precedence, operandType == 1 ? Type.ARITHMETIC : Type.BOOLEAN, resultType == 1 ? Type.ARITHMETIC : Type.BOOLEAN, function);
	}

	public Operator(@Nonnull String name, @Nonnull String identifier, int operandCount, int precedence, @Nonnull Type operandType, @Nonnull Type resultType, @Nullable Function function) {
		this.function = function;
		this.identifier = identifier;
		this.name = name;
		this.operandCount = operandCount;
		this.operandType = operandType;
		this.precedence = precedence;
		this.resultType = resultType;
	}

	@Nonnull
	public Function getFunction() {
		return function;
	}

	@Nonnull
	public String getIdentifier() {
		return identifier;
	}

	@Nonnull
	public String getName() {
		return name;
	}

	public int getOperandCount() {
		return operandCount;
	}

	@Nonnull
	public Type getOperandType() {
		return operandType;
	}

	public int getPrecedence() {
		return precedence;
	}

	@Nonnull
	public Type getResultType() {
		return resultType;
	}

	@Nonnull
	public BigDecimal perform(@Nonnull BigDecimal... values) {
		XApi.require(values.length == getOperandCount(), "Operator \"" + getIdentifier() + "\" requires " + getOperandCount() + " operands");

		Object result = getFunction().apply(values);

		XApi.require(result instanceof BigDecimal || result instanceof Boolean || result instanceof Integer, "Returned value of operator \"" + this + "\" is neither BigDecimal, nor Integer");

		if (result instanceof Boolean) {
			return (Boolean) result ? BigDecimal.ONE : BigDecimal.ZERO;
		}

		if (getResultType() == Type.BOOLEAN) {
			if (result instanceof BigDecimal) {
				return !result.equals(BigDecimal.ZERO) ? BigDecimal.ONE : BigDecimal.ZERO;
			}

			if (result instanceof Integer) {
				Integer value = (Integer) result;

				return value != 0 ? BigDecimal.ONE : BigDecimal.ZERO;
			}
		}

		if (result instanceof Integer) {
			return BigDecimal.valueOf((Integer) result);
		}

		return (BigDecimal) result;
	}

	@Nonnull
	@Override
	protected Object[] stringValues() {
		return new Object[] { getIdentifier(), getOperandCount(), getPrecedence(), getOperandType(), getResultType() };
	}

	@Nonnull
	public static XView values() {
		return Enumerations.values(Operator.class);
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy