mirror of
https://github.com/krgamestudios/Toy.git
synced 2026-04-15 14:54:07 +10:00
Rest parameter working
This commit is contained in:
@@ -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
0
scripts/error-test.toy
Normal 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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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";
|
||||
Reference in New Issue
Block a user