WarpPI/core/src/test/java/it/cavallium/warppi/math/rules/dsl/frontend/ParserTest.java

781 lines
23 KiB
Java

package it.cavallium.warppi.math.rules.dsl.frontend;
import it.cavallium.warppi.math.MathematicalSymbols;
import it.cavallium.warppi.math.rules.RuleType;
import it.cavallium.warppi.math.rules.dsl.DslError;
import it.cavallium.warppi.math.rules.dsl.Pattern;
import it.cavallium.warppi.math.rules.dsl.PatternRule;
import it.cavallium.warppi.math.rules.dsl.patterns.*;
import org.apache.commons.lang3.ObjectUtils;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import static it.cavallium.warppi.math.rules.dsl.frontend.TokenType.*;
import static org.junit.jupiter.api.Assertions.*;
class ParserTest {
private final List<DslError> errors = new ArrayList<>();
@BeforeEach
void setUp() {
errors.clear();
}
@Test
void noRules() {
final List<Token> tokens = Collections.singletonList(
new Token(EOF, "", 0)
);
final Parser parser = new Parser(tokens, errors::add);
assertEquals(Collections.emptyList(), parser.parse());
}
@Test
void multipleParseCalls() {
final List<Token> tokens = Collections.singletonList(
new Token(EOF, "", 0)
);
final Parser parser = new Parser(tokens, errors::add);
parser.parse();
assertThrows(IllegalStateException.class, parser::parse);
}
@Test
void validRuleMultipleReplacements() {
final List<Token> tokens = Arrays.asList(
new Token(REDUCTION, "reduction", 0),
new Token(IDENTIFIER, "TestRule_123", 10),
new Token(COLON, ":", 22),
new Token(IDENTIFIER, "x", 26),
new Token(PLUS, "+", 28),
new Token(IDENTIFIER, "y", 30),
new Token(TIMES, "*", 32),
new Token(IDENTIFIER, "z", 34),
new Token(EQUALS, "=", 36),
new Token(MINUS, "-", 38),
new Token(LEFT_PAREN, "(", 39),
new Token(IDENTIFIER, "a_123", 40),
new Token(PLUS_MINUS, "+-", 46),
new Token(NUMBER, "3", 49),
new Token(DIVIDE, "/", 51),
new Token(NUMBER, "2.2", 53),
new Token(RIGHT_PAREN, ")", 56),
new Token(ARROW, "->", 58),
new Token(LEFT_BRACKET, "[", 61),
new Token(IDENTIFIER, "x", 67),
new Token(POWER, "^", 68),
new Token(IDENTIFIER, "a_123", 69),
new Token(EQUALS, "=", 75),
new Token(COS, "cos", 77),
new Token(LEFT_PAREN, "(", 80),
new Token(PI, "pi", 81),
new Token(RIGHT_PAREN, ")", 83),
new Token(MINUS, "-", 85),
new Token(LOG, "log", 87),
new Token(LEFT_PAREN, "(", 90),
new Token(E, "e", 91),
new Token(COMMA, ",", 92),
new Token(E, "e", 94),
new Token(RIGHT_PAREN, ")", 95),
new Token(COMMA, ",", 96),
new Token(UNDEFINED, "undefined", 113),
new Token(COMMA, ",", 122),
new Token(RIGHT_BRACKET, "]", 138),
new Token(EOF, "", 140)
);
final Parser parser = new Parser(tokens, errors::add);
// x + y * z = -(a_123 +- 3 / 2.2)
final Pattern target = new EquationPattern(
new SumPattern(
new SubFunctionPattern("x"),
new MultiplicationPattern(
new SubFunctionPattern("y"),
new SubFunctionPattern("z")
)
),
new NegativePattern(new SumSubtractionPattern(
new SubFunctionPattern("a_123"),
new DivisionPattern(
new NumberPattern(new BigDecimal(3)),
new NumberPattern(new BigDecimal("2.2"))
)
))
);
// x^a_123 = cos(pi) - log(e, e)
final Pattern replacement1 = new EquationPattern(
new PowerPattern(
new SubFunctionPattern("x"),
new SubFunctionPattern("a_123")
),
new SubtractionPattern(
new CosinePattern(new ConstantPattern(MathematicalSymbols.PI)),
new LogarithmPattern(
new ConstantPattern(MathematicalSymbols.EULER_NUMBER),
new ConstantPattern(MathematicalSymbols.EULER_NUMBER)
)
)
);
final Pattern replacement2 = new UndefinedPattern();
final List<PatternRule> expected = Collections.singletonList(new PatternRule(
"TestRule_123",
RuleType.REDUCTION,
target,
replacement1,
replacement2
));
assertEquals(expected, parser.parse());
}
@Test
void validRuleNoReplacements() {
final List<Token> tokens = Arrays.asList(
new Token(EXISTENCE, "existence", 0),
new Token(IDENTIFIER, "test", 0),
new Token(COLON, ":", 0),
new Token(IDENTIFIER, "x", 0),
new Token(PLUS, "+", 0),
new Token(IDENTIFIER, "y", 0),
new Token(ARROW, "->", 0),
new Token(LEFT_BRACKET, "[", 0),
new Token(RIGHT_BRACKET, "]", 0),
new Token(EOF, "", 0)
);
final Parser parser = new Parser(tokens, errors::add);
final List<PatternRule> expected = Collections.singletonList(new PatternRule(
"test",
RuleType.EXISTENCE,
new SumPattern(
new SubFunctionPattern("x"),
new SubFunctionPattern("y")
)
));
assertEquals(expected, parser.parse());
}
@Test
void validRuleOneReplacement() {
final List<Token> tokens = Arrays.asList(
new Token(REDUCTION, "reduction", 0),
new Token(IDENTIFIER, "test", 0),
new Token(COLON, ":", 0),
new Token(MINUS, "-", 0),
new Token(IDENTIFIER, "x", 0),
new Token(TIMES, "*", 0),
new Token(IDENTIFIER, "x", 0),
new Token(ARROW, "->", 0),
new Token(MINUS, "-", 0),
new Token(IDENTIFIER, "x", 0),
new Token(POWER, "^", 0),
new Token(NUMBER, "2", 0),
new Token(EOF, "", 0)
);
final Parser parser = new Parser(tokens, errors::add);
final List<PatternRule> expected = Collections.singletonList(new PatternRule(
"test",
RuleType.REDUCTION,
new MultiplicationPattern(
new NegativePattern(new SubFunctionPattern("x")),
new SubFunctionPattern("x")
),
new NegativePattern(new PowerPattern(
new SubFunctionPattern("x"),
new NumberPattern(new BigDecimal(2))
))
));
assertEquals(expected, parser.parse());
}
@Test
void validRuleOneReplacementBrackets() {
final List<Token> tokens = Arrays.asList(
new Token(REDUCTION, "reduction", 0),
new Token(IDENTIFIER, "test", 0),
new Token(COLON, ":", 0),
new Token(NUMBER, "1", 0),
new Token(DIVIDE, "/", 0),
new Token(LEFT_PAREN, "(", 0),
new Token(IDENTIFIER, "x", 0),
new Token(TIMES, "*", 0),
new Token(IDENTIFIER, "x", 0),
new Token(RIGHT_PAREN, ")", 0),
new Token(ARROW, "->", 0),
new Token(LEFT_BRACKET, "[", 0),
new Token(IDENTIFIER, "x", 0),
new Token(POWER, "^", 0),
new Token(MINUS, "-", 0),
new Token(NUMBER, "2", 0),
new Token(RIGHT_BRACKET, "]", 0),
new Token(EOF, "", 0)
);
final Parser parser = new Parser(tokens, errors::add);
final List<PatternRule> expected = Collections.singletonList(new PatternRule(
"test",
RuleType.REDUCTION,
new DivisionPattern(
new NumberPattern(new BigDecimal(1)),
new MultiplicationPattern(
new SubFunctionPattern("x"),
new SubFunctionPattern("x")
)
),
new PowerPattern(
new SubFunctionPattern("x"),
new NegativePattern(
new NumberPattern(new BigDecimal(2))
)
)
));
assertEquals(expected, parser.parse());
}
@Test
void multipleValidRules() {
final List<Token> tokens = Arrays.asList(
new Token(REDUCTION, "reduction", 0),
new Token(IDENTIFIER, "test1", 0),
new Token(COLON, ":", 0),
new Token(PLUS, "+", 0),
new Token(IDENTIFIER, "x", 0),
new Token(ARROW, "->", 0),
new Token(IDENTIFIER, "x", 0),
new Token(EXPANSION, "expansion", 0),
new Token(IDENTIFIER, "test2", 0),
new Token(COLON, ":", 0),
new Token(IDENTIFIER, "x", 0),
new Token(ARROW, "->", 0),
new Token(MINUS, "-", 0),
new Token(MINUS, "-", 0),
new Token(IDENTIFIER, "x", 0),
new Token(CALCULATION, "calculation", 0),
new Token(IDENTIFIER, "test3", 0),
new Token(COLON, ":", 0),
new Token(NUMBER, "1", 0),
new Token(PLUS, "+", 0),
new Token(NUMBER, "1", 0),
new Token(ARROW, "->", 0),
new Token(NUMBER, "2", 0),
new Token(EOF, "", 0)
);
final Parser parser = new Parser(tokens, errors::add);
final List<PatternRule> expected = Arrays.asList(
new PatternRule(
"test1",
RuleType.REDUCTION,
new SubFunctionPattern("x"),
new SubFunctionPattern("x")
),
new PatternRule(
"test2",
RuleType.EXPANSION,
new SubFunctionPattern("x"),
new NegativePattern(new NegativePattern(new SubFunctionPattern("x")))
),
new PatternRule(
"test3",
RuleType.CALCULATION,
new SumPattern(
new NumberPattern(new BigDecimal(1)),
new NumberPattern(new BigDecimal(1))
),
new NumberPattern(new BigDecimal(2))
)
);
assertEquals(expected, parser.parse());
}
@Test
void subFunctionIdentifiers() {
final List<ReferenceEqualityToken> rule0x = new ArrayList<>();
final List<ReferenceEqualityToken> rule1x = new ArrayList<>();
final List<ReferenceEqualityToken> rule1y = new ArrayList<>();
final List<ReferenceEqualityToken> rule2x = new ArrayList<>();
final List<ReferenceEqualityToken> rule3x = new ArrayList<>();
final List<Token> tokens = Arrays.asList(
new Token(REDUCTION, "reduction", 0),
new Token(IDENTIFIER, "test1", 0),
new Token(COLON, ":", 0),
new Token(PLUS, "+", 0),
addIdentifierToken(rule0x, "x"),
new Token(ARROW, "->", 0),
addIdentifierToken(rule0x, "x"),
new Token(EXPANSION, "expansion", 0),
new Token(IDENTIFIER, "test2", 0),
new Token(COLON, ":", 0),
addIdentifierToken(rule1x, "x"),
new Token(POWER, "^", 0),
new Token(MINUS, "-", 0),
addIdentifierToken(rule1y, "y"),
new Token(ARROW, "->", 0),
new Token(NUMBER, "1", 0),
new Token(DIVIDE, "/", 0),
addIdentifierToken(rule1x, "x"),
new Token(POWER, "^", 0),
addIdentifierToken(rule1y, "y"),
// Rule with the same name (and type)
new Token(CALCULATION, "expansion", 0),
new Token(IDENTIFIER, "test2", 0),
new Token(COLON, ":", 0),
addIdentifierToken(rule2x, "x"),
new Token(ARROW, "->", 0),
addIdentifierToken(rule2x, "x"),
new Token(PLUS, "+", 0),
new Token(NUMBER, "0", 0),
// Identical rule
new Token(CALCULATION, "expansion", 0),
new Token(IDENTIFIER, "test2", 0),
new Token(COLON, ":", 0),
addIdentifierToken(rule3x, "x"),
new Token(ARROW, "->", 0),
addIdentifierToken(rule3x, "x"),
new Token(PLUS, "+", 0),
new Token(NUMBER, "0", 0),
new Token(EOF, "", 0)
);
final Parser parser = new Parser(tokens, errors::add);
final List<PatternRule> rules = parser.parse();
assertEquals(rule0x, getSubFunctionIdentifiers(parser, rules.get(0), "x"));
assertEquals(rule1x, getSubFunctionIdentifiers(parser, rules.get(1), "x"));
assertEquals(rule1y, getSubFunctionIdentifiers(parser, rules.get(1), "y"));
assertEquals(rule2x, getSubFunctionIdentifiers(parser, rules.get(2), "x"));
assertEquals(rule3x, getSubFunctionIdentifiers(parser, rules.get(3), "x"));
}
private static Token addIdentifierToken(final List<ReferenceEqualityToken> list, final String identifier) {
final Token token = new Token(IDENTIFIER, identifier, 0);
list.add(new ReferenceEqualityToken(token));
return token;
}
private static List<ReferenceEqualityToken> getSubFunctionIdentifiers(
final Parser parser,
final PatternRule rule,
final String subFunctionName
) {
final SubFunctionPattern exampleSubFunction = new SubFunctionPattern(subFunctionName);
final Stream<SubFunctionPattern> allSubFunctions = Stream.concat(
rule.getTarget().getSubFunctions(),
rule.getReplacements().stream().flatMap(Pattern::getSubFunctions)
);
return allSubFunctions
.filter(subFunc -> subFunc.equals(exampleSubFunction)) // Match the name without having access to it directly
.map(subFunc -> new ReferenceEqualityToken(
parser.getSubFunctionIdentifier(subFunc)
))
.collect(Collectors.toList());
}
private static class ReferenceEqualityToken {
private final Token token;
ReferenceEqualityToken(final Token token) {
this.token = token;
}
@Override
public boolean equals(final Object o) {
if (!(o instanceof ReferenceEqualityToken)) {
return false;
}
return this.token == ((ReferenceEqualityToken) o).token;
}
@Override
public String toString() {
return "ReferenceEqualityToken{" + ObjectUtils.identityToString(token) + '}';
}
}
// The EOF token is inserted by the lexer, therefore it can only be missing
// in case of programming errors, and not directly because of user input.
@Test
void missingEof() {
final List<Token> tokens = Arrays.asList(
new Token(EXISTENCE, "existence", 0),
new Token(IDENTIFIER, "test", 0),
new Token(COLON, ":", 0),
new Token(IDENTIFIER, "x", 0),
new Token(PLUS, "+", 0),
new Token(IDENTIFIER, "y", 0),
new Token(ARROW, "->", 0),
new Token(LEFT_BRACKET, "[", 0),
new Token(RIGHT_BRACKET, "]", 0)
);
final Parser parser = new Parser(tokens, errors::add);
assertThrows(RuntimeException.class, parser::parse);
}
@Test
void incompleteRule() {
final List<Token> tokens = Arrays.asList(
new Token(EXISTENCE, "existence", 0),
new Token(IDENTIFIER, "test", 0),
new Token(COLON, ":", 0),
new Token(IDENTIFIER, "x", 0),
new Token(PLUS, "+", 0),
new Token(IDENTIFIER, "y", 0),
new Token(ARROW, "->", 0),
new Token(EOF, "", 0)
);
final Parser parser = new Parser(tokens, errors::add);
assertTrue(parser.parse().isEmpty());
final List<DslError> expectedErrors = Collections.singletonList(new UnexpectedToken(
new Token(EOF, "", 0)
));
assertEquals(expectedErrors, errors);
}
@Test
void missingRuleType() {
final List<Token> tokens = Arrays.asList(
new Token(IDENTIFIER, "test", 0),
new Token(EOF, "", 0)
);
final Parser parser = new Parser(tokens, errors::add);
assertTrue(parser.parse().isEmpty());
final List<DslError> expectedErrors = Collections.singletonList(new UnexpectedToken(
new Token(IDENTIFIER, "test", 0),
REDUCTION, EXPANSION, CALCULATION, EXISTENCE
));
assertEquals(expectedErrors, errors);
}
@Test
void unexpectedTokenPrimary() {
final List<Token> tokens = Arrays.asList(
new Token(EXISTENCE, "existence", 0),
new Token(IDENTIFIER, "test", 0),
new Token(COLON, ":", 0),
new Token(IDENTIFIER, "x", 0),
new Token(PLUS, "+", 0),
new Token(CALCULATION, "calculation", 0),
new Token(ARROW, "->", 0),
new Token(LEFT_BRACKET, "[", 0),
new Token(RIGHT_BRACKET, "]", 0),
new Token(EOF, "", 0)
);
final Parser parser = new Parser(tokens, errors::add);
assertTrue(parser.parse().isEmpty());
final List<DslError> expectedErrors = Collections.singletonList(new UnexpectedToken(
new Token(CALCULATION, "calculation", 0)
));
assertEquals(expectedErrors, errors);
}
@Test
void missingRuleName() {
final List<Token> tokens = Arrays.asList(
new Token(REDUCTION, "reduction", 0),
new Token(COLON, ":", 0),
new Token(EOF, "", 0)
);
final Parser parser = new Parser(tokens, errors::add);
assertTrue(parser.parse().isEmpty());
final List<DslError> expectedErrors = Collections.singletonList(new UnexpectedToken(
new Token(COLON, ":", 0),
IDENTIFIER
));
assertEquals(expectedErrors, errors);
}
@Test
void missingColon() {
final List<Token> tokens = Arrays.asList(
new Token(REDUCTION, "reduction", 0),
new Token(IDENTIFIER, "test", 0),
new Token(IDENTIFIER, "x", 0),
new Token(ARROW, "->", 0),
new Token(IDENTIFIER, "x", 0),
new Token(EOF, "", 0)
);
final Parser parser = new Parser(tokens, errors::add);
assertTrue(parser.parse().isEmpty());
final List<DslError> expectedErrors = Collections.singletonList(new UnexpectedToken(
new Token(IDENTIFIER, "x", 0),
COLON
));
assertEquals(expectedErrors, errors);
}
@Test
void missingArrow() {
final List<Token> tokens = Arrays.asList(
new Token(REDUCTION, "reduction", 0),
new Token(IDENTIFIER, "test", 0),
new Token(COLON, ":", 0),
new Token(IDENTIFIER, "x", 0),
new Token(IDENTIFIER, "y", 0),
new Token(EOF, "", 0)
);
final Parser parser = new Parser(tokens, errors::add);
assertTrue(parser.parse().isEmpty());
final List<DslError> expectedErrors = Collections.singletonList(new UnexpectedToken(
new Token(IDENTIFIER, "y", 0),
ARROW
));
assertEquals(expectedErrors, errors);
}
@Test
void missingRightBracket() {
final List<Token> tokens = Arrays.asList(
new Token(REDUCTION, "reduction", 0),
new Token(IDENTIFIER, "test", 0),
new Token(COLON, ":", 0),
new Token(IDENTIFIER, "x", 0),
new Token(ARROW, "->", 0),
new Token(LEFT_BRACKET, "[", 0),
new Token(IDENTIFIER, "x", 0),
new Token(EOF, "", 0)
);
final Parser parser = new Parser(tokens, errors::add);
assertTrue(parser.parse().isEmpty());
final List<DslError> expectedErrors = Collections.singletonList(new UnexpectedToken(
new Token(EOF, "", 0),
RIGHT_BRACKET
));
assertEquals(expectedErrors, errors);
}
@Test
void missingOneArgFunctionLeftParen() {
final List<Token> tokens = Arrays.asList(
new Token(EXISTENCE, "existence", 0),
new Token(IDENTIFIER, "test", 0),
new Token(COLON, ":", 0),
new Token(SIN, "sin", 0),
new Token(IDENTIFIER, "x", 0),
new Token(RIGHT_PAREN, ")", 0),
new Token(ARROW, "->", 0),
new Token(LEFT_BRACKET, "[", 0),
new Token(RIGHT_BRACKET, "]", 0),
new Token(EOF, "", 0)
);
final Parser parser = new Parser(tokens, errors::add);
assertTrue(parser.parse().isEmpty());
final List<DslError> expectedErrors = Collections.singletonList(new UnexpectedToken(
new Token(IDENTIFIER, "x", 0),
LEFT_PAREN
));
assertEquals(expectedErrors, errors);
}
@Test
void missingOneArgFunctionRightParen() {
final List<Token> tokens = Arrays.asList(
new Token(EXISTENCE, "existence", 0),
new Token(IDENTIFIER, "test", 0),
new Token(COLON, ":", 0),
new Token(SIN, "sin", 0),
new Token(LEFT_PAREN, "(", 0),
new Token(IDENTIFIER, "x", 0),
new Token(ARROW, "->", 0),
new Token(LEFT_BRACKET, "[", 0),
new Token(RIGHT_BRACKET, "]", 0),
new Token(EOF, "", 0)
);
final Parser parser = new Parser(tokens, errors::add);
assertTrue(parser.parse().isEmpty());
final List<DslError> expectedErrors = Collections.singletonList(new UnexpectedToken(
new Token(ARROW, "->", 0),
RIGHT_PAREN
));
assertEquals(expectedErrors, errors);
}
@Test
void missingTwoArgFunctionLeftParen() {
final List<Token> tokens = Arrays.asList(
new Token(EXISTENCE, "existence", 0),
new Token(IDENTIFIER, "test", 0),
new Token(COLON, ":", 0),
new Token(LOG, "log", 0),
new Token(IDENTIFIER, "x", 0),
new Token(COMMA, ",", 0),
new Token(IDENTIFIER, "y", 0),
new Token(RIGHT_PAREN, ")", 0),
new Token(ARROW, "->", 0),
new Token(LEFT_BRACKET, "[", 0),
new Token(RIGHT_BRACKET, "]", 0),
new Token(EOF, "", 0)
);
final Parser parser = new Parser(tokens, errors::add);
assertTrue(parser.parse().isEmpty());
final List<DslError> expectedErrors = Collections.singletonList(new UnexpectedToken(
new Token(IDENTIFIER, "x", 0),
LEFT_PAREN
));
assertEquals(expectedErrors, errors);
}
@Test
void missingTwoArgFunctionComma() {
final List<Token> tokens = Arrays.asList(
new Token(EXISTENCE, "existence", 0),
new Token(IDENTIFIER, "test", 0),
new Token(COLON, ":", 0),
new Token(LOG, "log", 0),
new Token(LEFT_PAREN, "(", 0),
new Token(IDENTIFIER, "x", 0),
new Token(IDENTIFIER, "y", 0),
new Token(RIGHT_PAREN, ")", 0),
new Token(ARROW, "->", 0),
new Token(LEFT_BRACKET, "[", 0),
new Token(RIGHT_BRACKET, "]", 0),
new Token(EOF, "", 0)
);
final Parser parser = new Parser(tokens, errors::add);
assertTrue(parser.parse().isEmpty());
final List<DslError> expectedErrors = Collections.singletonList(new UnexpectedToken(
new Token(IDENTIFIER, "y", 0),
COMMA
));
assertEquals(expectedErrors, errors);
}
@Test
void missingTwoArgFunctionRightParen() {
final List<Token> tokens = Arrays.asList(
new Token(EXISTENCE, "existence", 0),
new Token(IDENTIFIER, "test", 0),
new Token(COLON, ":", 0),
new Token(LOG, "log", 0),
new Token(LEFT_PAREN, "(", 0),
new Token(IDENTIFIER, "x", 0),
new Token(COMMA, ",", 0),
new Token(IDENTIFIER, "y", 0),
new Token(ARROW, "->", 0),
new Token(LEFT_BRACKET, "[", 0),
new Token(RIGHT_BRACKET, "]", 0),
new Token(EOF, "", 0)
);
final Parser parser = new Parser(tokens, errors::add);
assertTrue(parser.parse().isEmpty());
final List<DslError> expectedErrors = Collections.singletonList(new UnexpectedToken(
new Token(ARROW, "->", 0),
RIGHT_PAREN
));
assertEquals(expectedErrors, errors);
}
@Test
void missingExpressionRightParen() {
final List<Token> tokens = Arrays.asList(
new Token(EXISTENCE, "existence", 0),
new Token(IDENTIFIER, "test", 0),
new Token(COLON, ":", 0),
new Token(LEFT_PAREN, "(", 0),
new Token(IDENTIFIER, "x", 0),
new Token(ARROW, "->", 0),
new Token(LEFT_BRACKET, "[", 0),
new Token(RIGHT_BRACKET, "]", 0),
new Token(EOF, "", 0)
);
final Parser parser = new Parser(tokens, errors::add);
assertTrue(parser.parse().isEmpty());
final List<DslError> expectedErrors = Collections.singletonList(new UnexpectedToken(
new Token(ARROW, "->", 0),
RIGHT_PAREN
));
assertEquals(expectedErrors, errors);
}
@Test
void recoveryToNextRule() {
final List<Token> tokens = Arrays.asList(
new Token(REDUCTION, "reduction", 0),
new Token(IDENTIFIER, "test1", 0),
new Token(COLON, ":", 0),
new Token(IDENTIFIER, "x", 0),
new Token(TIMES, "+", 0),
new Token(ARROW, "->", 0),
new Token(IDENTIFIER, "x", 0),
new Token(EXPANSION, "expansion", 0),
new Token(IDENTIFIER, "test2", 0),
new Token(IDENTIFIER, "x", 0),
new Token(ARROW, "->", 0),
new Token(MINUS, "-", 0),
new Token(MINUS, "-", 0),
new Token(IDENTIFIER, "x", 0),
new Token(CALCULATION, "calculation", 0),
new Token(IDENTIFIER, "test3", 0),
new Token(COLON, ":", 0),
new Token(NUMBER, "1", 0),
new Token(PLUS, "+", 0),
new Token(NUMBER, "1", 0),
new Token(ARROW, "->", 0),
new Token(NUMBER, "2", 0),
new Token(EOF, "", 0)
);
final Parser parser = new Parser(tokens, errors::add);
final List<PatternRule> expectedRules = Collections.singletonList(new PatternRule(
"test3",
RuleType.CALCULATION,
new SumPattern(
new NumberPattern(new BigDecimal(1)),
new NumberPattern(new BigDecimal(1))
),
new NumberPattern(new BigDecimal(2))
));
assertEquals(expectedRules, parser.parse());
final List<DslError> expectedErrors = Arrays.asList(
new UnexpectedToken(new Token(ARROW, "->", 0)),
new UnexpectedToken(new Token(IDENTIFIER, "x", 0), COLON)
);
assertEquals(expectedErrors, errors);
}
}