!include once #1034831 // Gazelle 22 Function Include for Testing set flag PingV3. scope test_leftArrowScript sclass #ClassA {} sclass #ClassB extends ClassA {} sclass #ClassC extends ClassB {} sclass #InheritanceDispatchTest { static S f(ClassA a) { ret "a"; } static S f(ClassB a) { ret "b"; } } sclass #Tester { O value = "123"; sO myStaticField = "ok"; } sclass #Sub1 { sclass X { static int value = 1; } } sclass #Sub2 { sclass X { static int value = 2; } } svoid test_leftArrowScript() { test_leftArrowScript_pinging(); embedded S countLoop(int n) { ret [[ i <- 0; while lessThan i ]] + n + [[ { i <- plus i 1 }; i ]]; } S ifThenElseScript = [[ if lessThan a b { joinWithSpace "It's" "less" } else if greaterThan a b { joinWithSpace "It's" "greater" } else { joinWithSpace "They're" "equal" } ]]; testFunctionValues(script -> leftArrowVerbose((S) script), // int primitive [[ 5 ]], 5, [[ -5 ]], -5, // function definition & call [[ def double x { Math multiplyExact x 2 } double 10 ]], 20, // new object with constructor arguments [[ new Pair "hello" "world" ]], pair("hello", "world"), // double constant [[ str 1.5e2 ]], "150.0", // float constant [[ 1.5e2f ]], 150f, // long constant [[ 0L ]], 0L, // hex constant [[ 0x80 ]], 0x80, // binary constant [[ 0B101 ]], 0B101, // character constant [[ '\t' ]], '\t', // [not implemented, too complicated] // last = result of last statement // [[ plus 1 2; Math addExact 5 last ]], 8, // get static field [[ Color black ]], Color.black, // get instance field, [[ tester <- new test_leftArrowScript_Tester; tester value ]], "123", // while loop countLoop(5), 5, // if statement [[ if lessThan 0 1 { "ok" } ]], "ok", [[ if lessThan 1 0 { "ok" } ]], null, // for each [[ l <- ll 2 3 sum <- 0 for number in l { sum <- plus sum number } sum ]], 5, // for each is also map() [[ for i in ll 2 3 { plus i 1 } ]], ll(3, 4), // for each as nested expression [[ joinWithSpace (for i in ll 2 3 { i }) ]], "2 3", // for i to n [[ for i to 2 { i } ]], ll(0, 1), // some bug [[ img <- newImage 10 10 r <- randomRect img 10 10 ]], rect(0, 0, 10, 10), // another bug [[ a <- 1 b <- a a ]], 1, // null bug [[ a <- 1 a <- null a ]], null, // return at the end [[ return 17 ]], 17, // two returns (first wins) [[ return 13 return 22 ]], 13, // same with "ret" for "return" [[ ret 13 ret 22 ]], 13, // conditional return [[ if true { return "so true" } return "oops" ]], "so true", [[ if false { return "not true" } return "but this" ]], "but this", // if-then-else [[ a <- 1; b <- 2; ]] + ifThenElseScript, "It's less", [[ a <- 6; b <- 2; ]] + ifThenElseScript, "It's greater", [[ a <- 5.0; b <- 5.0; ]] + ifThenElseScript, "They're equal", // if-then-else with "then" keyword but without curly braces [[ if true then "ok" else "not ok" ]], "ok", [[ if false then "ok" else "not ok" ]], "not ok", // nested expressions [[ plus (plus 1 2) 4 ]], 7, [[ (plus 5 6) toString ]], "11", // nested expressions over 2 lines (it's ok to split an expression // over multiple lines if you at least parenthesis is still open) [[ (plus 1 (plus 2 3)) ]], 6, // another case for nested expressions [[ str (Color black) ]], str(Color.black), // bug with nested for + new + linebreak + for (phew) [[ (for y in ll 1 { new Pair 1 2 for x in null {} }); 0 ]], 0, // param declares a variable [[ param x; x ]], null, // same with type [[ param x : int; x ]], null, // return with assignment [[ return x <- 1 ]], 1, // for pair [[ for pair a b in ll (pair 1 2) (pair 3 4) { plus a b } ]], ll(3, 7), // for key, value (map) [[ for a, b in litorderedmap 1 2 3 4 { plus a b } ]], ll(3, 7), // for index, value (list) [[ for index i, a in ll "a" "b" { concatStrings i a } ]], ll("0a", "1b"), // automatically convert int to long for method call [[ longPlus 1 2 ]], 3L, // same for constructors [[ new Ratio 1 ]], Ratio(1), // call a function from another function [[ def f1 { 1 } def f2 { plus (f1) 2 } f2 ]], 3, // return out of for loop [[ for x in iota 2 { return x } ]], 1, // continue loop [[ for x in iota 2 { if eq x 1 { continue } return "ok" } ]], "ok", // new without new [[ Pair (neg 1) (neg 2) ]], pair(-1, -2), // variable doesn't come into scope until it's initialized [[ neg <- neg 1; neg ]], -1, // repeat x { ... } construct [[ x <- 0 repeat plus 1 2 { x <- plus x 1 } x ]], 3, // update outer variable from function [[ x <- 0 def incIt { outer x <- plus x 1 } incIt x ]], 1, // return directly followed by } [[ if true { return } ]], null, // return from lambda (exits only the lambda, just like in Java) [[ repF 2 (IF0 -> { return 1; null }) ]], ll(1, 1), // "temp" (like in JavaX) [[ list <- new ArrayList { temp tempAdd list 5 assertContains list 5 } list ]], ll(), // "temp" test 2 (assure it handles exceptions properly) [[ list <- new ArrayList pcallF (Runnable -> { temp tempAdd list 5 fail }) list ]], ll(), // reference to functionContainer class itself [[ main ]], mc(), // referencing class with full package name [[ java.util.Arrays sort (newFloatArray 1) ]], null, [[ new java.util.ArrayList ]], ll(), // call method on literal [[ "" length ]], 0, // L or List to make a new list [[ new List ]], ll(), [[ new L ]], ll(), // Map to make a new HashMap [[ new Map ]], new Map, // new with a variable containing a class [[ c <- ArrayList; new c ]], ll(), [[ new Var, getClass ]], Var.class, shortName(InheritanceDispatchTest) + " (new " + shortName(ClassC) + ")", "b", // add simple tests here ); // get reference to current var context with _context new GazelleV_LeftArrowScriptParser parser; enableScaffolding(parser); parser.allowTheWorld(); new FlexibleVarContext ctx; assertSame(ctx, parser.parse("_context").get(ctx)); test_leftArrowScriptParseErrors(); test_leftArrowScript_lambdas(); test_leftArrowScript_binaryOperators(); test_leftArrowScriptCompileErrors(); // get static field in functionContainer parser = new GazelleV_LeftArrowScriptParser; parser.allowTheWorld(Tester, mc()); assertEqualsVerbose("ok", parser.parse("myStaticField")!); assertEqualsVerbose("ko", parser.parse("reversed myStaticField")!); assertEqualsVerbose(2, parser.parse("myStaticField length")!); test_leftArrowScript_classDefs(); test_leftArrowScript_forIterator(); var exception = leftArrowVerbose([[ try { throw new RuntimeException } catch e { e } ]]); assertEqualsVerbose(exception.getClass(), RuntimeException.class); // trying to get non-existant field/method on object assertFailVerbose(-> leftArrowVerbose([[ "" lengthX ]])); // make sure fields local to function are not visible outside assertFailVerbose(-> leftArrowParse([[ def x { y <- 1 } y ]])); test_leftArrowScript_comma(); // test priority of class resolution parser = new GazelleV_LeftArrowScriptParser; enableScaffolding(parser); parser.allowTheWorld(Sub1.class, Sub2.class); assertEqualsVerbose(1, parser.parse("X value")!); parser = new GazelleV_LeftArrowScriptParser; enableScaffolding(parser); parser.allowTheWorld(Sub2.class, Sub1.class); assertEqualsVerbose(2, parser.parse("X value")!); test_leftArrowScript_returnValueNotNeededOptimization(); // test addClassAlias parser = new GazelleV_LeftArrowScriptParser; parser.allowTheWorld(); parser.addClassAlias("Paar", "Pair"); assertEqualsVerbose(pair(1, 2), parser.parse("new Paar 1 2")!); // add tests here print("All left-arrow script tests OK!"); }