awaitLet allow synchronous bindings. Close #68

This commit is contained in:
2022-06-18 20:23:59 +00:00
parent da6bdd47c2
commit 77aa81378e

View File

@@ -699,48 +699,60 @@ class Macros {
macros["assertLet"] = ifLet.bind(true); macros["assertLet"] = ifLet.bind(true);
k.doc("awaitLet", 2, null, "(awaitLet [<promise bindings...>] <?catchHandler> <body...>)"); k.doc("awaitLet", 2, null, "(awaitLet [<promise bindings...>] <?catchHandler> <body...>)");
function awaitLet(wholeExp:ReaderExp, exps:Array<ReaderExp>, k:KissState) { function awaitLet(rejectionHandler:ReaderExp->ReaderExp, wholeExp:ReaderExp, exps:Array<ReaderExp>, k:KissState) {
var bindingList = exps[0].bindingList("awaitLet"); var bindingList = exps[0].bindingList("awaitLet");
var firstName = bindingList.shift(); var firstName = bindingList.shift();
var firstValue = bindingList.shift(); var firstValue = bindingList.shift();
var b = wholeExp.expBuilder(); var b = wholeExp.expBuilder();
var firstNameStr = firstName.symbolNameValue(); if (rejectionHandler == null) {
var error = b.callSymbol("+", [b.str('awaitLet $firstNameStr rejected promise: '), b.symbol("reason")]); function error(firstName:ReaderExp) {
var rejectionHandler = switch (exps[1].def) { return b.callSymbol("+", [b.str('awaitLet ${firstName.symbolNameValue()} rejected promise: '), b.symbol("reason")]);
}
rejectionHandler = switch (exps[1].def) {
case CallExp({pos: _, def: Symbol("catch")}, args): case CallExp({pos: _, def: Symbol("catch")}, args):
exps.splice(1,1); exps.splice(1,1);
b.callSymbol("lambda", args); (exp) -> b.callSymbol("lambda", args);
default: default:
b.callSymbol("lambda", [ (firstName) -> b.callSymbol("lambda", [
b.list([b.symbol("reason")]), b.list([b.symbol("reason")]),
b.callSymbol("#when", [ b.callSymbol("#when", [
b.symbol("vscode"), b.symbol("vscode"),
b.callSymbol("Vscode.window.showErrorMessage", [error]), b.callSymbol("Vscode.window.showErrorMessage", [error(firstName)]),
]), ]),
// If running VSCode js, this throw will be a no-op but it makes the expression type-unify: // If running VSCode js, this throw will be a no-op but it makes the expression type-unify:
b.callSymbol("throw", [ b.callSymbol("throw", [
error error(firstName)
]) ])
]); ]);
} }
}
var innerExp = if (bindingList.length == 0) {
b.begin(exps.slice(1));
} else {
awaitLet(rejectionHandler, wholeExp, [b.list(bindingList)].concat(exps.slice(1)), k);
};
switch(firstName.def) {
case MetaExp("sync", firstName):
return b.let([firstName, firstValue], [innerExp]);
case MetaExp(other, _):
throw KissError.fromExp(firstName, 'bad meta annotation &$other');
default:
}
return b.call(b.field("then", firstValue), [ return b.call(b.field("then", firstValue), [
b.callSymbol("lambda", [ b.callSymbol("lambda", [
b.list([firstName]), b.list([firstName]),
if (bindingList.length == 0) { innerExp
b.begin(exps.slice(1));
} else {
awaitLet(wholeExp, [b.list(bindingList)].concat(exps.slice(1)), k);
}
]), ]),
// Handle rejections: // Handle rejections:
rejectionHandler rejectionHandler(firstName)
]); ]);
} }
macros["awaitLet"] = awaitLet; macros["awaitLet"] = awaitLet.bind(null);
k.doc("whileLet", 2, null, "(whileLet [<bindings...>] <body...>)"); k.doc("whileLet", 2, null, "(whileLet [<bindings...>] <body...>)");
macros["whileLet"] = (wholeExp:ReaderExp, exps:Array<ReaderExp>, k:KissState) -> { macros["whileLet"] = (wholeExp:ReaderExp, exps:Array<ReaderExp>, k:KissState) -> {