Tutorial
Table of contents:Creating your own evaluators
Working with textual operators
Javaluator was initially designed to work with operators like +,*,=,!=,...
Some people had problems when trying to implement textual operators like OR, AND, NOT,... and using them in expressions like "type=PORT AND true". The default behaviour of AbstractEvaluator is to consider the OR in "PORT" like an operator.
There's a very simple way to overcome this issue: Override the tokenize method of AbstractEvaluator.
In this example, you can see that expression's tokens are separated each other by the blank character. The tokenize method can simply been implemented like that:
@Override protected Iteratortokenize(String expression) { return Arrays.asList(expression.split("\\s")).iterator(); }
Here is the complete sample code of an evaluator that uses textual operators:
package com.fathzer.soft.javaluator.examples; import java.util.Arrays; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import com.fathzer.soft.javaluator.AbstractEvaluator; import com.fathzer.soft.javaluator.Operator; import com.fathzer.soft.javaluator.Parameters; public class TextualOperatorsEvaluator extends AbstractEvaluator<Boolean> { /** The negate unary operator. */ public static final Operator NEGATE = new Operator("NOT", 1, Operator.Associativity.RIGHT, 3); /** The logical AND operator. */ private static final Operator AND = new Operator("AND", 2, Operator.Associativity.LEFT, 2); /** The logical OR operator. */ public static final Operator OR = new Operator("OR", 2, Operator.Associativity.LEFT, 1); private static final Parameters PARAMETERS; static { // Create the evaluator's parameters PARAMETERS = new Parameters(); // Add the supported operators PARAMETERS.add(AND); PARAMETERS.add(OR); PARAMETERS.add(NEGATE); } public TextualOperatorsEvaluator() { super(PARAMETERS); } @Override protected Boolean toValue(String literal, Object evaluationContext) { int index = literal.indexOf('='); if (index>=0) { String variable = literal.substring(0, index); String value = literal.substring(index+1); return value.equals(((Map<String, String>)evaluationContext).get(variable)); } else { return Boolean.valueOf(literal); } } @Override protected Boolean evaluate(Operator operator, Iterator<Boolean> operands, Object evaluationContext) { if (operator == NEGATE) { return !operands.next(); } else if (operator == OR) { Boolean o1 = operands.next(); Boolean o2 = operands.next(); return o1 || o2; } else if (operator == AND) { Boolean o1 = operands.next(); Boolean o2 = operands.next(); return o1 && o2; } else { return super.evaluate(operator, operands, evaluationContext); } } @Override protected Iterator<String> tokenize(String expression) { return Arrays.asList(expression.split("\\s")).iterator(); } public static void main(String[] args) { Map<String,String> variableToValue = new HashMap<>(); variableToValue.put("type", "PORT"); AbstractEvaluator<Boolean> evaluator = new TextualOperatorsEvaluator(); System.out.println ("type=PORT -> "+evaluator.evaluate("type=PORT", variableToValue)); System.out.println ("type=NORTH -> "+evaluator.evaluate("type=NORTH", variableToValue)); System.out.println ("type=PORT AND true -> "+evaluator.evaluate("type=PORT AND true", variableToValue)); } }
The output is
type=PORT -> true type=NORTH -> false type=PORT AND true -> true