package scratch;

import static org.junit.jupiter.api.Assertions.assertThrows;

import org.junit.jupiter.api.Test;

import scratch.Continuations.*;

public class Parser {
	@Test
	void parse() throws ParseException {
		evaluate("1");
		evaluate("1 + 2");
		evaluate("1+2");
		assertThrows(ParseException.class, () -> evaluate("1+"));
		evaluate("1 + 2 * 3");
		evaluate("1+2*3");
		evaluate("1 + (2 * 3)");
		evaluate("(1 + 2) * 3");
		evaluate("1 * 2 + 3");
		evaluate("(1 * 2) + 3");
		evaluate("1 * (2 + 3)");
		evaluate("a := 5 + 2; a * a + 3");
		assertThrows(IllegalArgumentException.class, () -> evaluate("a * a + 3"));
		evaluate("1_000_000");
		evaluate("0x1234");
		evaluate("0xBABE + 1_000");
		evaluate("7 - 5");
		evaluate("7 - (5 + 3 * 2)");
		evaluate("a := 5; 7 - a");
		evaluate("5^2");
		evaluate("(5^2)+2");
		assertThrows(ParseException.class, () -> evaluate("5^2+2"));
		assertThrows(ParseException.class, () -> evaluate("5^3"));
		assertThrows(ParseException.class, () -> evaluate("5^22"));
		evaluate("5^0x2");
	}

	public void evaluate(String input) throws ParseException {
		System.out.println("Raw: " + input);
		try {
			Expression<Integer> e = ExpressionParser.parse(input);
			System.out.println("Parsed: " + e.visit(new FancyExtendedToString<>()).apply(new StringBuilder()));
			System.out.println("Evaluated: " + e.visit(new FancyIntegerAlgebra()).apply(FunctionMap.empty()));
		} catch (ParseException e) {
			System.out.println("Error parsing: " + e.getMessage());
			throw e;
		} catch (IllegalArgumentException e) {
			System.out.println("Failed evaluating");
			throw e;
		}
	}
}
