From ca206ccc7e6de053c3a740cfa41c51d323254c42 Mon Sep 17 00:00:00 2001 From: Nat Quayle Nelson Date: Wed, 17 Mar 2021 11:15:12 -0600 Subject: [PATCH] Void function support --- kiss/src/kiss/FieldForms.hx | 8 +++++++- kiss/src/kiss/Helpers.hx | 11 ++++++++--- kiss/src/kiss/Reader.hx | 13 ++++++++++++- kiss/src/kiss/SpecialForms.hx | 9 ++++++++- kiss/src/test/cases/BasicTestCase.hx | 4 ++++ kiss/src/test/cases/BasicTestCase.kiss | 15 +++++++++++++-- 6 files changed, 52 insertions(+), 8 deletions(-) diff --git a/kiss/src/kiss/FieldForms.hx b/kiss/src/kiss/FieldForms.hx index e41368c7..671d7ae0 100644 --- a/kiss/src/kiss/FieldForms.hx +++ b/kiss/src/kiss/FieldForms.hx @@ -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() }; } diff --git a/kiss/src/kiss/Helpers.hx b/kiss/src/kiss/Helpers.hx index bb8375ed..d51b9f09 100644 --- a/kiss/src/kiss/Helpers.hx +++ b/kiss/src/kiss/Helpers.hx @@ -58,11 +58,11 @@ class Helpers { } // TODO generic type parameter declarations - public static function makeFunction(?name:ReaderExp, argList:ReaderExp, body:List, k:KissState):Function { + public static function makeFunction(?name:ReaderExp, returnsValue:Bool, argList:ReaderExp, body:List, 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 } } diff --git a/kiss/src/kiss/Reader.hx b/kiss/src/kiss/Reader.hx index b195cc5f..49f89cea 100644 --- a/kiss/src/kiss/Reader.hx +++ b/kiss/src/kiss/Reader.hx @@ -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]); }; diff --git a/kiss/src/kiss/SpecialForms.hx b/kiss/src/kiss/SpecialForms.hx index 7d697e00..cff35f3b 100644 --- a/kiss/src/kiss/SpecialForms.hx +++ b/kiss/src/kiss/SpecialForms.hx @@ -186,7 +186,14 @@ class SpecialForms { map["lambda"] = (wholeExp:ReaderExp, args:Array, 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, k:KissState) { diff --git a/kiss/src/test/cases/BasicTestCase.hx b/kiss/src/test/cases/BasicTestCase.hx index 0bb8d889..8d0db9a8 100644 --- a/kiss/src/test/cases/BasicTestCase.hx +++ b/kiss/src/test/cases/BasicTestCase.hx @@ -285,6 +285,10 @@ class BasicTestCase extends Test { function testArrowLambdas() { _testArrowLambdas(); } + + function testVoid() { + _testVoid(); + } } class BasicObject { diff --git a/kiss/src/test/cases/BasicTestCase.kiss b/kiss/src/test/cases/BasicTestCase.kiss index a7d3e6f1..9a5f4026 100644 --- a/kiss/src/test/cases/BasicTestCase.kiss +++ b/kiss/src/test/cases/BasicTestCase.kiss @@ -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)))) \ No newline at end of file + (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)) \ No newline at end of file