Experimental typeCase macro

This commit is contained in:
2022-12-16 02:35:46 +00:00
parent 78413179b4
commit 9510ca75b9
3 changed files with 78 additions and 1 deletions

View File

@@ -1437,7 +1437,67 @@ class Macros {
// Prelude.print(Reader.toString(exp.def));
exp;
};
k.doc("typeCase", 2, null, "(typeCase [<values>] ([:<Type> <name> <more typed names...>] <body>) <more cases...> (otherwise <required default>))");
macros["typeCase"] = (wholeExp:ReaderExp, args:Array<ReaderExp>, k:KissState) -> {
var b = wholeExp.expBuilder();
var argsListExp = args.shift();
var argsList = Helpers.argList(argsListExp, "typeCase", false);
var cases:kiss.List<ReaderExp> = [for (c in args) {
Prelude.print(c.expBuilder().neverCase());
}];
Helpers.checkNoEarlyOtherwise(cases);
var symbols = [for (i in 0...argsList.length) b.symbol()];
var dynamicSymbols = [for (s in symbols) b.typed("Dynamic", s)];
var outerLetBindings = [];
for (i in 0...argsList.length) {
outerLetBindings.push(dynamicSymbols[i]);
outerLetBindings.push(argsList[i]);
}
cases = [for (c in cases) {
var b = c.expBuilder();
switch (c.def) {
case CallExp({pos:_, def:ListExp(typedNames)}, body):
var names = [];
var types = [];
var typesWithoutGenerics = [];
for (exp in typedNames) {
switch (exp.def) {
case TypedExp(type, nameSymbol):
names.push(nameSymbol);
types.push(type);
if (type.contains("<")) {
type = type.substr(type.indexOf("<"));
}
typesWithoutGenerics.push(type);
default:
throw KissError.fromExp(c, "bad typeCase case");
}
}
var letBindings = [];
for (i in 0...names.length) {
letBindings.push(typedNames[i]);
letBindings.push(names[i]);
}
b.call(b.callSymbol("when", [b.callSymbol("and", [
for (i in 0...names.length) {
b.callSymbol("Std.isOfType", [names[i], b.symbol(typesWithoutGenerics[i])]);
}
]), b.list(names)]), [b.let(letBindings, body)]);
default: c;
}
}];
b.let(outerLetBindings, [
b.callSymbol("case", [b.list(symbols)].concat(cases))
]);
}
return macros;
}

View File

@@ -400,6 +400,10 @@ class BasicTestCase extends Test {
_testPrintMacrosCheck();
}
function testTypeCase() {
_testTypeCase();
}
var aNullToPrint = null;
}

View File

@@ -757,4 +757,17 @@ From:[(assert false (+ \"false \" \"should \" \"have \" \"been \" \"true\"))]" m
(let [u "good"]
(localVar v "bad")
(printLocalNulls))
(Assert.pass))
(Assert.pass))
(function :Void _testTypeCase []
(typeCase ["a"]
([:String a]
(Assert.equals "a" a)))
(typeCase ["a" 1]
(never [:String a :String one])
([:String a :Int one]
(Assert.equals "a1" "${a}${one}")))
(typeCase ["a" 5 5.5 true]
([:String a :Int five :Float fivePointFive :Bool tt]
(Assert.equals "a55.5true" "${a}${five}${fivePointFive}${tt}"))
(never otherwise)))