countingLambda

This commit is contained in:
2021-11-14 13:54:32 -07:00
parent c4106eed90
commit bb28737e61
5 changed files with 55 additions and 6 deletions

View File

@@ -1039,6 +1039,25 @@ class Macros {
]));
};
macros["countingLambda"] = (wholeExp:ReaderExp, exps:Array<ReaderExp>, k:KissState) -> {
wholeExp.checkNumArgs(3, null, "(countingLambda <countVar> [<argsNames...>] <body...>)");
var b = wholeExp.expBuilder();
var countVarSymbol = exps[0];
var args = exps[1];
var body = exps.slice(2);
return b.let([
b.meta("mut", countVarSymbol), b.int(0)
], [b.callSymbol("lambda", [
args,
b.callSymbol("+=", [
countVarSymbol,
b.int(1)
])
].concat(body))]);
};
return macros;
}

View File

@@ -96,8 +96,17 @@ class Reader {
// ->[args] body
// ->arg body
// ->{body}
// or any of those with the first expression after -> prefixed by :Void
readTable["->"] = (stream:Stream, k) -> {
// OR, for countingLambda:
// -+>countVar [args] body
// -+>countVar arg body
// -+>countVar {body}
// or any of those with the first expression after -> or -+> prefixed by :Void
function arrowSyntax(countingLambda:Bool, stream:Stream, k:KissState) {
var countVar = if (countingLambda) {
assertRead(stream, k);
} else {
null;
}
var firstExp = assertRead(stream, k);
var b = firstExp.expBuilder();
@@ -127,8 +136,15 @@ class Reader {
if (!returnsValue) {
argsExp = TypedExp("Void", argsExp).withPosOf(argsExp);
}
CallExp(b.symbol("lambda"), [argsExp, bodyExp]);
};
return if (countingLambda) {
CallExp(b.symbol("countingLambda"), [countVar, argsExp, bodyExp]);
} else {
CallExp(b.symbol("lambda"), [argsExp, bodyExp]);
};
}
readTable["->"] = arrowSyntax.bind(false);
readTable["-+>"] = arrowSyntax.bind(true);
// Because macro keys are sorted by length and peekChars(0) returns "", this will be used as the default reader macro:
readTable[""] = (stream:Stream, k:KissState) -> {

View File

@@ -204,7 +204,7 @@ class SpecialForms {
};
map["lambda"] = (wholeExp:ReaderExp, args:Array<ReaderExp>, k:KissState) -> {
wholeExp.checkNumArgs(2, null, "(lambda [[argsNames...]] [body...])");
wholeExp.checkNumArgs(2, null, "(lambda [<argsNames...>] <body...>)");
var returnsValue = switch (args[0].def) {
case TypedExp("Void", argNames):
args[0] = argNames;

View File

@@ -317,6 +317,10 @@ class BasicTestCase extends Test {
function testClamp() {
_testClamp();
}
function testCountingLambda() {
_testCountingLambda();
}
}
class BasicObject {

View File

@@ -560,4 +560,14 @@
(Assert.equals 10 (clamp bigValue 5 10))
(Assert.equals 10 bigValue)
(Assert.equals 5 (clamp smallValue 5 10))
(Assert.equals 5 smallValue)))
(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))))