Nested (or) in (case) patterns

This commit is contained in:
2021-01-04 09:02:06 -07:00
parent 79a68ec233
commit 95fa5e5a12
4 changed files with 19 additions and 10 deletions

View File

@@ -164,9 +164,6 @@ class Helpers {
throw CompileError.fromExp(caseExp, "case expression can only have one `when` guard"); throw CompileError.fromExp(caseExp, "case expression can only have one `when` guard");
guard = macro Prelude.truthy(${k.convert(whenExps[0])}); guard = macro Prelude.truthy(${k.convert(whenExps[0])});
makeSwitchPattern(whenExps[1]); makeSwitchPattern(whenExps[1]);
case CallExp({pos: _, def: Symbol("or")}, orExps):
patternExp.checkNumArgs(2, null, "(or [pattern1] [pattern2] [patterns...])");
orExps.map(k.forCaseParsing().convert);
default: default:
[k.forCaseParsing().convert(patternExp)]; [k.forCaseParsing().convert(patternExp)];
} }

View File

@@ -220,6 +220,8 @@ class Kiss {
public static function forCaseParsing(k:KissState):KissState { public static function forCaseParsing(k:KissState):KissState {
var copy = Reflect.copy(k); var copy = Reflect.copy(k);
copy.wrapListExps = false; copy.wrapListExps = false;
k.macros.remove("or");
k.specialForms["or"] = SpecialForms.caseOr;
return copy; return copy;
} }

View File

@@ -335,4 +335,13 @@ class SpecialForms {
return map; return map;
} }
public static function caseOr(wholeExp:ReaderExp, args:Array<ReaderExp>, k:KissState):Expr {
wholeExp.checkNumArgs(2, null, "(or [v1] [v2] [values...])");
return if (args.length == 2) {
macro ${k.convert(args[0])} | ${k.convert(args[1])};
} else {
macro ${k.convert(args[0])} | ${caseOr(wholeExp, args.slice(1), k)};
};
};
} }

View File

@@ -341,16 +341,17 @@
(case 5 (case 5
((when false (or 5 6)) (Assert.fail)) ((when false (or 5 6)) (Assert.fail))
(otherwise (Assert.pass))) (otherwise (Assert.pass)))
// TODO in Haxe, // In Haxe,
// `switch (Some(true)) { case Some(true | false): "a"; default: "b"; }` // `switch (Some(true)) { case Some(true | false): "a"; default: "b"; }`
// returns "a", so this should also be valid: // returns "a", so nested use of `or` in case patterns should also be valid:
/*(case (Some true) (case (Some true)
((Some (or true false)) ((Some (or true false))
(Assert.pass)) (Assert.pass))
(otherwise (Assert.fail)))*/ (otherwise (Assert.fail)))
// ^ Implement by overriding the `or` macro with an `or` special form to return variadically nested OpOr binop exps (case (Some 5)
// in KissState.forCaseParsing() instead of handling CallExp(Symbol(or)) specially ((Some (or 6 5 4))
) (Assert.pass))
(otherwise (Assert.fail))))
(defun _testMaps [] (defun _testMaps []
(deflocal :Map<String,String> myMap [=>"hey" "you" (deflocal :Map<String,String> myMap [=>"hey" "you"