diff --git a/kiss/src/kiss/SpecialForms.hx b/kiss/src/kiss/SpecialForms.hx index 6c3306a9..0e908a7e 100644 --- a/kiss/src/kiss/SpecialForms.hx +++ b/kiss/src/kiss/SpecialForms.hx @@ -322,6 +322,23 @@ class SpecialForms { // to cover all patterns. var args:kiss.List = args.copy(); + var cases:kiss.List = args.slice(1); + for (i in 0...cases.length) { + switch (cases[i].def) { + case CallExp({pos: _, def: Symbol("never")}, neverExps): + cases[i].checkNumArgs(1, 1, '(never )'); + var b = cases[i].expBuilder(); + var failureError = KissError.fromExp(cases[i], '').toString(AssertionFail); + var colonsInPrefix = if (Sys.systemName() == "Windows") 5 else 4; + cases[i] = b.call(neverExps[0], [ + b.callSymbol('throw', [ + b.callSymbol('kiss.Prelude.runtimeInsertAssertionMessage', [b.str('${Reader.toString(neverExps[0].def)} should never match pattern ${Reader.toString(neverExps[0].def)}'), b.str(failureError), b.int(colonsInPrefix)])])]); + case CallExp({pos: _, def: Symbol("otherwise")}, _) if (i != cases.length - 1): + throw KissError.fromExp(cases[i], "(otherwise ) branch must come last in a (case <...>) expression"); + default: + } + } + var isTupleCase = switch (args[0].def) { case ListExp(_): true; @@ -330,9 +347,9 @@ class SpecialForms { } var b = wholeExp.expBuilder(); - var defaultExpr = switch (args[-1].def) { + var defaultExpr = switch (cases[-1].def) { case CallExp({pos: _, def: Symbol("otherwise")}, otherwiseExps): - args.pop(); + cases.pop(); k.convert(b.begin(otherwiseExps)); default: null; @@ -342,7 +359,7 @@ class SpecialForms { var canCompareNull = !isTupleCase; - var cases = args.slice(1); + // case also override's haxe's switch() behavior by refusing to match null values against patterns. if (canCompareNull) { var nullExpr = defaultExpr; diff --git a/kiss/src/test/cases/BasicTestCase.kiss b/kiss/src/test/cases/BasicTestCase.kiss index 35fbe057..faa2f41f 100644 --- a/kiss/src/test/cases/BasicTestCase.kiss +++ b/kiss/src/test/cases/BasicTestCase.kiss @@ -363,11 +363,11 @@ From:[(assert false (+ \"false \" \"should \" \"have \" \"been \" \"true\"))]" m (function _testCase [] (case (toOption []) (None (Assert.pass)) - (otherwise (Assert.fail))) + (never otherwise)) (case (toOption "hey") - (None (Assert.fail)) + (never None) ((Some "hey") (Assert.pass)) - (otherwise (Assert.fail))) + (never otherwise)) (Assert.equals 5 (case (toOption 0) (otherwise 5))) // Test case with guards and multiple values