set flag OurSyncCollections. !include once #1034831 // Gazelle 22 Function Include for Testing svoid test_leftArrowScript_classDefs() { temp LASMultiClassLoader cl = new(mc()); test_leftArrowScript_classDefs(cl); } sclass test_leftArrowScript_classDefs_Base { S hey() { ret "ho"; } } svoid test_leftArrowScript_classDefs(LASMultiClassLoader cl) { var test = new TestFunctionValues(l1 leftArrowVerbose); // define a class with two fields S classPrefix = "scriptClasses."; embedded O runScript(S code) { new GazelleV_LeftArrowScriptParser parser; enableScaffolding(parser); parser.classDefPrefix(classPrefix); parser.lasClassLoader(cl); ret leftArrowVerbose(parser, code); } S classSrc = [[ class MyClass { a: String b: String } ]], src = classSrc; Class c = cast runScript(src); assertStartsWith(print(c.getName()), classPrefix + "MyClass" + "_"); // compile same source again - make sure we get the same class object assertSame(c, runScript(src)); assertEqualsVerbose("Number of fields", 3, l(getDeclaredFields_cached(c))); assertEqualsVerbose("Type of a", S.class, getField(c, "a").getType()); assertEqualsVerbose("Type of b", S.class, getField(c, "b").getType()); // Make sure a change in the class definition gives us a new class name Class c2 = cast runScript([[ class MyClass { a: String c: String } ]]); print(className(c2)); assertNotSame(c, c2); // Make sure a change in the methods also gives us a new class name S classSrc2 = [[ class MyClass { def bla { "x" } } ]]; c = (Class) runScript(classSrc2); assertSame(c, runScript(classSrc2)); c2 = (Class) runScript([[ class MyClass { def bla { "y" } } ]]); assertNotSame(c, c2); // Now let's try and use a script-defined class src = classSrc + [[ x <- new MyClass y <- new MyClass x a <- "yo" y a <- "oy" x a ]]; assertEqualsVerbose("yo", runScript(src)); // Using the class in a function src = classSrc + [[ def bla { x <- new MyClass x a <- "yo" x a } bla ]]; assertEqualsVerbose("yo", runScript(src)); // Now for defining some methods (yay!) src = [[ class MyClass2 { def method1 { "I'm here" } def method2 a { reversed a } } x <- new MyClass2 pair (x method1) (x method2 "sey") ]]; assertEqualsVerbose(pair("I'm here", "yes"), runScript(src)); // accessing instance fields src = [[ class MyClass3 { a: String def getA { this a } // requiring the this keyword for now def setA a { this a <- a } def aLength { (this a) length } } x <- new MyClass3 x setA "abc" assertEquals (x aLength) 3 x getA ]]; assertEqualsVerbose("abc", runScript(src)); // fully qualified type classSrc = [[ class MyClass4 { a: java.util.List } ]]; c = (Class) runScript(classSrc); assertEqualsVerbose(fieldType(c, "a"), L.class); // type with type parameter classSrc = [[ class MyClass5 { a: L } ]]; c = (Class) runScript(classSrc); assertEqualsVerbose("Raw type of L field", fieldType(c, "a"), L.class); assertEqualsVerbose("Generic type of L field", genericFieldType(c, "a"), new ParameterizedTypeImpl(null, L, S)); // primitive type classSrc = [[ class MyClass6 { x: int } ]]; c = (Class) runScript(classSrc); assertEqualsVerbose(fieldType(c, "x"), int.class); classSrc = [[ class ToString { def toString : S { "It's me, George!" } } new ToString ]]; assertEqualsVerbose("It's me, George!", str(runScript(classSrc))); // primitive array classSrc = [[ class MyClass7 { x: int[] } ]]; c = (Class) runScript(classSrc); assertEqualsVerbose(fieldType(c, "x"), int[].class); // define class implementing interface classSrc = [[ class Bla is IF0 { def get { "hello" } } new Bla ]]; IF0 f = cast runScript(classSrc); assertEqualsVerbose("hello", f!); // call function on class defined inline assertEqualsVerbose(Class.class, runScript([[ _getClass2 class A { } ]])); // constructor assertEqualsVerbose(5, runScript([[ class MyClass8 { x: int ctor { this x <- 5 } } new MyClass8, x ]]); // initialized field assertEqualsVerbose(7, runScript([[ class MyClass9 { x: int <- 7 } new MyClass9, x ]]); cl.rememberClassBytes(true); cl.onClassDefined(l1 disassembleClass); // define class with superclass classSrc = [[ class A { def yo { "yay" } } class B extends A { def wow { joinWithSpace (this yo) "amazing!" } } new B, wow ]]; assertEqualsVerbose("yay amazing!", runScript(classSrc)); // define class with superclass from outside of script classSrc = [[ class B extends test_leftArrowScript_classDefs_Base { def wow { joinWithSpace (this hey) (this hey) (this hey) } } new B, wow ]]; assertEqualsVerbose("ho ho ho", runScript(classSrc)); // initializer runScript([[ class MyClass9 { x: int initializer { this x <- 5 } } assertEqualsVerbose 5 < new MyClass9, x ]]); runScript([[ class MyClass10 { l: L <- new ArrayList initializer { this l, add "init" } ctor { this l, add "ctor" } } assertEqualsVerbose (ll "init" "ctor") < new MyClass10, l ]]); // TODO: Call superclass method (basically needs full method compilation) /*runScript([[ class MyClassA { def x: S { "hello" } } class MyClassB extends MyClassA { def x: S { ret concat (super x) " world" } } assertEqualsVerbose "hello world" < new MyClassB, x ]]);*/ // Reference own class name runScript([[ class MyClassSelf { def me: MyClassSelf { this } } ]]); // Methods have proper argument types runScript([[ class ArgTypes { def doIt (s: S) { "a string" } def doIt (s: O) { "not a string" } } assertEqualsVerbose "a string" < new ArgTypes, doIt "yo" assertEqualsVerbose "not a string" < new ArgTypes, doIt 123 ]]); // Methods with primitive return type runScript([[ class PrimReturn { def theNumber: int { 123 } } assertEqualsVerbose 123 < new PrimReturn, theNumber assertEqualsVerbose "int" < str < findMethod (new PrimReturn) "theNumber", getReturnType ]]); // settable fields runScript([[ class Settable { settable x: int settable b: bool settable l: long settable d: double settable y: S } s <- new Settable, x 5, y "test", b true assertEqualsVerbose 5 < s x assertEqualsVerbose 5 < call s "x" assertEqualsVerbose "test" < s y assertEqualsVerbose "test" < call s "y" assertEqualsVerbose true < s b ]]); // settable field with initializer runScript([[ class Settable { settable s: S <- "hello" } assertEqualsVerbose "hello" < new Settable, s ]]); // selfType as method return type runScript([[ class SelfTypeTest { def me: selfType { this } } t <- new SelfTypeTest assertEqualsVerbose t < t me ]]); // void methods runScript([[ class VoidMethodTest is Closeable { def close: void {} } ]]); // transient field O o = runScript([[ class TransientTest { transient i: int } new TransientTest ]]); assertTrueVerbose("transient", isTransient(fieldObject(o, "i"))); // LS as type o = runScript([[ class LSTest { l: LS } new LSTest ]]); assertEqualsVerbose("java.util.List", str(genericFieldType(o, "l"))); // Referring to a script-defined class as a Class o = runScript([[ class MyClass {} MyClass ]]); assertContainsVerbose("MyClass", className((Class) o)); // static field o = runScript([[ class MyClass { static hello: S <- "world" } ]]); assertEqualsVerbose("world", get((Class) o, "hello")); }