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