// (load) brings in the fields and compile-time definitions of another Kiss file (load "BasicTestCaseExtra.kiss") (function _testLoadInline [] (let [&mut thatValue 5] (load "BasicTestCaseExtra2.kiss") (Assert.equals 50 thatValue))) // (var) declares static variables (var message "Howdy") // #| ... |# parses and injects raw Haxe code (var mathResult #|5 + 6 * 3|#) // Order of operations will apply // (function) declares static functions (function myFloor [num] // funcalls can use dot access (Math.floor num)) // functions are resolved in the macro context (var funResult (myFloor 7.5)) // (prop) declares instance variables (prop myField 5) // (method) declares instance methods (method myMethod [] this.myField) // [...] returns a Kiss array (they have special features and convert implicitly) (var myArray [1 2 3]) // Array access is via nth (var myArrayLast (nth myArray -1)) // (collect) turns iterators to arrays (function _testCollect [] (Assert.equals "[0,1,2]" (Std.string (collect (range 3))))) // Variadic math uses haxe's Lambda.fold under the hood (var mySum (+ 1 2 3)) (var myDifference (- 5 4 3)) (function _testMultiplication [] (Assert.equals 60 (* 2 5 6)) (Assert.equals 5522401584 (* 84 289 89 71 36)) (Assert.equals "heyheyhey" (* "hey" 3))) // All math operations return floats, none truncate by default (var myQuotient (/ 6 3 2 2)) (var myRemainder (% 10 6)) (var myPower (^ 2 8)) (var &mut myNum 6) (var myInc ++myNum) (var myMin (min 9 3 7 1)) (var myMax (max 9 3 7 1)) (function _testLessThan [] (Assert.isTrue (< 1 2 3 4)) (Assert.isFalse (< 1 1 3 4)) (Assert.isFalse (< 1 12 12))) (function _testLesserEqual [] (Assert.isTrue (<= 1 2 3 4)) (Assert.isTrue (<= 1 1 3 4)) (Assert.isFalse (<= 1 12 11))) (function _testGreaterThan [] (Assert.isTrue (> 4 3 2 1)) (Assert.isFalse (> 4 4 2 1)) (Assert.isFalse (> 9 3 3))) (function _testGreaterEqual [] (Assert.isTrue (>= 4 3 2 1)) (Assert.isTrue (>= 4 4 2 1)) (Assert.isFalse (>= 9 4 5))) (function _testEqual [] (Assert.isTrue (= 1 1 1 1)) (Assert.isFalse (= 1 2 1 1)) (Assert.isTrue (= "hey" "hey" "hey")) (Assert.isFalse (= "hey" "you" "hey")) (Assert.isTrue (= true true true)) (Assert.isFalse (= true false true)) (Assert.isTrue (= false false false))) (function _testIf [] (Assert.equals true (if 1 true false)) (Assert.equals true (if 0 true false)) (Assert.equals true (if -1 true false)) (Assert.equals false (if null true false)) (Assert.equals true (if true true false)) (Assert.equals false (if false true false)) (Assert.equals true (if "string" true false)) (Assert.equals false (if "" true false)) (Assert.equals false (if [] true false)) (Assert.equals true (if [1] true false)) (Assert.equals 5 (if true 5)) (Assert.equals null (if false 5))) (var :Int myInt 8) (function myTryCatch [:Any e] (try (throw e) (catch [:String error] 5) (catch [:Int error] 6) (catch [error] 7))) (function myTypeCheck [] (the Int 5)) (function _testConcat [] (Assert.equals (.toString [1 2 3 4]) (.toString (concat [1] [2 3] [4])))) (function _testGroups [] (Assert.equals (.toString [[1 2] [3 4]]) (.toString (groups [1 2 3 4] 2))) (Assert.equals (.toString [[1 2 3] [4]]) (.toString (groups [1 2 3 4] 3 Keep))) (try (begin (groups [1 2 3 4] 3 Throw) (Assert.fail)) (catch [error] (Assert.pass)))) (function _testZip [] (Assert.equals (.toString [[1 2] [3 4]]) (.toString (zipThrow [1 3] [2 4]))) (Assert.equals (.toString [[1 2] [3 null]]) (.toString (zipKeep [1 3] [2]))) (Assert.equals (.toString [[1 2] [null 4]]) (.toString (zipKeep [1 null] [2 4]))) (try (begin (zipThrow [1 3] [2]) (Assert.fail)) (catch [error] (Assert.pass))) (try (begin (zipThrow [1] [2 4]) (Assert.fail)) (catch [error] (Assert.pass))) (Assert.equals (.toString [[1 2 3] [2 null 3]]) (.toString (zipKeep [1 2] [2] [3 3]))) (Assert.equals (.toString [[1 2]]) (.toString (zipDrop [1 2 3 4] [2]))) (Assert.equals (.toString [[1 2] [3 4]]) (.toString (apply zipThrow [[1 3] [2 4]])))) (function _testEnumerate [] (Assert.equals (.toString [[0 1] [1 2]]) (.toString (enumerate [1 2]))) (Assert.equals (.toString [[1 1] [2 2]]) (.toString (enumerate [1 2] 1)))) (function _testLet [] (let [a 5 b 6 :String c "stuff"] (Assert.equals 5 a) (Assert.equals 6 b) (Assert.equals "stuff" c)) (let [&mut a "str1"] (Assert.equals "str1" a) (set a "str2") (Assert.equals "str2" a))) (var myConstructedString (new String "sup")) (function _testCond [] (Assert.equals "this one" (cond ((= 5 6) "not this") ((= 8 9) "not this either") ((= 1 1) "this one") (true "not the default"))) (Assert.equals "the default" (cond ((= 5 6) "not this") ((= 8 9) "not this either") ((= 2 1) "not the third one") (true "the default"))) (Assert.equals "this" (cond ((= 5 5) "this") (true "default"))) (Assert.equals null (cond (false "not this")))) (function _testOr [] (Assert.equals 5 (or null 5)) // If the last value is falsy it can still be returned without breaking // the expected behavior of or -- which also allows for the (or ) // idiom for empty arrays and strings (Assert.equals (Std.string []) (Std.string (or null []))) (Assert.equals "" (or null [] ""))) (function _testAnd [] (Assert.equals 6 (and 5 6)) (Assert.isFalse ?(and false 5 6)) (Assert.isFalse ?(and 5 false 6))) (function mySetLocal [] (localVar &mut loc "one thing") (set loc "another thing") loc) (var myNot1 (not 5)) (var myNot2 !5) (var myFilteredList (begin (localVar l [-1 -2 5 -3 6]) (l.filter (lambda [v] (< 0 v))))) (var myWhen1 (when true 5 6)) (var myListOfTen [1 2 3 4 5 6 7 8 9 10]) (function _testQuickNths [] (Assert.equals 1 (first myListOfTen)) (Assert.equals 2 (second myListOfTen)) (Assert.equals 3 (third myListOfTen)) (Assert.equals 4 (fourth myListOfTen)) (Assert.equals 5 (fifth myListOfTen)) (Assert.equals 6 (sixth myListOfTen)) (Assert.equals 7 (seventh myListOfTen)) (Assert.equals 8 (eighth myListOfTen)) (Assert.equals 9 (ninth myListOfTen)) (Assert.equals 10 (tenth myListOfTen)) (Assert.equals 10 (last myListOfTen))) (function _testListDestructuring [] (localVar [a b c d &mut e f g h i j] myListOfTen) (Assert.equals 1 a) (Assert.equals 2 b) (Assert.equals 3 c) (Assert.equals 4 d) (Assert.equals 5 e) (set e 6) (Assert.equals 6 e) (Assert.equals 6 f) (Assert.equals 7 g) (Assert.equals 8 h) (Assert.equals 9 i) (Assert.equals 10 j) (let [[a b c &mut d e f g h i j] myListOfTen] (Assert.equals 1 a) (Assert.equals 2 b) (Assert.equals 3 c) (Assert.equals 4 d) (set d 6) (Assert.equals 6 d) (Assert.equals 5 e) (Assert.equals 6 f) (Assert.equals 7 g) (Assert.equals 8 h) (Assert.equals 9 i) (Assert.equals 10 j))) (var myMetaList [myListOfTen myListOfTen myListOfTen]) (function _testDoFor [] (localVar &mut c 0) (doFor v myListOfTen (Assert.equals (+ c 1) v) (set c v)) (doFor [a b c d e f g h i j] myMetaList (Assert.equals 1 a) (Assert.equals 2 b) (Assert.equals 3 c) (Assert.equals 4 d) (Assert.equals 5 e) (Assert.equals 6 f) (Assert.equals 7 g) (Assert.equals 8 h) (Assert.equals 9 i) (Assert.equals 10 j))) (function _testFor [] (localVar incrementedList (for v myListOfTen (+ 1 v))) (let [[a b c d e f g h i j] incrementedList] (Assert.equals 2 a) (Assert.equals 3 b) (Assert.equals 4 c) (Assert.equals 5 d) (Assert.equals 6 e) (Assert.equals 7 f) (Assert.equals 8 g) (Assert.equals 9 h) (Assert.equals 10 i) (Assert.equals 11 j)) (localVar smallerMetaList (for [a b c d e f g h i j] myMetaList [a e i])) (doFor [a e i] smallerMetaList (Assert.equals 1 a) (Assert.equals 5 e) (Assert.equals 10 i))) (function myOptionalFunc [a &opt b c] (Assert.equals 5 a) (Assert.equals null b) (Assert.equals 6 (or c 6))) // (or [optionalVar] [defaultValue]) is the convention for default values (function myRestSum [firstOne &rest :List others] (localVar &mut sum firstOne) (doFor nextOne others (set sum (+ sum nextOne))) sum) (var myRest1 (myRestSum 5)) (var myRest2 (myRestSum 1 1 1 1 1)) (var myRest3 (myRestSum 1 2 2)) (function myCombinedOptRest [firstOne &opt secondOne &rest :List thirdAndMore] (localVar &mut concatString (+ firstOne (or secondOne "boop"))) (doFor str thirdAndMore (set concatString (+ concatString str))) concatString) (var myCombined1 (myCombinedOptRest "a" "b" "c" "d")) (var myCombined2 (myCombinedOptRest "a")) (var myCombined3 (myCombinedOptRest "a" "b")) (function _testFieldExps [] (Assert.equals "hey" (.trim " hey ")) (Assert.equals "e" (.charAt (.trim " hey ") 1))) (function _testBreakContinue [] (let [[a b c] (for val [1 2 3 4 5 6 7 8] (if (> val 6) (break) (if !(= 0 (% val 2)) (continue) val)))] (Assert.equals 2 a) (Assert.equals 4 b) (Assert.equals 6 c))) (function _testAssert [] (try (assert false (+ "false " "should " "have " "been " "true")) (catch [:String message] (Assert.equals "Assertion false failed: false should have been true" message))) (assert true) (assert ![])) (function _testApply [] (Assert.equals 6 (apply + [1 2 3]))) (function applyWithMethod [obj] (apply .multiply obj [6])) (function _testAnonymousObject [] (let [obj (object a "string A" b 5)] (Assert.equals "string A" obj.a) (Assert.equals 5 obj.b))) (function toOption [:Dynamic value] (if value (Some value) None)) (function _testCase [] (case (toOption []) (None (Assert.pass)) (otherwise (Assert.fail))) (case (toOption "hey") (None (Assert.fail)) ((Some "hey") (Assert.pass)) (otherwise (Assert.fail))) (Assert.equals 5 (case (toOption 0) (otherwise 5))) // Test case with guards and multiple values (case 5 ((or 5 6) (Assert.pass)) (otherwise (Assert.fail))) (case [2 3] ((or [_ 3] [1 1]) (Assert.pass)) (otherwise (Assert.fail))) (case 5 ((when false (or 5 6)) (Assert.fail)) ((when true (or 7 8 9)) (Assert.fail)) (otherwise (Assert.pass))) (case 5 ((unless true (or 5 6)) (Assert.fail)) ((unless false (or 7 8 9)) (Assert.fail)) (otherwise (Assert.pass))) // In Haxe, // `switch (Some(true)) { case Some(true | false): "a"; default: "b"; }` // returns "a", so nested use of `or` in case patterns should also be valid: (case (Some true) ((Some (or true false)) (Assert.pass)) (otherwise (Assert.fail))) (case (Some 5) ((Some (or 6 5 4)) (Assert.pass)) (otherwise (Assert.fail))) // In Haxe, name = Pattern can be used in switch/case to match values: https://haxe.org/manual/lf-pattern-matching-variable-capture.html // In Kiss, the syntax for this is (as name pattern) (case (Some (Some 5)) ((Some (as inner (Some v))) (Assert.equals 5 v) (Assert.isTrue (Type.enumEq (Some 5) inner))) (otherwise (Assert.fail))) // Otherwise blocks should allow multiple expressions, too: (case 5 (otherwise 6 5))) (function _testMaps [] (localVar :Map myMap [=>"hey" "you" =>"found" "me"]) (Assert.equals "you" (dictGet myMap "hey")) (Assert.equals "me" (dictGet myMap "found")) (doFor =>key value myMap (assertLet [(Some _) (indexOf ["hey" "found"] key)] 0) (assertLet [(Some _) (indexOf ["you" "me"] value)] 0)) // Map destructuring: (let [[=>"hey" v1 =>"found" v2] myMap] (Assert.equals "you" v1) (Assert.equals "me" v2))) (function _testRange [] // With just one arg, it's the max: (localVar &mut :kiss.List myList (for i (range 5) i)) (Assert.equals 4 (nth myList -1)) // with two args, they are min and max: (set myList (for i (range 3 5) i)) (Assert.equals 3 (first myList)) (Assert.equals 4 (last myList)) // With three args, they are min, max, and step: (set myList (for i (range 7 17 2) i)) (Assert.equals 7 (first myList)) (Assert.equals 9 (second myList)) (Assert.equals 15 (last myList))) (function _testRest [] (Assert.equals (.toString [2 3 4]) (.toString (rest [1 2 3 4])))) (function doSomething [:Int->Int func] (func 5)) (function itsAMonster [:Null>>> monsterArg] "but it still compiles") (function _testTypeParsing [] // Do stuff with functions that take complex type parameters, mostly just to check if it compiles (Assert.equals 5 (doSomething (lambda [i] i))) (Assert.equals 7 (doSomething (lambda [i] (+ i 2)))) // Pass null to the really crazy one because I'm lazy: (Assert.equals "but it still compiles" (itsAMonster null))) (defMacro defconstfunc [name const] `(function ,name [] ,const)) (defconstfunc func5 5) (defconstfunc funcHello "hello") (function _testDefmacro [] (Assert.equals 5 (func5)) (Assert.equals "hello" (funcHello))) (var &mut welcomeCount 0) (defMacro macroWithLogic [name] (localVar message1 (ReaderExp.StrExp "Welcome ")) (localVar message2 (ReaderExp.StrExp " (Guest #")) (localVar message3 (ReaderExp.StrExp ")")) `(begin (set welcomeCount (+ welcomeCount 1)) (+ ,message1 ,name ,message2 (Std.string welcomeCount) ,message3))) (function _testDefmacroWithLogic [] (Assert.equals "Welcome Stevo (Guest #1)" (macroWithLogic "Stevo")) (Assert.equals "Welcome Bob (Guest #2)" (macroWithLogic "Bob"))) // Make sure built-in call aliases don't override user-defined variables (function _testCallAlias [] (let [map [=>"hey" "you"]] (Assert.equals "you" (dictGet map "hey")))) (function _testAssignArith [] (localVar &mut num 5) (+= num 5 6) (Assert.equals 16 num) (%= num 5) (Assert.equals 1 num) (^= num 3) (Assert.equals 1 num) (*= num 25 2) (Assert.equals 50 num) (/= num 25 2) (Assert.equals 1 num) (-= num 5 6) (Assert.equals -10 num)) (function _testPatternLets [] (let [some5 (Some 5) some6 (Some 6) none None :Null> oops null] (ifLet [(Some a) some5 (Some b) some6] (Assert.equals 11 (+ a b)) (Assert.fail)) (ifLet [(Some a) none] (Assert.fail)) (whenLet [(Some a) oops] (print "something went wrong!") (Assert.fail)) (unlessLet [(Some (or 5 6)) some5] (print "something else went wrong!") (Assert.fail)) // Don't double evaluate the expression: (let [&mut v 1] (unlessLet [2 (begin (+= v 1) v)] (Assert.fail)) (Assert.equals 2 v)) (assertThrows (assertLet [(Some thing) none] thing)) (Assert.equals 5 (assertLet [(Some thing) some5] thing)))) (function _testRawString [] (Assert.equals #| "\\" |# #"\"#) (Assert.equals #| "\"#" |# ##""#"##)) (function _testKissStrings [] (Assert.equals #| "\\\t\r\n\"$" |# "\\\t\r\n\"\$") (let [str "it's" num 3 l1 ["a" "b" "c"] l2 [1 2 3]] // string interpolation: (Assert.equals "it's 3asy as [a,b,c] [1,2,3]" "$str ${num}asy as $l1 $l2"))) (function _testArrowLambdas [] (let [withArgs ->[arg1 arg2] (+ arg1 arg2) withArg ->arg (* 2 arg) withoutArgs ->{ (+ 5) 6} &mut num 5 void ->:Void [] (set num 6)] (Assert.equals 11 (withArgs 5 6)) (Assert.equals 12 (withArg 6)) (Assert.equals 6 (withoutArgs)) (void) (Assert.equals 6 num))) (var &mut voidRan false) (function :Void myVoid [] (set voidRan true)) (function _testVoid [] (myVoid) (Assert.isTrue voidRan)) (function _testLetThrow [] (try { (letThrow (throw "the error we want") (catch [e] (Assert.fail))) (Assert.fail)} (catch [:String e] (Assert.equals "the error we want" e)))) // Test dot-access on identifiers aliases (var objWithField (object field 5)) (var float 0.5) // This should still read as a float, not a dot access on a variable called 0 (defAlias &ident owf objWithField) (function _testDotAccessOnAlias [] (Assert.equals 5 owf.field)) (function _testClamp [] (let [&mut bigValue 12 &mut smallValue 3] (Assert.equals 10 (clamp bigValue 5 10)) (Assert.equals 10 bigValue) (Assert.equals 5 (clamp smallValue 5 10)) (Assert.equals 5 smallValue))) (function _testCountingLambda [] (let [fullSyntax (countingLambda a [] a) arrowSyntax -+>b {b}] (Assert.equals 1 (fullSyntax)) (Assert.equals 2 (fullSyntax)) (Assert.equals 1 (arrowSyntax)) (Assert.equals 2 (arrowSyntax)))) (function _testExpComment [] (Assert.equals 15 (+ **6 5 **(- 5 11) 5 (+ 5 **(20 9))))) (var staticValue 9) (prop value 2) (method _testEval [] (Assert.equals 9 (eval 'staticValue)) (Assert.equals 2 (eval 'value)) (Assert.equals 11 (eval '(+ staticValue value)))) (function _testEvalStatic [] (Assert.equals 9 (eval 'staticValue)) (assertThrows (eval 'value))) (function _testCaseOnNull [] (Assert.equals 5 (case null (v 10) (null 5))) (Assert.equals 5 (case null (v 10) (null 5) (otherwise 6))) (Assert.equals 5 (case null (v 10) (otherwise 5)))) (function _testContains [] (assert (contains "abc" "b")) (assert !(contains "abc" "z")) (assert (contains [1 2 3] 1)) (assert !(contains [1 2 3] 5)) (Assert.pass)) (function _testIntersect [] (let [intersection2d (for i (the Array> (intersect (.split "abc" "") (.split "xyz" ""))) (i.join "")) intersection3d (for i (the Array> (intersect (.split "abc" "") (.split "xyz" "") (.split "123" ""))) (i.join ""))] (assert (contains intersection2d "ax")) (assert (contains intersection2d "ay")) (assert (contains intersection2d "az")) (assert (contains intersection2d "bx")) (assert (contains intersection2d "by")) (assert (contains intersection2d "bz")) (assert (contains intersection2d "cx")) (assert (contains intersection2d "cy")) (assert (contains intersection2d "cz")) (assert (contains intersection3d "ax1")) (assert (contains intersection3d "ax3")) (assert (contains intersection3d "bx3")) (assert (contains intersection3d "cy1")) (assert (contains intersection3d "cy3")) ) (Assert.pass))