package openmods.calc;
import java.util.List;
import openmods.calc.parsing.AstCompiler;
import openmods.calc.parsing.DefaultExprNodeFactory;
import openmods.calc.parsing.IAstParser;
import openmods.calc.parsing.ICompilerState;
import openmods.calc.parsing.IExprNode;
import openmods.calc.parsing.PrefixParser;
import openmods.calc.parsing.Token;
import org.junit.Test;
public class PrefixCompilerTest extends CalcTestUtils {
public final OperatorDictionary<String> operators = new OperatorDictionary<String>();
{
operators.registerBinaryOperator(PLUS);
operators.registerBinaryOperator(MINUS);
operators.registerBinaryOperator(ASSIGN);
operators.registerUnaryOperator(UNARY_NEG);
operators.registerUnaryOperator(UNARY_MINUS);
operators.registerDefaultOperator(DEFAULT);
}
private static final Token CLOSE_LIST = rightBracket("]");
private static final Token OPEN_LIST = leftBracket("[");
public static final String SYMBOL_LIST = "list";
public static class TestBracketNode implements IExprNode<String> {
private final List<IExprNode<String>> children;
public TestBracketNode(List<IExprNode<String>> children) {
this.children = children;
}
@Override
public void flatten(List<IExecutable<String>> output) {
for (IExprNode<String> child : children)
child.flatten(output);
output.add(call(SYMBOL_LIST, children.size()));
}
@Override
public Iterable<IExprNode<String>> getChildren() {
return children;
}
}
private final ICompilerState<String> testState = new TestCompilerState() {
@Override
public IAstParser<String> getParser() {
return new PrefixParser<String>(operators, new DefaultExprNodeFactory<String>(VALUE_PARSER) {
@Override
public IExprNode<String> createBracketNode(String openingBracket, String closingBracket, List<IExprNode<String>> children) {
return new TestBracketNode(children);
}
});
}
};
private CompilerResultTester given(Token... inputs) {
return new CompilerResultTester(new AstCompiler<String>(testState), inputs);
}
@Test
public void testSingleExpressions() {
given(dec("12")).expect(c("12"));
given(string("a")).expect(c("a"));
given(symbol("a")).expect(get("a"));
}
@Test
public void testSymbolCall() {
given(LEFT_BRACKET, symbol("a"), RIGHT_BRACKET).expect(call("a", 0));
given(LEFT_BRACKET, symbol("a"), dec("12"), RIGHT_BRACKET).expect(c("12"), call("a", 1));
given(LEFT_BRACKET, symbol("a"), dec("12"), dec("34"), RIGHT_BRACKET).expect(c("12"), c("34"), call("a", 2));
}
@Test
public void testSymbolAsArg() {
given(LEFT_BRACKET, symbol("a"), symbol("b"), RIGHT_BRACKET).expect(get("b"), call("a", 1));
given(LEFT_BRACKET, symbol("a"), dec("12"), symbol("b"), RIGHT_BRACKET).expect(c("12"), get("b"), call("a", 2));
given(LEFT_BRACKET, symbol("a"), symbol("b"), dec("12"), RIGHT_BRACKET).expect(get("b"), c("12"), call("a", 2));
}
@Test
public void testNestedSymbolCall() {
given(LEFT_BRACKET, symbol("a"), dec("12"), LEFT_BRACKET, symbol("b"), dec("34"), RIGHT_BRACKET, RIGHT_BRACKET).expect(c("12"), c("34"), call("b", 1), call("a", 2));
given(LEFT_BRACKET, symbol("a"), LEFT_BRACKET, symbol("b"), dec("12"), RIGHT_BRACKET, dec("34"), RIGHT_BRACKET).expect(c("12"), call("b", 1), c("34"), call("a", 2));
}
@Test
public void testSquareBrackets() {
given(OPEN_LIST, CLOSE_LIST).expect(call(SYMBOL_LIST, 0));
given(OPEN_LIST, dec("12"), CLOSE_LIST).expect(c("12"), call(SYMBOL_LIST, 1));
given(OPEN_LIST, dec("12"), dec("34"), CLOSE_LIST).expect(c("12"), c("34"), call(SYMBOL_LIST, 2));
}
@Test
public void testSymbolInSquareBrackets() {
given(OPEN_LIST, symbol("a"), CLOSE_LIST).expect(get("a"), call(SYMBOL_LIST, 1));
given(OPEN_LIST, dec("12"), symbol("a"), CLOSE_LIST).expect(c("12"), get("a"), call(SYMBOL_LIST, 2));
given(OPEN_LIST, symbol("a"), dec("12"), CLOSE_LIST).expect(get("a"), c("12"), call(SYMBOL_LIST, 2));
}
@Test
public void testMixedBrackets() {
given(LEFT_BRACKET, symbol("print"), OPEN_LIST, dec("12"), CLOSE_LIST, RIGHT_BRACKET).expect(c("12"), call(SYMBOL_LIST, 1), call("print", 1));
given(OPEN_LIST, LEFT_BRACKET, symbol("print"), dec("12"), RIGHT_BRACKET, CLOSE_LIST).expect(c("12"), call("print", 1), call(SYMBOL_LIST, 1));
}
@Test
public void testCommaWhitespace() {
given(LEFT_BRACKET, symbol("a"), dec("12"), dec("34"), RIGHT_BRACKET).expect(c("12"), c("34"), call("a", 2));
given(LEFT_BRACKET, symbol("a"), COMMA, dec("12"), dec("34"), RIGHT_BRACKET).expect(c("12"), c("34"), call("a", 2));
given(LEFT_BRACKET, symbol("a"), dec("12"), COMMA, dec("34"), RIGHT_BRACKET).expect(c("12"), c("34"), call("a", 2));
given(OPEN_LIST, symbol("a"), COMMA, dec("12"), COMMA, dec("34"), CLOSE_LIST).expect(get("a"), c("12"), c("34"), call(SYMBOL_LIST, 3));
given(LEFT_BRACKET, OP_PLUS, dec("12"), COMMA, dec("34"), RIGHT_BRACKET).expect(c("12"), c("34"), PLUS);
}
@Test
public void testUnaryOperator() {
given(LEFT_BRACKET, OP_MINUS, dec("12"), RIGHT_BRACKET).expect(c("12"), UNARY_MINUS);
given(LEFT_BRACKET, OP_NEG, dec("12"), RIGHT_BRACKET).expect(c("12"), UNARY_NEG);
}
@Test
public void testUnaryOperatorWithNestedArgs() {
given(LEFT_BRACKET, OP_MINUS, LEFT_BRACKET, OP_MINUS, dec("12"), RIGHT_BRACKET, RIGHT_BRACKET).expect(c("12"), UNARY_MINUS, UNARY_MINUS);
given(LEFT_BRACKET, OP_MINUS, OPEN_LIST, dec("12"), dec("34"), CLOSE_LIST, RIGHT_BRACKET).expect(c("12"), c("34"), call(SYMBOL_LIST, 2), UNARY_MINUS);
}
@Test
public void testBinaryOperatorWithNestedArgs() {
given(LEFT_BRACKET, OP_MINUS, LEFT_BRACKET, OP_MINUS, dec("12"), RIGHT_BRACKET, dec("34"), RIGHT_BRACKET).expect(c("12"), UNARY_MINUS, c("34"), MINUS);
given(LEFT_BRACKET, OP_MINUS, LEFT_BRACKET, symbol("a"), dec("34"), RIGHT_BRACKET, OPEN_LIST, dec("56"), CLOSE_LIST, RIGHT_BRACKET).expect(c("34"), call("a", 1), c("56"), call(SYMBOL_LIST, 1), MINUS);
}
@Test
public void testBinaryLeftAssociativeOperator() {
given(LEFT_BRACKET, OP_MINUS, dec("12"), dec("34"), RIGHT_BRACKET).expect(c("12"), c("34"), MINUS);
given(LEFT_BRACKET, OP_MINUS, dec("12"), dec("34"), dec("56"), RIGHT_BRACKET).expect(c("12"), c("34"), MINUS, c("56"), MINUS);
given(LEFT_BRACKET, OP_MINUS, dec("12"), dec("34"), dec("56"), dec("78"), RIGHT_BRACKET).expect(c("12"), c("34"), MINUS, c("56"), MINUS, c("78"), MINUS);
}
@Test
public void testBinaryRightAssociativeOperator() {
given(LEFT_BRACKET, OP_ASSIGN, dec("12"), dec("34"), RIGHT_BRACKET).expect(c("12"), c("34"), ASSIGN);
given(LEFT_BRACKET, OP_ASSIGN, dec("12"), dec("34"), dec("56"), RIGHT_BRACKET).expect(c("12"), c("34"), c("56"), ASSIGN, ASSIGN);
given(LEFT_BRACKET, OP_ASSIGN, dec("12"), dec("34"), dec("56"), dec("78"), RIGHT_BRACKET).expect(c("12"), c("34"), c("56"), c("78"), ASSIGN, ASSIGN, ASSIGN);
}
@Test
public void testValueModifierQuote() {
given(QUOTE_MODIFIER, dec("12")).expect(OPEN_ROOT_QUOTE_M, valueMarker("12"), CLOSE_ROOT_QUOTE_M);
given(QUOTE_MODIFIER, string("abc")).expect(OPEN_ROOT_QUOTE_M, valueMarker("abc"), CLOSE_ROOT_QUOTE_M);
}
@Test
public void testValueSymbolQuote() {
given(LEFT_BRACKET, QUOTE_SYMBOL, dec("12"), RIGHT_BRACKET).expect(OPEN_ROOT_QUOTE_S, valueMarker("12"), CLOSE_ROOT_QUOTE_S);
given(LEFT_BRACKET, QUOTE_SYMBOL, string("abc"), RIGHT_BRACKET).expect(OPEN_ROOT_QUOTE_S, valueMarker("abc"), CLOSE_ROOT_QUOTE_S);
}
@Test
public void testNestedEmptyModifierQuote() {
given(QUOTE_MODIFIER, LEFT_BRACKET, RIGHT_BRACKET).expect(OPEN_ROOT_QUOTE_M, OPEN_QUOTE, CLOSE_QUOTE, CLOSE_ROOT_QUOTE_M);
}
@Test
public void testNestedEmptySymbolQuote() {
given(LEFT_BRACKET, QUOTE_SYMBOL, LEFT_BRACKET, RIGHT_BRACKET, RIGHT_BRACKET).expect(OPEN_ROOT_QUOTE_S, OPEN_QUOTE, CLOSE_QUOTE, CLOSE_ROOT_QUOTE_S);
}
@Test
public void testNestedValueModifierQuote() {
given(QUOTE_MODIFIER, LEFT_BRACKET, dec("12"), RIGHT_BRACKET).expect(OPEN_ROOT_QUOTE_M, OPEN_QUOTE, valueMarker("12"), CLOSE_QUOTE, CLOSE_ROOT_QUOTE_M);
given(QUOTE_MODIFIER, LEFT_BRACKET, dec("12"), oct("34"), RIGHT_BRACKET).expect(OPEN_ROOT_QUOTE_M, OPEN_QUOTE, valueMarker("12"), valueMarker("34"), CLOSE_QUOTE, CLOSE_ROOT_QUOTE_M);
}
@Test
public void testNestedValueSymbolQuote() {
given(LEFT_BRACKET, QUOTE_SYMBOL, LEFT_BRACKET, dec("12"), RIGHT_BRACKET, RIGHT_BRACKET).expect(OPEN_ROOT_QUOTE_S, OPEN_QUOTE, valueMarker("12"), CLOSE_QUOTE, CLOSE_ROOT_QUOTE_S);
given(LEFT_BRACKET, QUOTE_SYMBOL, LEFT_BRACKET, dec("12"), oct("34"), RIGHT_BRACKET, RIGHT_BRACKET).expect(OPEN_ROOT_QUOTE_S, OPEN_QUOTE, valueMarker("12"), valueMarker("34"), CLOSE_QUOTE, CLOSE_ROOT_QUOTE_S);
}
@Test
public void testRawValueQuote() {
given(QUOTE_MODIFIER, symbol("12")).expect(OPEN_ROOT_QUOTE_M, rawValueMarker(symbol("12")), CLOSE_ROOT_QUOTE_M);
given(QUOTE_MODIFIER, OP_PLUS).expect(OPEN_ROOT_QUOTE_M, rawValueMarker(OP_PLUS), CLOSE_ROOT_QUOTE_M);
given(QUOTE_MODIFIER, mod(".")).expect(OPEN_ROOT_QUOTE_M, rawValueMarker(mod(".")), CLOSE_ROOT_QUOTE_M);
}
@Test
public void testNestedRawValueQuote() {
given(QUOTE_MODIFIER, LEFT_BRACKET, symbol("12"), RIGHT_BRACKET).expect(OPEN_ROOT_QUOTE_M, OPEN_QUOTE, rawValueMarker(symbol("12")), CLOSE_QUOTE, CLOSE_ROOT_QUOTE_M);
given(QUOTE_MODIFIER, LEFT_BRACKET, symbol("12"), OP_PLUS, RIGHT_BRACKET).expect(OPEN_ROOT_QUOTE_M, OPEN_QUOTE, rawValueMarker(symbol("12")), rawValueMarker(OP_PLUS), CLOSE_QUOTE, CLOSE_ROOT_QUOTE_M);
given(QUOTE_MODIFIER, LEFT_BRACKET, symbol("12"), mod("."), OP_PLUS, RIGHT_BRACKET).expect(OPEN_ROOT_QUOTE_M, OPEN_QUOTE, rawValueMarker(symbol("12")), rawValueMarker(mod(".")), rawValueMarker(OP_PLUS), CLOSE_QUOTE, CLOSE_ROOT_QUOTE_M);
}
@Test
public void testDoubleNestedQuote() {
given(QUOTE_MODIFIER, LEFT_BRACKET, LEFT_BRACKET, RIGHT_BRACKET, RIGHT_BRACKET).expect(OPEN_ROOT_QUOTE_M, OPEN_QUOTE, OPEN_QUOTE, CLOSE_QUOTE, CLOSE_QUOTE, CLOSE_ROOT_QUOTE_M);
given(QUOTE_MODIFIER, LEFT_BRACKET, LEFT_BRACKET, dec("12"), RIGHT_BRACKET, RIGHT_BRACKET).expect(OPEN_ROOT_QUOTE_M, OPEN_QUOTE, OPEN_QUOTE, valueMarker("12"), CLOSE_QUOTE, CLOSE_QUOTE, CLOSE_ROOT_QUOTE_M);
given(QUOTE_MODIFIER, LEFT_BRACKET, dec("0"), LEFT_BRACKET, dec("12"), RIGHT_BRACKET, dec("3"), RIGHT_BRACKET).expect(OPEN_ROOT_QUOTE_M, OPEN_QUOTE, valueMarker("0"), OPEN_QUOTE, valueMarker("12"), CLOSE_QUOTE, valueMarker("3"), CLOSE_QUOTE, CLOSE_ROOT_QUOTE_M);
}
@Test
public void testModifierQuoteAsArg() {
given(LEFT_BRACKET, symbol("test"), QUOTE_MODIFIER, dec("12"), RIGHT_BRACKET).expect(OPEN_ROOT_QUOTE_M, valueMarker("12"), CLOSE_ROOT_QUOTE_M, call("test", 1));
given(LEFT_BRACKET, symbol("test"), QUOTE_MODIFIER, symbol("12"), dec("34"), RIGHT_BRACKET).expect(OPEN_ROOT_QUOTE_M, rawValueMarker(symbol("12")), CLOSE_ROOT_QUOTE_M, c("34"), call("test", 2));
}
@Test
public void testSymboQuoteAsArg() {
given(LEFT_BRACKET, symbol("test"), LEFT_BRACKET, QUOTE_SYMBOL, dec("12"), RIGHT_BRACKET, RIGHT_BRACKET).expect(OPEN_ROOT_QUOTE_S, valueMarker("12"), CLOSE_ROOT_QUOTE_S, call("test", 1));
given(LEFT_BRACKET, symbol("test"), LEFT_BRACKET, QUOTE_SYMBOL, symbol("12"), RIGHT_BRACKET, dec("34"), RIGHT_BRACKET).expect(OPEN_ROOT_QUOTE_S, rawValueMarker(symbol("12")), CLOSE_ROOT_QUOTE_S, c("34"), call("test", 2));
}
@Test
public void testNestedQuoteAsArg() {
given(LEFT_BRACKET, symbol("test"), QUOTE_MODIFIER, LEFT_BRACKET, dec("12"), RIGHT_BRACKET, RIGHT_BRACKET).expect(OPEN_ROOT_QUOTE_M, OPEN_QUOTE, valueMarker("12"), CLOSE_QUOTE, CLOSE_ROOT_QUOTE_M, call("test", 1));
given(LEFT_BRACKET, symbol("test"), QUOTE_MODIFIER, LEFT_BRACKET, dec("12"), RIGHT_BRACKET, dec("34"), RIGHT_BRACKET).expect(OPEN_ROOT_QUOTE_M, OPEN_QUOTE, valueMarker("12"), CLOSE_QUOTE, CLOSE_ROOT_QUOTE_M, c("34"), call("test", 2));
given(LEFT_BRACKET, symbol("test"), QUOTE_MODIFIER, LEFT_BRACKET, dec("12"), RIGHT_BRACKET, LEFT_BRACKET, symbol("sqrt"), dec("34"), RIGHT_BRACKET, RIGHT_BRACKET).expect(OPEN_ROOT_QUOTE_M, OPEN_QUOTE, valueMarker("12"), CLOSE_QUOTE, CLOSE_ROOT_QUOTE_M, c("34"), call("sqrt", 1), call("test", 2));
}
@Test
public void testExpressionOnFirstPosition() {
given(LEFT_BRACKET, LEFT_BRACKET, OP_PLUS, dec("12"), dec("34"), RIGHT_BRACKET, dec("56"), dec("78"), RIGHT_BRACKET).expect(c("12"), c("34"), PLUS, c("56"), c("78"), call(SYMBOL_LIST, 2, 1), DEFAULT);
given(LEFT_BRACKET, LEFT_BRACKET, symbol("test"), RIGHT_BRACKET, dec("12"), dec("34"), RIGHT_BRACKET).expect(call("test", 0, 1), c("12"), c("34"), call(SYMBOL_LIST, 2, 1), DEFAULT);
}
@Test
public void testModifierOnFirstPosition() {
given(LEFT_BRACKET, QUOTE_MODIFIER, LEFT_BRACKET, symbol("test"), RIGHT_BRACKET, dec("12"), dec("34"), RIGHT_BRACKET).expect(OPEN_ROOT_QUOTE_M, OPEN_QUOTE, rawValueMarker(symbol("test")), CLOSE_QUOTE, CLOSE_ROOT_QUOTE_M, c("12"), c("34"), call(SYMBOL_LIST, 2, 1), DEFAULT);
}
@Test
public void testValueOnFirstPosition() {
// I'm not sure if it's good idea, but it's side-effect of default op. Without this there wouldn't be 'apply' synctatic sugar
given(LEFT_BRACKET, dec("5"), symbol("I"), RIGHT_BRACKET).expect(c("5"), get("I"), call(SYMBOL_LIST, 1, 1), DEFAULT);
}
}