Void function support
This commit is contained in:
@@ -98,11 +98,17 @@ class FieldForms {
|
||||
|
||||
var name = fieldName(formName, args[0]);
|
||||
var access = fieldAccess(formName, name, args[0]);
|
||||
var returnsValue = switch (args[0].def) {
|
||||
case TypedExp("Void", _):
|
||||
false;
|
||||
default:
|
||||
true;
|
||||
};
|
||||
|
||||
return {
|
||||
name: name,
|
||||
access: access,
|
||||
kind: FFun(Helpers.makeFunction(args[0], args[1], args.slice(2), k)),
|
||||
kind: FFun(Helpers.makeFunction(args[0], returnsValue, args[1], args.slice(2), k)),
|
||||
pos: wholeExp.macroPos()
|
||||
};
|
||||
}
|
||||
|
@@ -58,11 +58,11 @@ class Helpers {
|
||||
}
|
||||
|
||||
// TODO generic type parameter declarations
|
||||
public static function makeFunction(?name:ReaderExp, argList:ReaderExp, body:List<ReaderExp>, k:KissState):Function {
|
||||
public static function makeFunction(?name:ReaderExp, returnsValue:Bool, argList:ReaderExp, body:List<ReaderExp>, k:KissState):Function {
|
||||
if (name != null) {
|
||||
switch (name.def) {
|
||||
case MetaExp(_, name):
|
||||
return makeFunction(name, argList, body, k);
|
||||
return makeFunction(name, returnsValue, argList, body, k);
|
||||
default:
|
||||
}
|
||||
}
|
||||
@@ -132,6 +132,11 @@ class Helpers {
|
||||
};
|
||||
}
|
||||
|
||||
var expr = k.convert(CallExp(Symbol("begin").withPos(body[0].pos), body).withPos(body[0].pos));
|
||||
if (returnsValue) {
|
||||
expr = EReturn(expr).withMacroPosOf(body[-1]);
|
||||
}
|
||||
|
||||
// To make function args immutable by default, we would use (let...) instead of (begin...)
|
||||
// to make the body expression.
|
||||
// But setting default arguments is so common, and arguments are not settable references,
|
||||
@@ -149,7 +154,7 @@ class Helpers {
|
||||
default:
|
||||
throw CompileError.fromExp(argList, 'expected an argument list');
|
||||
},
|
||||
expr: EReturn(k.convert(CallExp(Symbol("begin").withPos(body[0].pos), body).withPos(body[0].pos))).withMacroPosOf(body[-1])
|
||||
expr: expr
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -97,6 +97,7 @@ class Reader {
|
||||
// ->[args] body
|
||||
// ->arg body
|
||||
// ->{body}
|
||||
// or any of those with the first expression after -> prefixed by :Void
|
||||
readTable["->"] = (stream, k) -> {
|
||||
var firstExp = assertRead(stream, k);
|
||||
var b = firstExp.expBuilder();
|
||||
@@ -104,6 +105,13 @@ class Reader {
|
||||
var argsExp:ReaderExp = null;
|
||||
var bodyExp:ReaderExp = null;
|
||||
|
||||
var returnsValue = true;
|
||||
switch (firstExp.def) {
|
||||
case TypedExp("Void", realFirstExp):
|
||||
firstExp = realFirstExp;
|
||||
returnsValue = false;
|
||||
default:
|
||||
}
|
||||
switch (firstExp.def) {
|
||||
case ListExp(_):
|
||||
argsExp = firstExp;
|
||||
@@ -115,7 +123,10 @@ class Reader {
|
||||
argsExp = b.list([]);
|
||||
bodyExp = firstExp;
|
||||
default:
|
||||
throw CompileError.fromExp(firstExp, "first expression after -> should be [args...], arg, or {body}");
|
||||
throw CompileError.fromExp(firstExp, "first expression after -> should be [args...], arg, or {body}, or one of those prefixed with :Void");
|
||||
}
|
||||
if (!returnsValue) {
|
||||
argsExp = TypedExp("Void", argsExp).withPosOf(argsExp);
|
||||
}
|
||||
CallExp(b.symbol("lambda"), [argsExp, bodyExp]);
|
||||
};
|
||||
|
@@ -186,7 +186,14 @@ class SpecialForms {
|
||||
|
||||
map["lambda"] = (wholeExp:ReaderExp, args:Array<ReaderExp>, k:KissState) -> {
|
||||
wholeExp.checkNumArgs(2, null, "(lambda [[argsNames...]] [body...])");
|
||||
EFunction(FAnonymous, Helpers.makeFunction(null, args[0], args.slice(1), k)).withMacroPosOf(wholeExp);
|
||||
var returnsValue = switch (args[0].def) {
|
||||
case TypedExp("Void", argNames):
|
||||
args[0] = argNames;
|
||||
false;
|
||||
default:
|
||||
true;
|
||||
}
|
||||
EFunction(FAnonymous, Helpers.makeFunction(null, returnsValue, args[0], args.slice(1), k)).withMacroPosOf(wholeExp);
|
||||
};
|
||||
|
||||
function forExpr(formName:String, wholeExp:ReaderExp, args:Array<ReaderExp>, k:KissState) {
|
||||
|
@@ -285,6 +285,10 @@ class BasicTestCase extends Test {
|
||||
function testArrowLambdas() {
|
||||
_testArrowLambdas();
|
||||
}
|
||||
|
||||
function testVoid() {
|
||||
_testVoid();
|
||||
}
|
||||
}
|
||||
|
||||
class BasicObject {
|
||||
|
@@ -476,7 +476,18 @@
|
||||
withoutArgs
|
||||
->{
|
||||
(+ 5)
|
||||
6}]
|
||||
6}
|
||||
&mut num 5
|
||||
void
|
||||
->:Void [] (set num 6)]
|
||||
(Assert.equals 11 (withArgs 5 6))
|
||||
(Assert.equals 12 (withArg 6))
|
||||
(Assert.equals 6 (withoutArgs))))
|
||||
(Assert.equals 6 (withoutArgs))
|
||||
(void)
|
||||
(Assert.equals 6 num)))
|
||||
|
||||
(defvar &mut voidRan false)
|
||||
(defun :Void myVoid [] (set voidRan true))
|
||||
(defun _testVoid []
|
||||
(myVoid)
|
||||
(Assert.isTrue voidRan))
|
Reference in New Issue
Block a user