countingLambda
This commit is contained in:
@@ -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;
|
||||
}
|
||||
|
||||
|
@@ -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) -> {
|
||||
|
@@ -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;
|
||||
|
@@ -317,6 +317,10 @@ class BasicTestCase extends Test {
|
||||
function testClamp() {
|
||||
_testClamp();
|
||||
}
|
||||
|
||||
function testCountingLambda() {
|
||||
_testCountingLambda();
|
||||
}
|
||||
}
|
||||
|
||||
class BasicObject {
|
||||
|
@@ -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))))
|
Reference in New Issue
Block a user