Rest parameter working

This commit is contained in:
2022-08-27 11:59:54 +01:00
parent 85f3dfbf1d
commit 90e5a5d08b
7 changed files with 77 additions and 10 deletions

View File

@@ -21,12 +21,13 @@ 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
DONE: functions last argument can be a rest parameter
TODO: functions return a set number of values
TODO: functions last argument can be a rest parameter
TODO: assert needs to kill the whole script
TODO: assert needs to kill the whole script, not just functions
TODO: ternary operator
TODO: Nullish types
TODO: A way to check the type of a variable (typeOf keyword)
TODO: a = b = c = 1; ?
@@ -34,3 +35,5 @@ TODO: are compounds shallow or deep copies?
TODO: Assertion-based test scripts
TODO: standard library
TODO: external runner library
TODO: document how it all works
TODO: third output stream, for parser/compiler/interpreter errors

0
scripts/error-test.toy Normal file
View File

View File

@@ -782,9 +782,15 @@ 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) ]);
//get the rest param, if it exists
Literal restParam = TO_NULL_LITERAL;
if (paramArray->count >= 2 && AS_TYPE(paramArray->literals[ paramArray->count -1 ]).typeOf == LITERAL_FUNCTION_ARG_REST) {
restParam = paramArray->literals[ paramArray->count -2 ];
}
//check the param total is correct
if (paramArray->count != arguments.count * 2) {
printf(ERROR "ERROR: Incorrect number of arguments passed to function \"\n");
if ((IS_NULL(restParam) && paramArray->count != arguments.count * 2) || (!IS_NULL(restParam) && paramArray->count -2 > arguments.count * 2)) {
printf(ERROR "ERROR: Incorrect number of arguments passed to function \"");
printLiteral(identifier);
printf("\"\n" RESET);
@@ -795,16 +801,55 @@ static bool execFnCall(Interpreter* interpreter) {
return false;
}
for (int i = 0; i < paramArray->count; i += 2) { //contents is the indexes of identifier & type
//contents is the indexes of identifier & type
for (int i = 0; i < paramArray->count - (IS_NULL(restParam) ? 0 : 2); i += 2) { //don't count the rest parameter, if present
//declare and define each entry in the scope
if (!declareScopeVariable(inner.scope, paramArray->literals[i], paramArray->literals[i + 1])) {
printf(ERROR "[internal] Could not re-declare parameter\n" RESET);
//free, and skip out
freeLiteralArray(&arguments);
freeInterpreter(&inner);
return false;
}
if (!setScopeVariable(inner.scope, paramArray->literals[i], popLiteralArray(&arguments), false)) {
printf(ERROR "[internal] Could not define parameter (bad type?)\n" RESET);
//free, and skip out
freeLiteralArray(&arguments);
freeInterpreter(&inner);
return false;
}
}
//if using rest, pack the optional extra arguments into the rest parameter (array)
if (!IS_NULL(restParam)) {
LiteralArray rest;
initLiteralArray(&rest);
while (arguments.count > 0) {
pushLiteralArray(&rest, popLiteralArray(&arguments));
}
Literal restType = TO_TYPE_LITERAL(LITERAL_ARRAY, true);
TYPE_PUSH_SUBTYPE(&restType, TO_TYPE_LITERAL(LITERAL_ANY, false));
//declare & define the rest parameter
if (!declareScopeVariable(inner.scope, restParam, restType)) {
printf(ERROR "[internal] Could not declare rest parameter\n" RESET);
//free, and skip out
freeLiteral(restType);
freeLiteralArray(&rest);
freeLiteralArray(&arguments);
freeInterpreter(&inner);
return false;
}
if (!setScopeVariable(inner.scope, restParam, TO_ARRAY_LITERAL(&rest), false)) {
printf(ERROR "[internal] Could not define rest parameter\n" RESET);
//free, and skip out
freeLiteral(restType);
freeLiteralArray(&rest);
freeLiteralArray(&arguments);
freeInterpreter(&inner);
return false;
}
@@ -1083,7 +1128,7 @@ static void execInterpreter(Interpreter* interpreter) {
static void readInterpreterSections(Interpreter* interpreter) {
//data section
const short literalCount = readShort(interpreter->bytecode, &interpreter->count);
const unsigned short literalCount = readShort(interpreter->bytecode, &interpreter->count);
if (command.verbose) {
printf(NOTICE "Reading %d literals\n" RESET, literalCount);

View File

@@ -305,6 +305,10 @@ void printLiteralCustom(Literal literal, void (printFn)(const char*)) {
case LITERAL_ANY:
printFn("(any)");
break;
default:
//should never be seen
fprintf(stderr, ERROR "[internal] Unrecognized literal type in print: %d\n" RESET, literal.type);
}
}
@@ -489,7 +493,12 @@ bool literalsAreEqual(Literal lhs, Literal rhs) {
return true;
case LITERAL_FUNCTION_INTERMEDIATE:
fprintf(stderr, ERROR "[internal] Can't compare functions\n" RESET);
fprintf(stderr, ERROR "[internal] Can't compare intermediate functions\n" RESET);
return false;
default:
//should never be seen
fprintf(stderr, ERROR "[internal] Unrecognized literal type in equality: %d\n" RESET, lhs.type);
return false;
}

View File

@@ -19,6 +19,7 @@ typedef enum {
LITERAL_TYPE,
LITERAL_TYPE_INTERMEDIATE, //used to process types in the compiler only
LITERAL_FUNCTION_INTERMEDIATE, //used to process functions in the compiler only
LITERAL_FUNCTION_ARG_REST, //used to process function rest parameters
// LITERAL_FUNCTION_NATIVE, //for handling native functions
LITERAL_ANY, //used by the type system only
} LiteralType;

View File

@@ -1419,8 +1419,7 @@ static void fnDecl(Parser* parser, Node** nodeHandle) {
Literal argIdentifier = _toIdentifierLiteral(cpy, strlen(cpy)); //BUGFIX: use this instead of the macro
//set the type (array of any types)
Literal argTypeLiteral = TO_TYPE_LITERAL(LITERAL_ARRAY, false);
TYPE_PUSH_SUBTYPE(&argTypeLiteral, TO_TYPE_LITERAL(LITERAL_ANY, false));
Literal argTypeLiteral = TO_TYPE_LITERAL(LITERAL_FUNCTION_ARG_REST, false);
//emit the node to the argument list (grow the node if needed)
if (argumentNode->fnCollection.capacity < argumentNode->fnCollection.count + 1) {

View File

@@ -30,7 +30,7 @@ var tally = make();
assert tally() == 1 && tally() == 2, "Closures failed";
//expressions as arguments
//test expressions as arguments
fn argFn() {
return 42;
}
@@ -42,4 +42,14 @@ fn outerFn(val) {
outerFn(argFn());
//test extra parameters
fn extra(one, two, ...rest) {
assert rest == ["three", "four", "five", "six", "seven"], "rest parameters failed";
}
extra("one", "two", "three", "four", "five", "six", "seven");
print "All good";