Skip to content

Commit

Permalink
Allow completely control the instantiation of the binary expression c…
Browse files Browse the repository at this point in the history
…lass (#499)

Co-authored-by: Victor.Lalykin <[email protected]>
  • Loading branch information
vlalykin and Victor.Lalykin authored May 1, 2020
1 parent c906e51 commit bc13924
Show file tree
Hide file tree
Showing 5 changed files with 88 additions and 38 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@
*/
package com.mitchellbosecke.pebble.extension.core;

import static com.mitchellbosecke.pebble.operator.BinaryOperatorType.FILTER;
import static com.mitchellbosecke.pebble.operator.BinaryOperatorType.NORMAL;
import static com.mitchellbosecke.pebble.operator.BinaryOperatorType.TEST;

import com.mitchellbosecke.pebble.extension.AbstractExtension;
import com.mitchellbosecke.pebble.extension.Filter;
import com.mitchellbosecke.pebble.extension.Function;
Expand Down Expand Up @@ -55,7 +59,6 @@
import com.mitchellbosecke.pebble.tokenParser.ParallelTokenParser;
import com.mitchellbosecke.pebble.tokenParser.SetTokenParser;
import com.mitchellbosecke.pebble.tokenParser.TokenParser;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
Expand Down Expand Up @@ -97,26 +100,26 @@ public List<UnaryOperator> getUnaryOperators() {
@Override
public List<BinaryOperator> getBinaryOperators() {
List<BinaryOperator> operators = new ArrayList<>();
operators.add(new BinaryOperatorImpl("or", 10, OrExpression.class, Associativity.LEFT));
operators.add(new BinaryOperatorImpl("and", 15, AndExpression.class, Associativity.LEFT));
operators.add(new BinaryOperatorImpl("is", 20, PositiveTestExpression.class, Associativity.LEFT));
operators.add(new BinaryOperatorImpl("is not", 20, NegativeTestExpression.class, Associativity.LEFT));
operators.add(new BinaryOperatorImpl("contains", 20, ContainsExpression.class, Associativity.LEFT));
operators.add(new BinaryOperatorImpl("==", 30, EqualsExpression.class, Associativity.LEFT));
operators.add(new BinaryOperatorImpl("equals", 30, EqualsExpression.class, Associativity.LEFT));
operators.add(new BinaryOperatorImpl("!=", 30, NotEqualsExpression.class, Associativity.LEFT));
operators.add(new BinaryOperatorImpl(">", 30, GreaterThanExpression.class, Associativity.LEFT));
operators.add(new BinaryOperatorImpl("<", 30, LessThanExpression.class, Associativity.LEFT));
operators.add(new BinaryOperatorImpl(">=", 30, GreaterThanEqualsExpression.class, Associativity.LEFT));
operators.add(new BinaryOperatorImpl("<=", 30, LessThanEqualsExpression.class, Associativity.LEFT));
operators.add(new BinaryOperatorImpl("+", 40, AddExpression.class, Associativity.LEFT));
operators.add(new BinaryOperatorImpl("-", 40, SubtractExpression.class, Associativity.LEFT));
operators.add(new BinaryOperatorImpl("*", 60, MultiplyExpression.class, Associativity.LEFT));
operators.add(new BinaryOperatorImpl("/", 60, DivideExpression.class, Associativity.LEFT));
operators.add(new BinaryOperatorImpl("%", 60, ModulusExpression.class, Associativity.LEFT));
operators.add(new BinaryOperatorImpl("|", 100, FilterExpression.class, Associativity.LEFT));
operators.add(new BinaryOperatorImpl("~", 110, ConcatenateExpression.class, Associativity.LEFT));
operators.add(new BinaryOperatorImpl("..", 120, RangeExpression.class, Associativity.LEFT));
operators.add(new BinaryOperatorImpl("or", 10, OrExpression::new, NORMAL, Associativity.LEFT));
operators.add(new BinaryOperatorImpl("and", 15, AndExpression::new, NORMAL, Associativity.LEFT));
operators.add(new BinaryOperatorImpl("is", 20, PositiveTestExpression::new, TEST, Associativity.LEFT));
operators.add(new BinaryOperatorImpl("is not", 20, NegativeTestExpression::new, TEST, Associativity.LEFT));
operators.add(new BinaryOperatorImpl("contains", 20, ContainsExpression::new, NORMAL, Associativity.LEFT));
operators.add(new BinaryOperatorImpl("==", 30, EqualsExpression::new, NORMAL, Associativity.LEFT));
operators.add(new BinaryOperatorImpl("equals", 30, EqualsExpression::new, NORMAL, Associativity.LEFT));
operators.add(new BinaryOperatorImpl("!=", 30, NotEqualsExpression::new, NORMAL, Associativity.LEFT));
operators.add(new BinaryOperatorImpl(">", 30, GreaterThanExpression::new, NORMAL, Associativity.LEFT));
operators.add(new BinaryOperatorImpl("<", 30, LessThanExpression::new, NORMAL, Associativity.LEFT));
operators.add(new BinaryOperatorImpl(">=", 30, GreaterThanEqualsExpression::new, NORMAL, Associativity.LEFT));
operators.add(new BinaryOperatorImpl("<=", 30, LessThanEqualsExpression::new, NORMAL, Associativity.LEFT));
operators.add(new BinaryOperatorImpl("+", 40, AddExpression::new, NORMAL, Associativity.LEFT));
operators.add(new BinaryOperatorImpl("-", 40, SubtractExpression::new, NORMAL, Associativity.LEFT));
operators.add(new BinaryOperatorImpl("*", 60, MultiplyExpression::new, NORMAL, Associativity.LEFT));
operators.add(new BinaryOperatorImpl("/", 60, DivideExpression::new, NORMAL, Associativity.LEFT));
operators.add(new BinaryOperatorImpl("%", 60, ModulusExpression::new, NORMAL, Associativity.LEFT));
operators.add(new BinaryOperatorImpl("|", 100, FilterExpression::new, FILTER, Associativity.LEFT));
operators.add(new BinaryOperatorImpl("~", 110, ConcatenateExpression::new, NORMAL, Associativity.LEFT));
operators.add(new BinaryOperatorImpl("..", 120, RangeExpression::new, NORMAL, Associativity.LEFT));

return operators;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,9 @@ public interface BinaryOperator {

String getSymbol();

Class<? extends BinaryExpression<?>> getNodeClass();
BinaryExpression<?> getInstance();

BinaryOperatorType getType();

Associativity getAssociativity();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,24 +8,51 @@
*/
package com.mitchellbosecke.pebble.operator;

import com.mitchellbosecke.pebble.error.PebbleException;
import com.mitchellbosecke.pebble.node.expression.BinaryExpression;
import com.mitchellbosecke.pebble.node.expression.FilterExpression;
import com.mitchellbosecke.pebble.node.expression.NegativeTestExpression;
import com.mitchellbosecke.pebble.node.expression.PositiveTestExpression;
import java.util.function.Supplier;

public class BinaryOperatorImpl implements BinaryOperator {

private final int precedence;

private final String symbol;

private final Class<? extends BinaryExpression<?>> nodeClass;
private final Supplier<? extends BinaryExpression<?>> nodeSupplier;

private final BinaryOperatorType type;

private final Associativity associativity;

/**
* This constuctor left for backward compatibility with custom extensions
*/
public BinaryOperatorImpl(String symbol, int precedence,
Class<? extends BinaryExpression<?>> nodeClass,
Associativity associativity) {
this(symbol, precedence, () -> {
try {
return nodeClass.newInstance();
} catch (InstantiationException | IllegalAccessException e) {
throw new PebbleException(e, "Error instantiating class " + nodeClass.getName());
}
}, getDefaultType(nodeClass), associativity);
}

/**
* This constuctor allows you to completely control the instantiation of the expression class
*/
public BinaryOperatorImpl(String symbol, int precedence,
Supplier<? extends BinaryExpression<?>> nodeSupplier,
BinaryOperatorType type,
Associativity associativity) {
this.symbol = symbol;
this.precedence = precedence;
this.nodeClass = nodeClass;
this.nodeSupplier = nodeSupplier;
this.type = type;
this.associativity = associativity;
}

Expand All @@ -40,12 +67,28 @@ public String getSymbol() {
}

@Override
public Class<? extends BinaryExpression<?>> getNodeClass() {
return this.nodeClass;
public BinaryExpression<?> getInstance() {
return this.nodeSupplier.get();
}

@Override
public BinaryOperatorType getType() {
return this.type;
}

@Override
public Associativity getAssociativity() {
return this.associativity;
}

private static BinaryOperatorType getDefaultType(Class<? extends BinaryExpression<?>> nodeClass) {
if (FilterExpression.class.equals(nodeClass)) {
return BinaryOperatorType.FILTER;
} else if (PositiveTestExpression.class.equals(nodeClass) || NegativeTestExpression.class
.equals(nodeClass)) {
return BinaryOperatorType.TEST;
} else {
return BinaryOperatorType.NORMAL;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package com.mitchellbosecke.pebble.operator;

public enum BinaryOperatorType {
NORMAL, FILTER, TEST
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@
import com.mitchellbosecke.pebble.node.expression.ConcatenateExpression;
import com.mitchellbosecke.pebble.node.expression.ContextVariableExpression;
import com.mitchellbosecke.pebble.node.expression.Expression;
import com.mitchellbosecke.pebble.node.expression.FilterExpression;
import com.mitchellbosecke.pebble.node.expression.FilterInvocationExpression;
import com.mitchellbosecke.pebble.node.expression.FunctionOrMacroInvocationExpression;
import com.mitchellbosecke.pebble.node.expression.GetAttributeExpression;
Expand All @@ -34,13 +33,12 @@
import com.mitchellbosecke.pebble.node.expression.LiteralNullExpression;
import com.mitchellbosecke.pebble.node.expression.LiteralStringExpression;
import com.mitchellbosecke.pebble.node.expression.MapExpression;
import com.mitchellbosecke.pebble.node.expression.NegativeTestExpression;
import com.mitchellbosecke.pebble.node.expression.ParentFunctionExpression;
import com.mitchellbosecke.pebble.node.expression.PositiveTestExpression;
import com.mitchellbosecke.pebble.node.expression.TernaryExpression;
import com.mitchellbosecke.pebble.node.expression.UnaryExpression;
import com.mitchellbosecke.pebble.operator.Associativity;
import com.mitchellbosecke.pebble.operator.BinaryOperator;
import com.mitchellbosecke.pebble.operator.BinaryOperatorType;
import com.mitchellbosecke.pebble.operator.UnaryOperator;

import java.math.BigDecimal;
Expand Down Expand Up @@ -180,13 +178,12 @@ else if (token.test(Token.Type.PUNCTUATION, "{")) {

// the right hand expression of the FILTER operator is handled in a
// unique way
if (FilterExpression.class.equals(operator.getNodeClass())) {
if (operator.getType() == BinaryOperatorType.FILTER) {
expressionRight = this.parseFilterInvocationExpression();
}
// the right hand expression of TEST operators is handled in a
// unique way
else if (PositiveTestExpression.class.equals(operator.getNodeClass())
|| NegativeTestExpression.class.equals(operator.getNodeClass())) {
else if (operator.getType() == BinaryOperatorType.TEST) {
expressionRight = this.parseTestInvocationExpression();
} else {
/*
Expand All @@ -204,16 +201,16 @@ else if (PositiveTestExpression.class.equals(operator.getNodeClass())
* expression we are creating.
*/
BinaryExpression<?> finalExpression;
Class<? extends BinaryExpression<?>> operatorNodeClass = operator.getNodeClass();

try {
finalExpression = operatorNodeClass.newInstance();
finalExpression.setLineNumber(this.stream.current().getLineNumber());
} catch (InstantiationException | IllegalAccessException e) {
finalExpression = operator.getInstance();
} catch (RuntimeException e) {
throw new ParserException(e,
"Error instantiating operator node [" + operatorNodeClass.getName() + "]",
"Error instantiating operator node",
token.getLineNumber(), this.stream.getFilename());
}

finalExpression.setLineNumber(this.stream.current().getLineNumber());
finalExpression.setLeft(expression);
finalExpression.setRight(expressionRight);

Expand Down Expand Up @@ -578,7 +575,7 @@ public ArgumentsNode parseArguments(boolean isMacroDefinition) {
throw new ParserException(null,
"Positional arguments must be declared before any named arguments.",
this.stream.current()
.getLineNumber(),
.getLineNumber(),
this.stream.getFilename());
}
positionalArgs.add(new PositionalArgumentNode(argumentValue));
Expand Down

0 comments on commit bc13924

Please sign in to comment.