diff --git a/docs/TODO.txt b/docs/TODO.txt index 3bc560e..428861d 100644 --- a/docs/TODO.txt +++ b/docs/TODO.txt @@ -19,13 +19,12 @@ DONE: functions are invoked by calling their names DONE: function arguments can have specified types DONE: function returns can have specified types DONE: closures are explicitly supported +DONE: functions are first-class citizens +DONE: functions take a set number of parameters -TODO: functions take a set number of parameters -TODO: functions can return a set number of values -TODO: functions are first-class citizens +TODO: functions return a set number of values TODO: functions last argument can be a rest parameter -TODO: check for wrong number of function parameters TODO: Nullish types TODO: A way to check the type of a variable (typeOf keyword) diff --git a/docs/spec.md b/docs/spec.md index 798cd4f..3f39eec 100644 --- a/docs/spec.md +++ b/docs/spec.md @@ -275,7 +275,7 @@ fn doSomething() { } ``` -Functions can take a number of parameters within the parenthesis following their names, and can return a number of values to the calling context using the return keyword. +Functions can take a set number of parameters within the parenthesis following their names, and can return a number of values to the calling context using the return keyword. ``` fn reverseOrder(a, b, c) { //return type isn't required by default diff --git a/scripts/function.toy b/scripts/function.toy deleted file mode 100644 index ef50ac4..0000000 --- a/scripts/function.toy +++ /dev/null @@ -1,51 +0,0 @@ -/* -fn name(param1: string, param2: string, param3): string { - print "foobar"; - print param1; - return param2; -} - -var result = name("hello world", "goodnight world"); - -print "fizz"; -print result; -print "buzz"; - - -*/ - -/* -fn outer() { - fn inner() { - print "foo"; - } - - inner(); - - return inner; -} - -var handle = outer(); - -handle(); //breaks -*/ - - -fn make() { - var counter = 0; - - fn count() { - return counter++; - } - - return count; -} - -var tally = make(); - -print tally(); -print tally(); -print tally(); -print tally(); -print tally(); - diff --git a/source/compiler.c b/source/compiler.c index 5631832..dd5bbb7 100644 --- a/source/compiler.c +++ b/source/compiler.c @@ -426,6 +426,25 @@ static void writeCompilerWithJumps(Compiler* compiler, Node* node, void* breakAd } } + //push the argument COUNT to the top of the stack + int argumentsCount = findLiteralIndex(&compiler->literalCache, TO_INTEGER_LITERAL(node->fnCall.arguments->fnCollection.count)); + if (argumentsCount < 0) { + argumentsCount = pushLiteralArray(&compiler->literalCache, TO_INTEGER_LITERAL(node->fnCall.arguments->fnCollection.count)); + } + + if (argumentsCount >= 256) { + //push a "long" index + compiler->bytecode[compiler->count++] = OP_LITERAL_LONG; //1 byte + + *((unsigned short*)(compiler->bytecode + compiler->count)) = (unsigned short)argumentsCount; //2 bytes + compiler->count += sizeof(unsigned short); + } + else { + //push the index + compiler->bytecode[compiler->count++] = OP_LITERAL; //1 byte + compiler->bytecode[compiler->count++] = (unsigned char)argumentsCount; //1 byte + } + //call the function //DO NOT call the collection, this is done in binary } diff --git a/source/interpreter.c b/source/interpreter.c index c361227..c39c16a 100644 --- a/source/interpreter.c +++ b/source/interpreter.c @@ -750,8 +750,10 @@ static bool execFnCall(Interpreter* interpreter) { LiteralArray arguments; initLiteralArray(&arguments); - //unpack the arguments - while (interpreter->stack.count > 1) { + Literal stackSize = popLiteralArray(&interpreter->stack); + + //unpack the stack of arguments + for (int i = 0; i < AS_INTEGER(stackSize); i++) { pushLiteralArray(&arguments, popLiteralArray(&interpreter->stack)); //NOTE: also reverses the order } @@ -780,6 +782,19 @@ static bool execFnCall(Interpreter* interpreter) { LiteralArray* paramArray = AS_ARRAY(inner.literalCache.literals[ readShort(inner.bytecode, &inner.count) ]); LiteralArray* returnArray = AS_ARRAY(inner.literalCache.literals[ readShort(inner.bytecode, &inner.count) ]); + //check the param total is correct + if (paramArray->count != arguments.count * 2) { + printf(ERROR "ERROR: Incorrect number of arguments passed to function \"\n"); + printLiteral(identifier); + printf("\"\n" RESET); + + //free, and skip out + freeLiteralArray(&arguments); + freeInterpreter(&inner); + + return false; + } + for (int i = 0; i < paramArray->count; i += 2) { //contents is the indexes of identifier & type //declare and define each entry in the scope if (!declareScopeVariable(inner.scope, paramArray->literals[i], paramArray->literals[i + 1])) { diff --git a/test/functions.toy b/test/functions.toy new file mode 100644 index 0000000..24be460 --- /dev/null +++ b/test/functions.toy @@ -0,0 +1,32 @@ +//test function return +fn testFourtyTwo() { + return 42; +} + +assert testFourtyTwo() == 42, "function returns failed"; + + +//test function parameters +fn identity(x) { + return x; +} + +assert identity("hello world") == "hello world", "identity function failed"; + + +//test closures +fn make() { + var counter = 0; + + fn count() { + return ++counter; + } + + return count; +} + +var tally = make(); + +assert tally() == 1 && tally() == 2, "Closures failed"; + +print "All good"; \ No newline at end of file