/**
* Copyright (c) 2009-2011, The HATS Consortium. All rights reserved.
* This file is licensed under the terms of the Modified BSD License.
*/
package abs.frontend.parser;
import java.io.StringReader;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import abs.frontend.FrontendTest;
import abs.frontend.antlr.parser.ABSParserWrapper;
import abs.frontend.ast.CompilationUnit;
import abs.frontend.ast.DeltaDecl;
public class ParserTest extends FrontendTest {
// private String emptyblock ;
private String bbclass;
// private String ms1, ms2, meth1, meth2 , fields, comment, comment2 ;
private String[] pureExp = { " x ", " this.x ",
"null",
// function expressions
// data constructor expression
"Int(x , y)",
// function application
"pluss(x,y)", "nth(tail(file,n))",
// pair constructor
"pair(x,y)",
// case expression
"case set { EmptyStringSet => False ; }", "case set { EmptyStringSet() => False ; }",
"case set { EmptyStringSet => False ; InsertString(string2,set2) => True ;}",
"if True then 5 else 6"};
private String[] effExp = { "new local Foo() ", "new local Foo(a,b) ", "o!init() ", "o!init(y) ", "o!init(y,z) ",
"this!init(y,z) ", "o.init(y,z,w) ",
// "this.init(y,z)",
"y.get" };
private String[] eqExp = { "a == b " };
@Before
public void setUp() {
// emptyblock = "{ }";
// methodsignatures
// ms1 = "Unit init(Foo x , Bar y)";
// ms2 = "Unit append(Int i)";
// meth1 = ms1 + "{ Int x ; Int y ; return null ; }";
// meth2 = ms2 + "{ skip; return null ; }";
bbclass = "class BoundedBuffer implements Buffer { \n" + " ListofInt buffer ; Int max ; Int n ; \n"
+ " Unit init(Foo x){ Int x ; Int y ; return null ; }\n"
+ " Unit append(Int i){ skip; return null ; }}";
}
@Test
public void testNothing() {
assertParseOk(" "); // NO decls no block
}
@Test
public void testEmptyBlock() {
assertParseOk("{ }"); // No decls.
}
@Test
public void ifExp() {
assertParseOk("{ (if True then x else x).get; }" );
assertParseOk("{ Int x = 5; if(if 4 == 5 then True else False) { x = 4; } else { x = 3; } }" );
assertParseOk("{ if True then x else x.get; }" );
}
@Test
public void testStmts() {
assertParseOk("{ return x; }");
assertParseOk("{ return x.get ; }"); // one statement
assertParseOk("{ skip ; return x.get ; }"); // n statements
assertParseOk("{ Int x ; Int y ; skip ; return x.get ; }"); // Variable
// decls
assertParseOk("{ skip ; return x.get ; }");
assertParseOk("{ Fut<I> x ; J z ; }"); // need trailing semicolon here.
assertParseOk(" { Fut<I> x ; Fut<Fut<I>> y ; J z ; K w ; }");
assertParseOk("{ Int x = 5; Int y; Foo ref = null; List<Int> list = Cons(5, Nil); skip; }"); // Variable
// decls
// with/without
// initializers
//
}
// Interface declarations
@Test
public void testIfDecl() {
assertParseOk(" interface Foo {} {}");
assertParseOk(" interface Bar extends Bar1, Bar2 {} {}");
assertParseError("interface Foo extends {} {}");
assertParseError("interface extends {} {}");
}
// Class declarations
@Test
public void testClassDecl() {
assertParseOk("class FooClass {} {}");
assertParseOk("class FooClass implements Foo {} {}");
assertParseOk("class FooClass implements Foo {}"); // optional main
// body
assertParseOk("class FooClass implements Foo.Bar {}"); // qualified
// Name
assertParseOk("class FooClass(T x , T y) implements Foo {}"); // class
// params
assertParseOk("class FooClass(T x) implements Foo {}"); // class params
assertParseOk("class FooClass(Foo.T x) implements Foo {}"); // class
// params
// qualified
// name
assertParseOk("class FooClass() implements Foo {}"); // class params
assertParseOk("class FooClass implements Foo { T x ; }"); // field
assertParseOk("class FooClass implements Foo { Foo.T x ; }"); // field
// qualified
assertParseOk("class FooClass implements Foo { T x ; { x = a ; } }"); // init
// block
assertParseOk("class FooClass implements Foo { T x = a ; }"); // field
// with
// initializer
assertParseOk("class FooClass implements Foo { {} } {} "); // empty
// init
// block
assertParseOk(bbclass);
assertParseError("class FooClass implements {}" + "{}");
}
// datatype declarations
@Test
public void testDatatypeDecl() {
assertParseOk("data Foo = XCons | YCons ; ");
assertParseOk("data IntList = IntNil | Cons(Int, IntList) ; ");
assertParseOk("data IntList = IntNil | Cons(Prelude.Int, IntList) ; ");
}
@Test
public void dataTypeSelectors() {
assertParseOk("data Foo = Bla(Int i);");
assertParseOk("data Foo = X | Bla(Int i);");
}
@Test
public void testParametricDatatypeDecl() {
assertParseOk("data List<A> = Nil | Cons(A, List<A>); ");
assertParseOk("data Pair<A, B> = Pair(A, B); ");
}
@Test
public void testFunctionDecl() {
assertParseOk("def Int inc(Int x) = x;"); // fun_exp = IDENTIFIER
assertParseOk("def Int inc(Int x) = plus(x,one());"); // fun_exp =
// Term(co,l)
assertParseOk("def Datatype fn(Int x , Int y) = x;");
assertParseOk("def TPair revPair(TPair p) = pair(snd(p),fst(p));");
assertParseOk("def TPair revPair(TPair p) = Prelude.pair(Prelude.snd(p),fst(p));");
// using let
assertParseOk("def TPair revPair(TPair p) = let(T x) = fst(p) in pair(snd(p),x);");
// using nested let
assertParseOk("def TPair revPair(TPair p) = let(T x) = fst(p) in let(T y) = snd(p) in pair(y,x);");
}
@Test
public void testParametricFunctionDecl() {
assertParseOk("def Int length<A>(List<A> list) = case list { Nil => 0; Cons(_, rest) => 1 + length(rest); };");
assertParseOk("def A nth<A>(List<A> list) = case n { 0 => head(list) ; _ => nth(tail(list), n-1) ; };");
}
@Test
public void testAnnotations() {
assertParseOk("[Test : \"value\"] class FooClass {} {}");
assertParseOk("[Test : \"value\"] [Test: Nil] class FooClass {} {}");
assertParseOk("[Test: 5] data Foo;");
assertParseOk("[Test2 : Pair(5, \"value\")] data Pair<A, B> = Pair(A, B);");
assertParseOk("[Test : 5] def Int constant() = 5;");
assertParseOk("[Test: Nil] def A constant<A>(A a) = a;");
assertParseOk("interface A { [Pre : x > 5] [Post : x > 0] Int method(Int x); }");
assertParseOk("class A { [Method : Testable] Int method(Int x) { return x; } }");
assertParseOk("class A { Int method(Int x) { [Value: Good] return x; } }");
assertParseOk("[Block: Init]{ Int x = 1; [Stmt: \"conditional\"] if (x == 1) [Branch: Then] x = 5; else [Branch: Else] x = -1; }");
assertParseOk("[Test] class FooClass {} {}");
assertParseOk("[\"value\"] class FooClass {} {}");
assertParseOk("class FooClass([Test] T t) {}");
assertParseOk("class FooClass { [Test] T t; }");
assertParseOk("class FooClass { Unit m([Test] T t) { }}");
assertParseOk("class FooClass { Unit m() { [Test] T t; }}");
assertParseOk("class FooClass { [Test] Unit m() { }}");
}
@Test
public void testNAryConstructors() {
assertParseOk("{ List<Int> l = list[]; }");
assertParseOk("{ Set<String> s = set[\"one\", \"Two\", \"three\"]; }");
}
// comments
@Test
public void testComment() {
assertParseOk("// one line\n");
assertParseOk("/* Multi \n line \n comment */");
}
@Test
public void testProg() {
assertParseOk("interface Foo {} \n interface Bar extends Bar1, Bar2 {} \n class FooClass implements Foo {} {}");
}
@Test
public void testAssignStmts() {
for (String e : pureExp) {
assertParseOk("{ v = " + e + ";}");
assertParseOk("{ this.f = " + e + ";}");
}
for (String e : effExp) {
assertParseOk("{ v = " + e + ";}");
assertParseOk("{ this.f = " + e + ";}");
}
for (String e : eqExp) {
assertParseOk("{ v = " + e + ";}");
assertParseOk("{ this.f = " + e + ";}");
}
assertParseError("class A { A m() { this = null; return null;} }");
}
@Test
public void testAwaitStmts() {
String[] guards = { "y?", "y? & z? ", " y? & z? & w?",
// any functional expression
};
for (String g : guards)
assertParseOk("{ await " + g + " ; }");
}
@Test
public void testOtherStmts() {
String[] otherStmt = { "skip ; ", "suspend ; ", "return e ; " };
for (String s : otherStmt)
assertParseOk("{" + s + "}");
}
@Test
public void testControlStmts() {
assertParseOk("{ if (x) y = True ; }");
assertParseOk("{ if (x) y = True ; else y = False ; }");
assertParseOk("{ if (x) { y = True ; z = False; } else y = False ; }");
assertParseOk("{ if (x) { if (y) skip ; else skip ; } else skip ; }");
assertParseOk("{ if (x) if (y) skip ; else skip ; else skip ; }");
assertParseOk("{ while (x) skip ; }");
assertParseOk("{ while (x) { x = y ; skip ; } }");
assertParseOk("{ if (x) y = True ; else y = False ; }");
assertParseOk("{ if (x) { y = True ; z = False; } else y = False ; }");
}
@Test
public void testStmtBlock() {
assertParseOk("{ skip ; }");
assertParseError(" { skip }");
assertParseOk("{ x = y ; skip ; }");
assertParseError("{ x = y skip ; }");
assertParseOk("{ x = y ; y = z ; skip ; }");
assertParseOk("{ { x = y ; skip ; await x? ; } skip ; }");
assertParseOk("{ { x = y ; } skip ; }");
assertParseOk(" { { } { } { } } ");
}
@Test
public void testStmtList() {
assertParseOk("{ x = null; x = y.get ; x = y ; } ");
}
@Test
public void moduleDeclQualName() {
assertParseOk("module ABS.Lang;");
}
@Test
public void importQual() {
assertParseOk("import ABS.Test;");
}
@Test
public void importFrom() {
assertParseOk("import Test from ABS;");
}
@Test
public void importFromList() {
assertParseOk("import Test, Test2, fun from ABS;");
}
@Test
public void importStarFrom() {
assertParseOk("import * from ABS;");
}
@Test
public void exportQual() {
assertParseOk("export ABS.Test;");
}
@Test
public void exportSimple() {
assertParseOk("export Test;");
}
@Test
public void exportList() {
assertParseOk("export Test, fun;");
}
@Test
public void exportStar() {
assertParseOk("export *;");
}
@Test
public void ticket189() {
assertParseError("def Unit foo() = Unit;\n"+
"class Bob { \n" +
" Unit run() { " +
" case Nil {"+
" Nil => Unit;"+
" _ => foo() // Note missing semicolon\n"+
"}; \n" +
"} \n" +
"} \n");
}
@Test
public void ticket203() {
assertParseError("def Bool g() = f(s a, s b);");
}
@Test
public void ticket238() throws Exception{
assertParseOk("module T238; delta D; productline P; features F,G; delta D when F && (! G);");
// fails because logical connectives apart from && are not implemented yet...
}
@Test
public void entry_deltadecl() throws Exception {
CompilationUnit u = new ABSParserWrapper().parse(new StringReader("delta Mon;"));
DeltaDecl d = (DeltaDecl) u.getDeltaDecl(0);
Assert.assertNotNull(d);
}
@Test (expected = ParseException.class)
public void deltaNameLowerCaseTest() throws Exception{
String deltaDecl = "delta foo;";
new ABSParserWrapper(null, true, false).parse(new StringReader(deltaDecl));
}
}