package org.jtwig.parser.parboiled.expression; import com.google.common.base.Function; import com.google.common.collect.ImmutableListMultimap; import com.google.common.collect.Multimaps; import org.jtwig.model.expression.BinaryOperationExpression; import org.jtwig.parser.parboiled.ParserContext; import org.jtwig.parser.parboiled.base.PositionTrackerParser; import org.jtwig.parser.parboiled.base.SpacingParser; import org.jtwig.parser.parboiled.expression.operator.BinaryOperatorParser; import org.jtwig.render.expression.calculator.operation.binary.BinaryOperator; import org.parboiled.Rule; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.List; public class BinaryOperationExpressionParser extends ExpressionParser<BinaryOperationExpression> { final Collection<BinaryOperator> operators; public BinaryOperationExpressionParser(ParserContext context, Collection<BinaryOperator> operators) { super(BinaryOperationExpressionParser.class, context); this.operators = operators; } @Override public Rule ExpressionRule() { Rule initialExpression = parserContext().parser(PrimaryExpressionParser.class).ExpressionRule(); ImmutableListMultimap<Integer, BinaryOperator> index = Multimaps.index(operators, precedence()); List<Integer> integers = new ArrayList<>(index.keySet()); Collections.sort(integers); for (Integer integer : integers) { initialExpression = BinaryOperation(initialExpression, index.get(integer)); } return initialExpression; } Function<BinaryOperator, Integer> precedence() { return new Function<BinaryOperator, Integer>() { @Override public Integer apply(BinaryOperator input) { return input.precedence(); } }; } Rule BinaryOperation(Rule expressionRule, List<BinaryOperator> operator) { return Sequence( expressionRule, parserContext().parser(SpacingParser.class).Spacing(), ZeroOrMore( parserContext().parser(PositionTrackerParser.class).PushPosition(), parserContext().parser(BinaryOperatorParser.class).BinaryOperator(operator), parserContext().parser(SpacingParser.class).Spacing(), expressionRule, push(new BinaryOperationExpression( parserContext().parser(PositionTrackerParser.class).pop(2), pop(2), parserContext().parser(BinaryOperatorParser.class).pop(1), pop() )) ) ); } }