public class AndExpression implements Expression<Boolean> {
	private final Expression left, right;

	public AndExpression(Expression left, Expression right) {
		this.left = left;
		this.right = right;
	}

	@Override
	public Boolean value(ExecContext ctx) {
		return ctx.getConverter().toBool(left.value(ctx)) && ctx.getConverter().toBool(right.value(ctx));
	}

	@Override
	public Expression[] children() {
		return new Expression[] { left, right };
	}
} public class ApplyExpression implements Expression {
	private final Expression value;
	private final Expression[] args;

	public ApplyExpression(Expression value, Expression... args) {
		this.value = value;
		this.args = args;
	}

	@Override
	public Object value(ExecContext ctx) {
		Object base = ctx.dereference(value);
		Object[] argValues = new Object[args.length];
		for (int i = 0; i < argValues.length; i++) {
			argValues[i] = ctx.dereference(args[i]);
		}
		try {
			return ctx.apply(base, argValues);
		} catch (NoSuchMethodException nsme) {
			// TODO log it. Think of error handling in general.
			return null;
		}
	}

	@Override
	public Expression[] children() {
		Expression[] ret = new Expression[args.length + 1];
		ret[0] = value;
		System.arraycopy(args, 0, ret, 1, args.length);
		return ret;
	}
} public class AssignExpression implements Expression {
	private final Expression base;
	private final String identifier;
	private final Expression value;

	public AssignExpression(Expression base, String identifier, Expression value) {
		this.base = base;
		this.identifier = identifier;
		this.value = value;
	}

	@Override
	public Object value(ExecContext ctx) {
		Object root = base == null ? null : base.value(ctx);
		if (base != null && root == null) {
			return null; // null.something always yields null
		}
		try {
			return ctx.setFieldValue(root, identifier, ctx.dereference(value));
		} catch (NoSuchFieldException nsfe) {
			return null;
		}
	}

	@Override
	public Expression[] children() {
		return new Expression[] { base, value };
	}
} public class BlockExpression implements Expression {
	private final StatementListExpression body;
	private final String[] varNames;

	public BlockExpression(String[] varNames, StatementListExpression body) {
		this.varNames = Arrays.copyOf(varNames, varNames.length);
		this.body = body;
	}

	@Override
	public Object value(final ExecContext ctx) {
		return new Block(varNames, body);
	}

	@Override
	public Expression[] children() {
		return new Expression[] { body };
	}
} public class CallExpression implements Expression {
	private final Expression base;
	private final String identifier;
	private final Expression[] args;

	public CallExpression(Expression base, String identifier, Expression... args) {
		this.base = base;
		this.identifier = identifier;
		this.args = args;
	}


	@Override
	public Object value(ExecContext ctx) {
		Object[] argValues = new Object[args.length];
		for (int i = 0; i < argValues.length; i++) {
			argValues[i] = ctx.dereference(args[i]);
		}
		Object root = base == null ? null : base.value(ctx);
		if (base != null && root == null) {
			return null; // null.something(...) always yields null
		}
		try {
			return ctx.callMethod(root, identifier, argValues);
		} catch (NoSuchMethodException nsme) {
			return null;
		}
	}

	@Override
	public Expression[] children() {
		Expression[] ret = new Expression[args.length + 1];
		ret[0] = base;
		System.arraycopy(args, 0, ret, 1, args.length);
		return ret;
	}
} public class ComparisonExpression implements Expression<Boolean> {
	private Expression left, right;

	public ComparisonExpression(Expression left, Expression right) {
		this.left = left;
		this.right = right;
	}

	@Override
	public Boolean value(ExecContext ctx) {
		Object leftValue = ctx.dereference(left);
		Object rightValue = ctx.dereference(right);
		if (leftValue instanceof Double || rightValue instanceof Double) {
			return ctx.getConverter().toDouble(leftValue) < ctx.getConverter().toDouble(rightValue);
		} else {
			return ctx.getConverter().toInt(leftValue) < ctx.getConverter().toInt(rightValue);
		}
	}

	@Override
	public Expression[] children() {
		return new Expression[] { left, right };
	}
} public class ConstantExpression implements Expression {
	private final Object constant;

	public ConstantExpression(Object constant) {
		this.constant = constant;
	}

	@Override
	public Object value(ExecContext ctx) {
		return constant;
	}

	@Override
	public Expression[] children() {
		return new Expression[0];
	}
} public class DivisionExpression implements Expression {
	private final Expression left, right;

	public DivisionExpression(Expression left, Expression right) {
		this.left = left;
		this.right = right;
	}

	@Override
	public Object value(ExecContext ctx) {
		Object l = ctx.dereference(left);
		Object r = ctx.dereference(right);
		if (l instanceof Double || r instanceof Double) {
			return ctx.getConverter().toDouble(l) / ctx.getConverter().toDouble(r);
		}
		return ctx.getConverter().toInt(l) / ctx.getConverter().toInt(r);
	}

	@Override
	public Expression[] children() {
		return new Expression[] { left, right };
	}
} public class EqualsExpression implements Expression<Boolean> {
	private Expression left, right;

	public EqualsExpression(Expression left, Expression right) {
		this.left = left;
		this.right = right;
	}

	@Override
	public Expression[] children() {
		return new Expression[] { left, right };
	}

	@Override
	public Boolean value(ExecContext ctx) {
		Object leftValue = ctx.dereference(left);
		Object rightValue = ctx.dereference(right);
		return leftValue == null ? rightValue == null : leftValue.equals(rightValue);
	}
} public class MinusExpression implements Expression {
	private final Expression left, right;

	public MinusExpression(Expression left, Expression right) {
		this.left = left;
		this.right = right;
	}

	@Override
	public Object value(ExecContext ctx) {
		Object l = ctx.dereference(left);
		Object r = ctx.dereference(right);
		if (l instanceof Double || r instanceof Double) {
			return ctx.getConverter().toDouble(l) - ctx.getConverter().toDouble(r);
		}
		return ctx.getConverter().toInt(l) - ctx.getConverter().toInt(r);
	}

	@Override
	public Expression[] children() {
		return new Expression[] { left, right };
	}
} public class MultiplicationExpression implements Expression {
	private final Expression left, right;

	public MultiplicationExpression(Expression left, Expression right) {
		this.left = left;
		this.right = right;
	}

	@Override
	public Object value(ExecContext ctx) {
		Object l = ctx.dereference(left);
		Object r = ctx.dereference(right);
		if (l instanceof Double || r instanceof Double) {
			return ctx.getConverter().toDouble(l) * ctx.getConverter().toDouble(r);
		}
		return ctx.getConverter().toInt(l) * ctx.getConverter().toInt(r);
	}

	@Override
	public Expression[] children() {
		return new Expression[] { left, right };
	}
} public class NegateExpression implements Expression {
	private final Expression expr;

	public NegateExpression(Expression expr) {
		this.expr = expr;
	}

	@Override
	public Object value(ExecContext ctx) {
		Object value = ctx.dereference(expr);
		if (value instanceof Integer) {
			return 0-((Integer)value);
		} else if (value instanceof Double) {
			return 0-((Double)value);
		}
		return 0;
	}

	@Override
	public Expression[] children() {
		return new Expression[] { expr };
	}
} public class NotExpression implements Expression<Boolean> {
	private final Expression expr;

	public NotExpression(Expression expr) {
		this.expr = expr;
	}

	@Override
	public Boolean value(ExecContext ctx) {
		return !ctx.getConverter().toBool(ctx.dereference(expr));
	}

	@Override
	public Expression[] children() {
		return new Expression[] { expr };
	}
} public class OrExpression implements Expression {
	private final Expression left, right;

	public OrExpression(Expression left, Expression right) {
		this.left = left;
		this.right = right;
	}

	@Override
	public Object value(ExecContext ctx) {
		Object leftVal = ctx.dereference(left);
		Object rightVal = ctx.dereference(right);
		if (ctx.getConverter().toBool(leftVal)) {
			return leftVal;
		} else {
			return rightVal;
		}
	}

	@Override
	public Expression[] children() {
		return new Expression[] { left, right };
	}
} public class PlusExpression implements Expression {
	private final Expression left, right;

	public PlusExpression(Expression left, Expression right) {
		this.left = left;
		this.right = right;
	}

	@Override
	public Object value(ExecContext ctx) {
		Object l = ctx.dereference(left);
		Object r = ctx.dereference(right);
		if (l instanceof String || r instanceof String) {
			return ctx.getConverter().toString(l) + ctx.getConverter().toString(r);
		} else if (l instanceof Double || r instanceof Double) {
			return ctx.getConverter().toDouble(l) + ctx.getConverter().toDouble(r);
		}
		return ctx.getConverter().toInt(l) + ctx.getConverter().toInt(r);
	}

	@Override
	public Expression[] children() {
		return new Expression[] { left, right };
	}
} public class ResourceExpression implements Expression {
	private final String pckg, type, name;

	public ResourceExpression(String pckg, String type, String name) {
		this.pckg = pckg;
		this.type = type;
		this.name = name;
	}

	@Override
	public Object value(ExecContext ctx) {
		try {
			return ctx.getResource(pckg, type, name);
		} catch (NoSuchFieldException _) {
			return null;
		}
	}

	@Override
	public Expression[] children() {
		return new Expression[0];
	}
} public class StatementListExpression implements Expression {
	private final List<Expression> statements;

	public StatementListExpression(List<Expression> statements) {
		this.statements = Collections.unmodifiableList(statements);
	}

	@Override
	public Object value(ExecContext ctx) {
		Object ret = null;
		for (Value e : statements) {
			ret = e.value(ctx);
		}
		return ret;
	}

	@Override
	public Expression[] children() {
		return statements.toArray(new Expression[statements.size()]);
	}
} public class TernaryExpression implements Expression {
	private final Expression expression, trueValue, falseValue;

	public TernaryExpression(Expression expression, Expression trueValue, Expression falseValue) {
		this.expression = expression;
		this.trueValue = trueValue;
		this.falseValue = falseValue;
	}

	@Override
	public Object value(ExecContext ctx) {
		return ctx.getConverter().toBool(ctx.dereference(expression))
				? ctx.dereference(trueValue) : ctx.dereference(falseValue);
	}

	@Override
	public Expression[] children() {
		return new Expression[] { expression, trueValue, falseValue };
	}
} public class VarExpression implements Expression {
	private final Expression base;
	private final String identifier;

	public VarExpression(Expression base, String identifier) {
		this.base = base;
		this.identifier = identifier;
	}

	@Override
	public Object value(ExecContext ctx) {
		Object root = base == null ? null : base.value(ctx);
		if (base != null && root == null) {
			return null; // null.something always yields null
		}
		try {
			return ctx.getFieldValue(root, identifier);
		} catch (NoSuchFieldException nsfe) {
			return null;
		}
	}

	@Override
	public Expression[] children() {
		return new Expression[] { base };
	}
} public class CharSupport {
	/** When converting ANTLR char and string literals, here is the
	 *  value set of escape chars.
	 */
	/* package */ static int ANTLRLiteralEscapedCharValue[] = new int[255];

	/** Given a char, we need to be able to show as an ANTLR literal.
	 */
	/* package */ static String ANTLRLiteralCharValueEscape[] = new String[255];

	static {
		ANTLRLiteralEscapedCharValue['n'] = '\n';
		ANTLRLiteralEscapedCharValue['r'] = '\r';
		ANTLRLiteralEscapedCharValue['t'] = '\t';
		ANTLRLiteralEscapedCharValue['b'] = '\b';
		ANTLRLiteralEscapedCharValue['f'] = '\f';
		ANTLRLiteralEscapedCharValue['\\'] = '\\';
		ANTLRLiteralEscapedCharValue['\''] = '\'';
		ANTLRLiteralEscapedCharValue['"'] = '"';
		ANTLRLiteralCharValueEscape['\n'] = "\\n";
		ANTLRLiteralCharValueEscape['\r'] = "\\r";
		ANTLRLiteralCharValueEscape['\t'] = "\\t";
		ANTLRLiteralCharValueEscape['\b'] = "\\b";
		ANTLRLiteralCharValueEscape['\f'] = "\\f";
		ANTLRLiteralCharValueEscape['\\'] = "\\\\";
		ANTLRLiteralCharValueEscape['\''] = "\\'";
	}

	/** Given char x or \t or \u1234 return the char value;
	 *  Unnecessary escapes like '\{' yield -1.
	 */
	public static int getCharValueFromCharInGrammarLiteral(String cstr) {
		switch ( cstr.length() ) {
			case 1 :
				// 'x'
				return cstr.charAt(0); // no escape char
			case 2 :
				if ( cstr.charAt(0)!='\\' ) return -1;
				// '\x'  (antlr lexer will catch invalid char)
				if ( Character.isDigit(cstr.charAt(1)) ) return -1;
				int escChar = cstr.charAt(1);
				int charVal = ANTLRLiteralEscapedCharValue[escChar];
				if ( charVal==0 ) return -1;
				return charVal;
			case 6 :
				// '\u1234'
				if ( !cstr.startsWith("\\u") ) return -1;
				String unicodeChars = cstr.substring(2, cstr.length());
				return Integer.parseInt(unicodeChars, 16);
			default :
				return -1;
		}
	}

	public static String getStringFromGrammarStringLiteral(String literal) {
		StringBuilder buf = new StringBuilder();
		int i = 1; // skip first quote
		int n = literal.length()-1; // skip last quote
		while ( i < n ) { // scan all but last quote
			int end = i+1;
			if ( literal.charAt(i) == '\\' ) {
				end = i+2;
				if ( (i+1)>=n ) break; // ignore spurious \ on end
				if ( literal.charAt(i+1) == 'u' ) end = i+6;
			}
			if ( end>n ) break;
			String esc = literal.substring(i, end);
			int c = getCharValueFromCharInGrammarLiteral(esc);
			if ( c==-1 ) { buf.append(esc); }
			else buf.append((char)c);
			i = end;
		}
		return buf.toString();
	}
}
import com.madisp.stupid.expr.AndExpression;
import com.madisp.stupid.expr.ApplyExpression;
import com.madisp.stupid.expr.AssignExpression;
import com.madisp.stupid.expr.BlockExpression;
import com.madisp.stupid.expr.CallExpression;
import com.madisp.stupid.expr.ComparisonExpression;
import com.madisp.stupid.expr.ConstantExpression;
import com.madisp.stupid.expr.DivisionExpression;
import com.madisp.stupid.expr.EqualsExpression;
import com.madisp.stupid.expr.MinusExpression;
import com.madisp.stupid.expr.MultiplicationExpression;
import com.madisp.stupid.expr.NegateExpression;
import com.madisp.stupid.expr.NotExpression;
import com.madisp.stupid.expr.OrExpression;
import com.madisp.stupid.expr.PlusExpression;
import com.madisp.stupid.expr.ResourceExpression;
import com.madisp.stupid.expr.StatementListExpression;
import com.madisp.stupid.expr.TernaryExpression;
import com.madisp.stupid.expr.VarExpression;
import com.madisp.stupid.gen.StupidBaseVisitor;
import com.madisp.stupid.gen.StupidLexer;
import com.madisp.stupid.gen.StupidParser;
import com.madisp.stupid.util.CharSupport;
import org.antlr.v4.runtime.ANTLRInputStream;
import org.antlr.v4.runtime.CommonTokenStream;
import org.antlr.v4.runtime.misc.NotNull;
import java.util.ArrayList;
import java.util.List;
			return visitExpr(ctx.center);
		} else if (ctx.BANG() != null) {
			return new NotExpression(visitExpr(ctx.center));
		} else if (ctx.MINUS() != null) {
			return new NegateExpression(visitExpr(ctx.center));
		} else if (ctx.EQUALS() != null && ctx.EQUALS().size() == 2) {
			return new EqualsExpression(visitExpr(ctx.left), visitExpr(ctx.right));
		} else if (ctx.LANGLE() != null) {
			return new ComparisonExpression(visitExpr(ctx.left), visitExpr(ctx.right));
		} else if (ctx.RANGLE() != null) {
			return new ComparisonExpression(visitExpr(ctx.right), visitExpr(ctx.left));
		} else if (ctx.var() != null) {
			Expression base = null;
			if (ctx.DOT() != null) {
				base = visitExpr(ctx.left);
			}
			return new VarExpression(base, ctx.var().IDENTIFIER().getText());
		} else if (ctx.call() != null) {
			StupidParser.ArgslistContext args = ctx.call().argslist();
			List<Expression> argsList = new ArrayList<Expression>();
			while (args != null) {
				argsList.add(visitExpr(args.expr()));
				args = args.argslist();
			}
			Expression base = null;
			if (ctx.DOT() != null) {
				base = visitExpr(ctx.left);
			}
			return new CallExpression(base, ctx.call().IDENTIFIER().getText(),
					argsList.toArray(new Expression[argsList.size()]));
		} else if (ctx.ASK() != null) {
			return new TernaryExpression(visitExpr(ctx.left), visitExpr(ctx.center), visitExpr(ctx.right));
		} else if (ctx.assign() != null) {
			Expression base = null;
			if (ctx.DOT() != null) {
				base = visitExpr(ctx.left);
			}
			return new AssignExpression(base, ctx.assign().IDENTIFIER().getText(), visitExpr(ctx.assign().expr()));
		}
		return super.visitExpr(ctx);
	}

	@Override
	public Expression visitValue(@NotNull StupidParser.ValueContext ctx) {
		if (ctx.bool() != null) {
			return visitBool(ctx.bool());
		} else if (ctx.str() != null) {
			return visitStr(ctx.str());
		} else if (ctx.num() != null) {
			return visitNum(ctx.num());
		} else if (ctx.nil() != null) {
			return visitNil(ctx.nil());
		} else if (ctx.block() != null) {
			return visitBlock(ctx.block());
		} else if (ctx.resource() != null) {
			return visitResource(ctx.resource());
		}
		return super.visitValue(ctx);
	}

	@Override
	public Expression visitBool(@NotNull StupidParser.BoolContext ctx) {
		if (ctx.TRUE() != null) {
			return new ConstantExpression(true);
		} else if (ctx.FALSE() != null) {
			return new ConstantExpression(false);
		}
		return super.visitBool(ctx);
	}

	@Override
	public Expression visitStr(@NotNull StupidParser.StrContext ctx) {
		return new ConstantExpression(CharSupport.getStringFromGrammarStringLiteral(ctx.getText()));
	}

	@Override
	public Expression visitNum(@NotNull StupidParser.NumContext ctx) {
		if (ctx.INT() != null) {
			return new ConstantExpression(Integer.parseInt(ctx.getText()));
		} else if (ctx.DOUBLE() != null) {
			return new ConstantExpression(Double.parseDouble(ctx.getText()));
		}
		return super.visitNum(ctx);
	}

	@Override
	public Expression visitNil(@NotNull StupidParser.NilContext ctx) {
		return new ConstantExpression(null);
	}

	@Override
	public Expression visitBlock(@NotNull StupidParser.BlockContext ctx) {
		StupidParser.VarlistContext vars = ctx.varlist();
		List<String> varsList = new ArrayList<String>();
		while (vars != null) {
			varsList.add(vars.IDENTIFIER().getText());
			vars = vars.varlist();
		}

		List<Expression> statements = new ArrayList<Expression>();
		StupidParser.StatementsContext xs = ctx.statements();
		while (xs != null) {
			statements.add(visitExpr(xs.expr()));
			xs = xs.statements();
		}

		return new BlockExpression(varsList.toArray(new String[varsList.size()]), new StatementListExpression(statements));
	}

	@Override
	public Expression visitResource(@NotNull StupidParser.ResourceContext ctx) {
		if (ctx.NULL() != null) {
			return new ConstantExpression(0);
		}
		String pckg = null;
		if (ctx.pckg() != null) {
			pckg = ctx.pckg().getText();
		}
		String type = ctx.type.getText();
		String name = ctx.name.getText();
		return new ResourceExpression(pckg, type, name);