Void function support

This commit is contained in:
2021-03-17 11:15:12 -06:00
parent 64e31cfb8b
commit 96d08e5d88
6 changed files with 52 additions and 8 deletions

View File

@@ -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()
};
}

View File

@@ -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
}
}

View File

@@ -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]);
};

View File

@@ -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) {

View File

@@ -285,6 +285,10 @@ class BasicTestCase extends Test {
function testArrowLambdas() {
_testArrowLambdas();
}
function testVoid() {
_testVoid();
}
}
class BasicObject {

View File

@@ -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))