package org.jmlspecs.openjmltest.testcases;
import java.util.List;
import javax.tools.Diagnostic;
import javax.tools.JavaFileObject;
import org.jmlspecs.openjml.JmlTree.JmlBinary;
import org.jmlspecs.openjml.JmlTree.JmlMethodInvocation;
import org.jmlspecs.openjml.JmlTree.JmlQuantifiedExpr;
import org.jmlspecs.openjml.JmlTree.JmlSingleton;
import org.jmlspecs.openjml.JmlTree.JmlVariableDecl;
import org.jmlspecs.openjmltest.ParseBase;
import org.jmlspecs.openjmltest.TestJavaFileObject;
import org.junit.Assume;
import org.junit.Test;
import com.sun.tools.javac.parser.JmlFactory;
import com.sun.tools.javac.parser.JmlParser;
import com.sun.tools.javac.parser.Parser;
import com.sun.tools.javac.parser.Tokens.TokenKind;
import com.sun.tools.javac.tree.*;
import com.sun.tools.javac.tree.JCTree.JCArrayAccess;
import com.sun.tools.javac.tree.JCTree.JCAssign;
import com.sun.tools.javac.tree.JCTree.JCBinary;
import com.sun.tools.javac.tree.JCTree.JCConditional;
import com.sun.tools.javac.tree.JCTree.JCFieldAccess;
import com.sun.tools.javac.tree.JCTree.JCIdent;
import com.sun.tools.javac.tree.JCTree.JCLiteral;
import com.sun.tools.javac.tree.JCTree.JCMethodInvocation;
import com.sun.tools.javac.tree.JCTree.JCModifiers;
import com.sun.tools.javac.tree.JCTree.JCParens;
import com.sun.tools.javac.tree.JCTree.JCPrimitiveTypeTree;
import com.sun.tools.javac.tree.JCTree.JCTypeCast;
import com.sun.tools.javac.tree.JCTree.JCUnary;
import com.sun.tools.javac.tree.JCTree.LetExpr;
import com.sun.tools.javac.util.JCDiagnostic;
import com.sun.tools.javac.util.Log;
import static org.junit.Assert.*;
/** These test the AST structure produced by parsing various expressions -
* checking the node type and position.
* @author David Cok
*/
@org.junit.runner.RunWith(IgnoreFalseAssumptions.class)
public class expressions extends ParseBase {
@Override
public void setUp() throws Exception {
//noCollectDiagnostics = true;
super.setUp();
jml = true;
}
// TODO - put in a few harness tests
// TODO - test error messages
public void helpFailure(String failureMessage, String s, Object ... list) {
boolean failed = false;
try {
helpExpr(s,list);
} catch (AssertionError a) {
failed = true;
assertEquals("Failure report wrong",failureMessage,a.getMessage());
}
if (!failed) fail("Test Harness failed to report an error");
}
public void helpExpr(String s, Object... list) {
try {
Log.instance(context).useSource(new TestJavaFileObject(s));
JmlParser p = ((JmlFactory)fac).newParser(s,false,true,true,jml);
JCTree.JCExpression e = p.parseExpression();
List<JCTree> out = ParseTreeScanner.walk(e);
int i = 0;
int k = 0;
if (print) {
for (JCTree t: out) {
System.out.println(t.getClass()
+ " " + t.getStartPosition()
+ " " + t.getPreferredPosition()
+ " " + p.getEndPos(t));
}
}
if (print || collector.getDiagnostics().size() != 0)
printDiagnostics();
if (collector.getDiagnostics().size() != 0) {
fail("Saw unexpected errors");
}
Object p1, p2, p3;
for (JCTree t: out) {
assertEquals("Class not matched at token " + k, list[i++], t.getClass());
p1 = list[i++];
p2 = (i < list.length && list[i] instanceof Integer) ? list[i++] : null;
p3 = (i < list.length && list[i] instanceof Integer) ? list[i++] : null;
// FIXME - need better way to obtain positions
if (p3 != null) {
assertEquals("Start position for token " + k, p1, t.getStartPosition());
assertEquals("Preferred position for token " + k, p2, t.getPreferredPosition());
assertEquals("End position for token " + k, p3, p.getEndPos(t));
} else if (p2 != null) {
assertEquals("Start position for token " + k, p1, t.getStartPosition());
assertEquals("End position for token " + k, p2, p.getEndPos(t));
} else {
assertEquals("Preferred position for token " + k, p1, t.getPreferredPosition());
}
++k;
}
if ( i != list.length) fail("Incorrect number of nodes listed");
if (p.getScanner().token().kind != TokenKind.EOF) fail("Not at end of input");
} catch (Exception e) {
e.printStackTrace(System.out);
fail("Exception thrown while processing test: " + e);
}
}
public void helpExprErrors(String s, Object... list) {
try {
Log.instance(context).useSource(new TestJavaFileObject(s));
Parser p = ((JmlFactory)fac).newParser(s,false,true,true,jml);
p.parseExpression();
int i = 0;
if (print || collector.getDiagnostics().size() != list.length) printDiagnostics();
assertEquals("Saw wrong number of errors ",list.length,collector.getDiagnostics().size());
for (Diagnostic<? extends JavaFileObject> dd: collector.getDiagnostics()) {
assertEquals("Error message " + i,list[i++],noSource((JCDiagnostic)dd));
}
} catch (Exception e) {
e.printStackTrace(System.out);
fail("Exception thrown while processing test: " + e);
}
}
String noSource(JCDiagnostic dd) {
return dd.noSource();
}
@Test
public void testBug2() {
helpExpr("equals(\\result.multiply(val).add(remainder(val)))"
,JCMethodInvocation.class, 0,6,49
,JCIdent.class, 0,0,6
,JCMethodInvocation.class, 7,32,48
,JCFieldAccess.class, 7,28,32
,JCMethodInvocation.class, 7,23,28
,JCFieldAccess.class, 7,14,23
,JmlSingleton.class, 7,7,14
,JCIdent.class, 24,24,27
,JCMethodInvocation.class, 33,42,47
,JCIdent.class, 33,33,42
,JCIdent.class, 43,43,46
);
}
@Test
public void testBug() {
helpExpr("equals(\\result[0].equals(divide(val)))"
,JCMethodInvocation.class, 0,6,38
,JCIdent.class, 0,0,6
,JCMethodInvocation.class, 7,24,37
,JCFieldAccess.class, 7,17,24
,JCArrayAccess.class, 7,14,17
,JmlSingleton.class, 7,7,14
,JCLiteral.class, 15,15,16
,JCMethodInvocation.class, 25,31,36
,JCIdent.class, 25,25,31
,JCIdent.class, 32,32,35
);
}
/** Test scanning something very simple */
@Test
public void testSomeJava() {
jml = false;
helpExpr("a",
JCIdent.class ,0,0,1);
helpExpr("aaa",
JCIdent.class ,0,0,3);
}
/** Test scanning Java binary expression to check node positions */
@Test
public void testBinary() {
jml = false;
helpExpr("aa+bbb",
JCBinary.class, 0,2,6,
JCIdent.class ,0,0,2,
JCIdent.class ,3,3,6);
}
/** Test scanning Java binary expression to check node positions */
@Test
public void testJCBinary() {
jml = false;
helpExpr("a+b*c",
JCBinary.class, 0,1,5,
JCIdent.class ,0,0,1,
JCBinary.class, 2,3,5,
JCIdent.class ,2,2,3,
JCIdent.class ,4,4,5
);
helpExpr("a*b+c",
JCBinary.class, 0,3,5,
JCBinary.class, 0,1,3,
JCIdent.class ,0,0,1,
JCIdent.class ,2,2,3,
JCIdent.class ,4,4,5
);
}
/** Test scanning JML equivalence expression */
@Test
public void testJMLUnary1() {
helpExpr(" - (++a) + !b + (a--) + (~a++)",
JCBinary.class, 1,22,30,
JCBinary.class, 1,14,21,
JCBinary.class, 1,9,13,
JCUnary.class, 1,1,8,
JCParens.class, 3,3,8,
JCUnary.class, 4,4,7,
JCIdent.class ,6,6,7,
JCUnary.class, 11,11,13,
JCIdent.class ,12,12,13,
JCParens.class, 16,16,21,
JCUnary.class, 17,18,20,
JCIdent.class ,17,17,18,
JCParens.class, 24,24,30,
JCUnary.class, 25,25,29,
JCUnary.class, 26,27,29,
JCIdent.class ,26,26,27
);
}
/** Test scanning JML equivalence expression */
@Test
public void testJMLBinary1() {
helpExpr("a <==> b",
JmlBinary.class, 0,2,8,
JCIdent.class ,0,0,1,
JCIdent.class ,7,7,8);
}
/** Test scanning JML inequivalence expression */
@Test
public void testJMLBinary2() {
helpExpr("a <=!=>b",
JmlBinary.class, 0,2,8,
JCIdent.class ,0,0,1,
JCIdent.class ,7,7,8);
}
/** Test scanning JML implies expression */
@Test
public void testJMLBinary3() {
helpExpr("a ==> b",
JmlBinary.class, 0,2,8,
JCIdent.class ,0,0,1,
JCIdent.class ,7,7,8);
}
/** Test scanning JML reverse implies expression */
@Test
public void testJMLBinary4() {
helpExpr("a <== b",
JmlBinary.class, 0,2,8,
JCIdent.class ,0,0,1,
JCIdent.class ,7,7,8);
}
/** Test JML left association for <==> */
@Test
public void testJMLprecedence() {
helpExpr("a <==> b <==> c <==> d",
JmlBinary.class, 0,16,22,
JmlBinary.class, 0,9,15,
JmlBinary.class, 0,2,8,
JCIdent.class ,0,0,1,
JCIdent.class ,7,7,8,
JCIdent.class ,14,14,15,
JCIdent.class ,21,21,22);
}
/** Test JML right association for ==> */
@Test
public void testJMLprecedence1() {
helpExpr("a ==> b ==> c ==> d",
JmlBinary.class, 0,2,22,
JCIdent.class ,0,0,1,
JmlBinary.class, 7,9,22,
JCIdent.class ,7,7,8,
JmlBinary.class, 14,16,22,
JCIdent.class ,14,14,15,
JCIdent.class ,21,21,22);
}
/** Test JML left association for <== */
@Test
public void testJMLprecedence1a() {
helpExpr("a <== b <== c <== d",
JmlBinary.class, 0,16,22,
JmlBinary.class, 0,9,15,
JmlBinary.class, 0,2,8,
JCIdent.class ,0,0,1,
JCIdent.class ,7,7,8,
JCIdent.class ,14,14,15,
JCIdent.class ,21,21,22);
}
/** Test precedence between equiv and implies operators */
@Test
public void testJMLprecedence2() {
helpExpr("a ==> b <==> c ==> d",
JmlBinary.class, 0,9,22,
JmlBinary.class, 0,2,8,
JCIdent.class ,0,0,1,
JCIdent.class ,7,7,8,
JmlBinary.class, 14,16,22,
JCIdent.class ,14,14,15,
JCIdent.class ,21,21,22);
}
/** Test association of equiv operators */
@Test
public void testJMLprecedence2a() {
helpExpr("a <==> b <==> c <==> d",
JmlBinary.class, 0,16,22,
JmlBinary.class, 0,9,15,
JmlBinary.class, 0,2,8,
JCIdent.class ,0,0,1,
JCIdent.class ,7,7,8,
JCIdent.class ,14,14,15,
JCIdent.class ,21,21,22);
}
/** Test precedence between equivalence and Java operators */
@Test
public void testJMLprecedence3() {
helpExpr("a + b <==> c || d",
JmlBinary.class, 0,9,22,
JCBinary.class, 0,2,8,
JCIdent.class ,0,0,1,
JCIdent.class ,7,7,8,
JCBinary.class, 14,16,22,
JCIdent.class ,14,14,15,
JCIdent.class ,21,21,22);
}
/** Test precedence between implies and Java operators */
@Test
public void testJMLprecedence4() {
helpExpr("a + b ==> c || d",
JmlBinary.class, 9,
JCBinary.class, 2,
JCIdent.class ,0,
JCIdent.class ,7,
JCBinary.class, 16,
JCIdent.class ,14,
JCIdent.class ,21);
}
/** Test precedence between equivalence and assignment, ternary operators */
@Test
public void testJMLprecedence5() {
helpExpr("a = b<==>bb ? c<=!=>cc : d<==>dd",
JCAssign.class, 2,
JCIdent.class ,0,
JCConditional.class, 12,
JmlBinary.class, 5,
JCIdent.class ,4,
JCIdent.class ,9,
JmlBinary.class, 15,
JCIdent.class ,14,
JCIdent.class ,20,
JmlBinary.class, 26,
JCIdent.class ,25,
JCIdent.class ,30);
}
/** Test precedence between lock and other operators */
@Test
public void testJMLprecedence6() {
helpExpr("a << b <# c == d",
JCBinary.class, 12,
JmlBinary.class, 7,
JCBinary.class, 2,
JCIdent.class ,0,
JCIdent.class ,5,
JCIdent.class ,10,
JCIdent.class ,15
);
}
/** Test precedence between lock and other operators */
@Test
public void testJMLprecedence7() {
helpExpr("a == b <#=c << d",
JCBinary.class, 2,
JCIdent.class ,0,
JmlBinary.class, 7,
JCIdent.class ,5,
JCBinary.class, 12,
JCIdent.class ,10,
JCIdent.class ,15
);
}
/** Test associativity of lock operators */
@Test
public void testJMLprecedence8() {
helpExpr("a <# b <#=c <# d",
JmlBinary.class, 12,
JmlBinary.class, 7,
JmlBinary.class, 2,
JCIdent.class ,0,
JCIdent.class ,5,
JCIdent.class ,10,
JCIdent.class ,15
);
}
/** Test precedence between lock and equivalence */
@Test
public void testJMLprecedence9() {
helpExpr("a <==> b <#=c <==> d",
JmlBinary.class, 14,
JmlBinary.class, 2,
JCIdent.class ,0,
JmlBinary.class, 9,
JCIdent.class ,7,
JCIdent.class ,12,
JCIdent.class ,19
);
}
/** Test scanning \result expression */
@Test
public void testResult() {
helpExpr(" \\result + \\result",
JCBinary.class, 1,9,18,
JmlSingleton.class ,1,1,8,
JmlSingleton.class ,11,11,18);
}
/** Test scanning \old expression */
@Test
public void testOld() {
helpExpr(" \\old(a+b)",
JmlMethodInvocation.class, 1,5,10,
JCBinary.class, 6,7,9,
JCIdent.class ,6,6,7,
JCIdent.class ,8,8,9);
}
/** Test scanning \elemtype expression */
@Test
public void testElemtype() {
helpExpr(" \\elemtype(a+b)",
JmlMethodInvocation.class, 1,10,15,
JCBinary.class, 11,12,14,
JCIdent.class ,11,11,12,
JCIdent.class ,13,13,14);
}
/** Test scanning \nonnullelements expression */
@Test
public void testNonnullelements() {
helpExpr(" \\nonnullelements(a+b)",
JmlMethodInvocation.class, 17,
JCBinary.class, 19,
JCIdent.class ,18,
JCIdent.class ,20);
}
/** Test scanning \typeof expression */
@Test
public void testTypeofA() {
helpExpr(" \\typeof(a+b)",
JmlMethodInvocation.class, 8,
JCBinary.class, 10,
JCIdent.class ,9,
JCIdent.class ,11);
}
/** Test scanning \max(\lockset) expression */
@Test
public void testMaxLockset() {
helpExpr(" \\max(\\lockset)",
JmlMethodInvocation.class, 5,
JmlSingleton.class, 6);
}
/** Test scanning \max(\lockset) expression */
@Test
public void testMaxLocksetError2() {
helpExprErrors(" \\max","/TEST.java:1: reached end of file while parsing");
}
/** Test precedence of <= operator */
@Test
public void testCompare() {
helpExpr(" a == b <= c",
JCBinary.class, 1,3,12,
JCIdent.class, 1,1,2,
JCBinary.class, 6,8,12,
JCIdent.class ,6,6,7,
JCIdent.class ,11,11,12);
}
/** Test precedence of <= operator */
@Test
public void testCompare2() {
helpExpr(" a <= b == c",
JCBinary.class, 1,8,12,
JCBinary.class, 1,3,7,
JCIdent.class, 1,1,2,
JCIdent.class ,6,6,7,
JCIdent.class ,11,11,12);
}
/** Test precedence of <: operator */
@Test
public void testSubTypeof() {
helpExpr(" a == b <: c",
JCBinary.class, 1,3,12,
JCIdent.class, 1,1,2,
JmlBinary.class, 6,8,12,
JCIdent.class ,6,6,7,
JCIdent.class ,11,11,12);
}
/** Test precedence of <: operator */
@Test
public void testSubTypeof2() {
helpExpr(" a <: b == c",
JCBinary.class, 1,8,12,
JmlBinary.class, 1,3,7,
JCIdent.class, 1,1,2,
JCIdent.class ,6,6,7,
JCIdent.class ,11,11,12);
}
/** Test precedence of <: operator */
@Test
public void testSubTypeof3() {
helpExpr(" a <: b << c",
JmlBinary.class, 3,
JCIdent.class, 1,
JCBinary.class, 8,
JCIdent.class ,6,
JCIdent.class ,11);
}
/** Test precedence of <: operator */
@Test
public void testSubTypeof4() {
helpExpr(" a << b <: c",
JmlBinary.class, 8,
JCBinary.class, 3,
JCIdent.class, 1,
JCIdent.class ,6,
JCIdent.class ,11);
}
/** Test precedence of <: operator */
@Test
public void testSubTypeof5() {
helpExpr(" (a) <: c",
JmlBinary.class, 5,
JCParens.class, 1,
JCIdent.class, 2,
JCIdent.class ,8);
}
/** Test precedence of <: operator */
@Test
public void testSubTypeof6() {
helpExpr(" a <: (c)",
JmlBinary.class, 3,
JCIdent.class, 1,
JCParens.class, 6,
JCIdent.class ,7);
}
/** Test precedence of <: operator */
@Test
public void testSubTypeof7() {
helpExpr(" (a) <: (c)",
JmlBinary.class, 5,
JCParens.class, 1,
JCIdent.class, 2,
JCParens.class, 8,
JCIdent.class ,9);
}
@Test
public void testQuantifier() {
helpExpr(" \\exists int i; 0 <= i; i < 0 ",
JmlQuantifiedExpr.class,1,1,30,
JmlVariableDecl.class,10,14,15,
JCModifiers.class,10,10,10,
JCPrimitiveTypeTree.class, 10,10,13,
JCBinary.class, 17,19,23,
JCLiteral.class ,17,17,18,
JCIdent.class ,22,22,23,
JCBinary.class ,25,27,30,
JCIdent.class ,25,25,26,
JCLiteral.class ,29,29,30);
}
@Test
public void testQuantifier2() {
helpExpr("(\\forall int i; 0 <= i; i < 0 ) ",
JCParens.class, 0,0,32,
JmlQuantifiedExpr.class,1,1,30,
JmlVariableDecl.class,10,14,15,
JCModifiers.class,10,10,10,
JCPrimitiveTypeTree.class, 10,10,13,
JCBinary.class, 17,19,23,
JCLiteral.class ,17,17,18,
JCIdent.class ,22,22,23,
JCBinary.class ,25,27,30,
JCIdent.class ,25,25,26,
JCLiteral.class ,29,29,30);
}
@Test
public void testQuantifier3() {
helpExpr("(\\sum int i; 0 <= i; i + 1 ) ",
JCParens.class, 0,0,32,
JmlQuantifiedExpr.class,1,1,30,
JmlVariableDecl.class,10,14,15,
JCModifiers.class,10,10,10,
JCPrimitiveTypeTree.class, 10,10,13,
JCBinary.class, 17,19,23,
JCLiteral.class ,17,17,18,
JCIdent.class ,22,22,23,
JCBinary.class ,25,27,30,
JCIdent.class ,25,25,26,
JCLiteral.class ,29,29,30);
}
@Test
public void testQuantifier4() {
helpExpr("(\\product int i; ; i + 1 ) ",
JCParens.class, 0,0,26,
JmlQuantifiedExpr.class,1,1,24,
JmlVariableDecl.class,10,14,15,
JCModifiers.class,10,10,10,
JCPrimitiveTypeTree.class, 10,10,13,
JCBinary.class ,19,21,24,
JCIdent.class ,19,19,20,
JCLiteral.class ,23,23,24);
}
@Test
public void testQuantifier5() {
helpExpr("(\\min int i; i + 1 ) ",
JCParens.class, 0,0,26,
JmlQuantifiedExpr.class,1,1,24,
JmlVariableDecl.class,10,14,15,
JCModifiers.class,10,10,10,
JCPrimitiveTypeTree.class, 10,10,13,
JCBinary.class ,19,21,24,
JCIdent.class ,19,19,20,
JCLiteral.class ,23,23,24);
}
@Test
public void testQuantifier6() {
helpExpr("(\\max int i; i + 1 ) ",
JCParens.class, 0,0,26,
JmlQuantifiedExpr.class,1,1,24,
JmlVariableDecl.class,10,14,15,
JCModifiers.class,10,10,10,
JCPrimitiveTypeTree.class, 10,10,13,
JCBinary.class ,19,21,24,
JCIdent.class ,19,19,20,
JCLiteral.class ,23,23,24);
}
@Test
public void testLet1() {
helpExpr("(\\let int i=1+2, boolean b = i==i; i + 1 ) ",
JCParens.class, 0, 0, 44,
LetExpr.class, 1, 1, 42,
JmlVariableDecl.class,6,10, 15,
JCModifiers.class, 6,6,6,
JCPrimitiveTypeTree.class, 6,6,9,
JCBinary.class, 12,13,15,
JCLiteral.class, 12,12,13,
JCLiteral.class, 14,14,15,
JmlVariableDecl.class, 17,25,33,
JCModifiers.class, 17,17,17,
JCPrimitiveTypeTree.class, 17,17,24,
JCBinary.class, 29,30,33,
JCIdent.class, 29,29,30,
JCIdent.class,32,32,33,
JCBinary.class, 37,39,42,
JCIdent.class, 37,37,38,
JCLiteral.class, 41,41,42
);
}
@Test
public void testMisc() {
helpExpr("(\\result==j) ==> \\typeof(o) <: \\type(oo) "
,JmlBinary.class ,0,13,40
,JCParens.class, 0,0,12
,JCBinary.class ,1,8,11
,JmlSingleton.class ,1,1,8
,JCIdent.class ,10,10,11
,JmlBinary.class ,17,28,40
,JmlMethodInvocation.class, 17,24,27
,JCIdent.class ,25,25,26
,JmlMethodInvocation.class, 31,36,40
,JCIdent.class ,37,37,39
);
}
@Test
public void testCastResult2() {
helpExpr("((Integer)\\result) == 0"
,JCBinary.class ,0,19,23
,JCParens.class, 0,0,18
,JCTypeCast.class ,1,1,17
,JCIdent.class ,2,2,9
,JmlSingleton.class ,10,10,17
,JCLiteral.class, 22,22,23
);
}
@Test
public void testCastResult() {
helpExpr("((x)==>\\result) == 0"
,JCBinary.class ,0,16,20
,JCParens.class, 0,0,15
,JmlBinary.class ,1,4,14
,JCParens.class, 1,1,4
,JCIdent.class ,2,2,3
,JmlSingleton.class ,7,7,14
,JCLiteral.class, 19,19,20
);
}
// TODO: other expressions, etc.
}