package nebula.lang; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import junit.framework.TestCase; import org.antlr.runtime.ANTLRStringStream; import org.antlr.runtime.CommonTokenStream; import org.antlr.runtime.RecognitionException; import org.objectweb.asm.ClassWriter; import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.Opcodes; public class NebulaParser_Expr_SimpleTest extends TestCase { TypeLoaderForTest compiler; @Override protected void setUp() throws Exception { compiler = new TypeLoaderForTest(new SystemTypeLoader()); } class Complier extends ClassLoader implements Opcodes { /* * Returns the byte code of an Expression class corresponding to this * expression. */ byte[] compile(final String name, final Expr<?> expr, CompilerContext context) { // class header ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS); cw.visit(V1_1, ACC_PUBLIC, name, null, "java/lang/Object", new String[] { ExpressionForSimpleTest.class.getName().replace('.', '/') }); // default public constructor MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null); mv.visitVarInsn(ALOAD, 0); mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V"); mv.visitInsn(RETURN); mv.visitMaxs(1, 1); mv.visitEnd(); // eval method mv = cw.visitMethod(ACC_PUBLIC, "eval", "(JJ)J", null, null); expr.compile(new AsmCompiler(cw, mv)); mv.visitInsn(LRETURN); // max stack and max locals automatically computed mv.visitMaxs(0, 0); mv.visitEnd(); return cw.toByteArray(); } /* * Returns the byte code of an Expression class corresponding to this * expression. */ byte[] compileBoolean(final String name, final Expr<?> expr, CompilerContext context) { // class header ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS); cw.visit(V1_1, ACC_PUBLIC, name, null, "java/lang/Object", new String[] { ExpressionForSimpleTestBoolean.class.getName().replace('.', '/') }); // default public constructor MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null); mv.visitVarInsn(ALOAD, 0); mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V"); mv.visitInsn(RETURN); mv.visitMaxs(1, 1); mv.visitEnd(); // eval method mv = cw.visitMethod(ACC_PUBLIC, "eval", "(JJ)I", null, null); expr.compile(new AsmCompiler(cw, mv)); mv.visitInsn(IRETURN); // max stack and max locals automatically computed mv.visitMaxs(0, 0); mv.visitEnd(); return cw.toByteArray(); } protected Long compute(Expr<?> exp, CompilerContext context) { try { byte[] b = this.compile("Example", exp, context); FileOutputStream fos = new FileOutputStream("tmp\\Example.class"); fos.write(b); fos.close(); Class<?> expClass = this.defineClass("Example", b, 0, b.length); // instantiates this compiled expression class... ExpressionForSimpleTest iexp = (ExpressionForSimpleTest) expClass.newInstance(); return iexp.eval(0L, 0L); } catch (FileNotFoundException e) { throw new RuntimeException(e); } catch (ClassFormatError e) { throw new RuntimeException(e); } catch (IOException e) { throw new RuntimeException(e); } catch (InstantiationException e) { throw new RuntimeException(e); } catch (IllegalAccessException e) { throw new RuntimeException(e); } } protected Integer computeBoolean(Expr<?> exp, CompilerContext context) { try { exp.scan(context); byte[] b = this.compileBoolean("Example", exp, context); FileOutputStream fos = new FileOutputStream("tmp\\Example.class"); fos.write(b); fos.close(); Class<?> expClass = this.defineClass("Example", b, 0, b.length); // instantiates this compiled expression class... ExpressionForSimpleTestBoolean iexp = (ExpressionForSimpleTestBoolean) expClass.newInstance(); return iexp.eval(0L, 0L); } catch (FileNotFoundException e) { throw new RuntimeException(e); } catch (ClassFormatError e) { throw new RuntimeException(e); } catch (IOException e) { throw new RuntimeException(e); } catch (InstantiationException e) { throw new RuntimeException(e); } catch (IllegalAccessException e) { throw new RuntimeException(e); } } } private long compute(Expr<?> expr) { Complier complier = new Complier(); return complier.compute(expr, new CompilerContext() { @Override public Type resolveType(String name) { return compiler.findType(name); } }); } private int computeBoolean(Expr<?> expr) { Complier complier = new Complier(); return complier.computeBoolean(expr, new CompilerContext() { @Override public Type resolveType(String name) { return compiler.findType(name); } }); } private void eqValue(String exprText, boolean result) { try { if (result) { assertEquals(1, computeBoolean(parse(exprText))); } else { assertEquals(0, computeBoolean(parse(exprText))); } } catch (RecognitionException e) { fail(e.toString()); } } private void eqValue(String exprText, int result) { try { assertEquals(result, compute(parse(exprText))); } catch (RecognitionException e) { fail(e.toString()); } } private void eqExpr(String exprText, String expectedResult) { try { Expr<?> expr = parse(exprText); assertEquals(expectedResult, expr.toString()); } catch (RecognitionException e) { fail(e.toString()); } } private Expr<?> parse(String exprText) throws RecognitionException { NebulaLexer lexer = new NebulaLexer(new ANTLRStringStream(exprText)); CommonTokenStream tokens = new CommonTokenStream(lexer); NebulaParser parser = new NebulaParser(tokens, compiler); parser.enterMethod(null); parser.pushLocal("a", (Type) null); parser.pushLocal("b", (Type) null); parser.pushLocal("n", (Type) null); return parser.expression(); } public void testTypeDefinition() { eqExpr("a+b", "(a + b)"); eqExpr("a-b", "(a - b)"); eqExpr("a*b", "(a * b)"); eqExpr("a/b", "(a / b)"); eqExpr("a%b", "(a % b)"); eqExpr("++a", "(++a)"); eqExpr("--a", "(--a)"); // eqExpr("+a", "(+a)"); // eqExpr("-a", "(-a)"); eqExpr("a +1 * b /10-1", "((a + ((1 * b) / 10)) - 1)"); eqExpr("a>b", "(a > b)"); eqExpr("a==b", "(a == b)"); eqExpr("a<b", "(a < b)"); eqExpr("a>=b", "(a >= b)"); eqExpr("a<=b", "(a <= b)"); eqExpr("a!=b", "(a != b)"); eqExpr("a&&b", "(a && b)"); eqExpr("a<b&&b>=a", "((a < b) && (b >= a))"); eqExpr("a and b", "(a && b)"); eqExpr("a||b", "(a || b)"); eqExpr("a or b", "(a || b)"); eqExpr("!a", "(!a)"); eqExpr("not a", "(!a)"); eqExpr("not(a)", "(!a)"); eqExpr("not(a==b)", "(!(a == b))"); eqExpr(" a >=10 && n==1 or a!= b ", "(((a >= 10) && (n == 1)) || (a != b))"); try { parse("$Person[12]"); parse("$Person[12,34234,33..33,22..]"); parse("$Person[a==10 && b==2]"); parse("$Person[a==10 && b==2]"); } catch (RecognitionException e) { throw new RuntimeException(e); } // eqExpr("$Person[a==10 && b==2]",""); // } public void testCompute() { eqValue("3+5", 3 + 5); eqValue("3-5", 3 - 5); eqValue("3*5", 3 * 5); eqValue("3/5", 3 / 5); eqValue("3%5", (3 % 5)); eqValue("3 +1 * 5 /10-1", ((3 + ((1 * 5) / 10)) - 1)); eqValue("3>5", (3 > 5)); eqValue("5>3", (5 > 3)); eqValue("3==5", (3 == 5)); eqValue("3<5", (3 < 5)); eqValue("3>=5", (3 >= 5)); eqValue("3<=5", (3 <= 5)); eqValue("3!=5", (3 != 5)); eqValue("3>0 && 5<0", 3 > 0 && 5 < 0); eqValue("3>0 and 5<0", 3 > 0 && 5 < 0); eqValue("3==1 || 5==1", 3 == 1 || 5 == 1); eqValue("3==1 or 5==1", 3 == 1 || 5 == 1); eqValue("!(3==1)", !(3 == 1)); // eq("not 3",(!3)); eqValue("not(3==1)", !(3 == 1)); eqValue("not(3==5)", (!(3 == 5))); eqValue(" 10 >=10 && 6==1 or 3!= 5 ", (((10 >= 10) && (6 == 1)) || (3 != 5))); } }