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

net.thisptr.jackson.jq.internal.tree.binaryop.BinaryOperatorExpression Maven / Gradle / Ivy

There is a newer version: 1.2.0
Show newest version
package net.thisptr.jackson.jq.internal.tree.binaryop;

import java.lang.reflect.Constructor;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Stack;

import net.thisptr.jackson.jq.Expression;
import net.thisptr.jackson.jq.Version;
import net.thisptr.jackson.jq.internal.tree.binaryop.BinaryOperatorExpression.Operator.Associativity;
import net.thisptr.jackson.jq.internal.tree.binaryop.assignment.Assignment;
import net.thisptr.jackson.jq.internal.tree.binaryop.assignment.ComplexAlternativeAssignment;
import net.thisptr.jackson.jq.internal.tree.binaryop.assignment.ComplexDivideAssignment;
import net.thisptr.jackson.jq.internal.tree.binaryop.assignment.ComplexMinusAssignment;
import net.thisptr.jackson.jq.internal.tree.binaryop.assignment.ComplexModuloAssignment;
import net.thisptr.jackson.jq.internal.tree.binaryop.assignment.ComplexMultiplyAssignment;
import net.thisptr.jackson.jq.internal.tree.binaryop.assignment.ComplexPlusAssignment;
import net.thisptr.jackson.jq.internal.tree.binaryop.assignment.UpdateAssignment;
import net.thisptr.jackson.jq.internal.tree.binaryop.comparison.CompareEqualTest;
import net.thisptr.jackson.jq.internal.tree.binaryop.comparison.CompareGreaterEqualTest;
import net.thisptr.jackson.jq.internal.tree.binaryop.comparison.CompareGreaterTest;
import net.thisptr.jackson.jq.internal.tree.binaryop.comparison.CompareLessEqualTest;
import net.thisptr.jackson.jq.internal.tree.binaryop.comparison.CompareLessTest;
import net.thisptr.jackson.jq.internal.tree.binaryop.comparison.CompareNotEqualTest;

public abstract class BinaryOperatorExpression implements Expression {
	protected Expression lhs;
	protected Expression rhs;
	private String image;

	public BinaryOperatorExpression(final Expression lhs, final Expression rhs, final String image) {
		this.lhs = lhs;
		this.rhs = rhs;
		this.image = image;
	}

	@Override
	public String toString() {
		return String.format("(%s %s %s)", lhs, image, rhs);
	}

	public enum Operator {
		ASSIGN("=", 6, Associativity.RIGHT, Assignment.class),
		UDPATE("|=", 6, Associativity.RIGHT, UpdateAssignment.class),
		DEFAULT_EQUAL("//=", 6, Associativity.RIGHT, ComplexAlternativeAssignment.class),
		PLUS_EQUAL("+=", 6, Associativity.RIGHT, ComplexPlusAssignment.class),
		MINUS_EQUAL("-=", 6, Associativity.RIGHT, ComplexMinusAssignment.class),
		TIMES_EQUAL("*=", 6, Associativity.RIGHT, ComplexMultiplyAssignment.class),
		DIVIDE_EQUAL("/=", 6, Associativity.RIGHT, ComplexDivideAssignment.class),
		MODULO_EQUAL("%=", 6, Associativity.RIGHT, ComplexModuloAssignment.class),
		DEFAULT("//", 5, Associativity.LEFT, AlternativeOperatorExpression.class),
		OR("or", 4, Associativity.LEFT, BooleanOrExpression.class),
		AND("and", 4, Associativity.LEFT, BooleanAndExpression.class),
		LESS_EQUAL("<=", 3, Associativity.LEFT, CompareLessEqualTest.class),
		LESS("<", 3, Associativity.LEFT, CompareLessTest.class),
		GREATER_EQUAL(">=", 3, Associativity.LEFT, CompareGreaterEqualTest.class),
		GREATER(">", 3, Associativity.LEFT, CompareGreaterTest.class),
		EQUAL("==", 3, Associativity.LEFT, CompareEqualTest.class),
		NOT_EQUAL("!=", 3, Associativity.LEFT, CompareNotEqualTest.class),
		PLUS("+", 2, Associativity.LEFT, PlusExpression.class),
		MINUS("-", 2, Associativity.LEFT, MinusExpression.class),
		MODULO("%", 1, Associativity.LEFT, ModuloExpression.class),
		DIVIDE("/", 1, Associativity.LEFT, DivideExpression.class),
		TIMES("*", 1, Associativity.LEFT, MultiplyExpression.class);

		public final String image;
		public final int precedence;
		public final Associativity associativity;
		public final Class clazz;
		public final Constructor constructor;
		public final boolean versionAware;

		public enum Associativity {
			LEFT, RIGHT
		}

		private Operator(final String image, final int precedence, final Associativity associativity, final Class clazz) {
			this.image = image;
			this.precedence = precedence;
			this.associativity = associativity;
			this.clazz = clazz;

			Constructor ctor;
			boolean versionAware;
			try {
				try {
					ctor = clazz.getConstructor(Expression.class, Expression.class, Version.class);
					versionAware = true;
				} catch (NoSuchMethodException e) {
					ctor = clazz.getConstructor(Expression.class, Expression.class);
					versionAware = false;
				}
			} catch (Exception e) {
				throw new RuntimeException(e);
			}

			this.constructor = ctor;
			this.versionAware = versionAware;
		}

		public static Operator fromImage(final String image) {
			final Operator op = lookup.get(image);
			if (op == null)
				throw new IllegalArgumentException();
			return op;
		}

		private static Map lookup = new HashMap<>();
		static {
			for (final Operator op : Operator.values())
				lookup.put(op.image, op);
		}

		public Expression buildTree(final Expression lhs, final Expression rhs, final Version version) {
			try {
				if (versionAware)
					return constructor.newInstance(lhs, rhs, version);
				return constructor.newInstance(lhs, rhs);
			} catch (Exception e) {
				throw new RuntimeException(e);
			}
		}
	}

	public static Expression buildTree(final List exprs, final List operators, final Version version) {
		if (exprs.size() != operators.size() + 1)
			throw new IllegalArgumentException();

		// shunting-yard algorithm
		final Stack stackExprs = new Stack<>();
		final Stack stackOperators = new Stack<>();

		final Iterator iterExpr = exprs.iterator();
		final Iterator iterOperator = operators.iterator();

		stackExprs.push(iterExpr.next());
		while (iterExpr.hasNext()) {
			final Operator op1 = iterOperator.next();
			while (!stackOperators.isEmpty()) {
				final Operator op2 = stackOperators.peek();
				if (op1.precedence > op2.precedence
						|| op1.precedence == op2.precedence && op1.associativity == Associativity.LEFT) {
					final Operator op = stackOperators.pop();
					final Expression rhs = stackExprs.pop();
					final Expression lhs = stackExprs.pop();
					stackExprs.push(op.buildTree(lhs, rhs, version));
				} else {
					break;
				}
			}
			stackOperators.push(op1);
			stackExprs.push(iterExpr.next());
		}

		while (!stackOperators.isEmpty()) {
			final Operator op = stackOperators.pop();
			final Expression rhs = stackExprs.pop();
			final Expression lhs = stackExprs.pop();
			stackExprs.push(op.buildTree(lhs, rhs, version));
		}

		return stackExprs.get(0);
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy