Fixed invoking functions within function arguments

Somewhat similar to c9d4b9965c
This commit is contained in:
2026-05-19 13:21:41 +10:00
parent a0d75b3c70
commit f55f27726c
10 changed files with 115 additions and 47 deletions
+31
View File
@@ -0,0 +1,31 @@
//WARN: This is just a scratch pad, don't use it
//for (var i in array) print i;
//for (var i in range(10)) print i;
//example of a `range` function
fn range(limit: Int) {
var counter: Int = 0;
fn next() {
if (counter >= limit) {
return null;
}
else return counter++;
}
return next;
}
var next = range(10);
fn log(x) {
if (x == null) return;
print x;
}
while (true) {
log(next());
}
+7 -7
View File
@@ -1,12 +1,12 @@
if (true) { fn a(x) {
print "Who?"; print x;
} }
else if (true) {
print "What?"; fn b() {
} return 42;
else {
print "IDK";
} }
a(b(), b());
+1
View File
@@ -76,6 +76,7 @@ typedef enum Toy_AstFlag {
TOY_AST_FLAG_COLLECTION = 32, TOY_AST_FLAG_COLLECTION = 32,
TOY_AST_FLAG_PAIR = 33, TOY_AST_FLAG_PAIR = 33,
TOY_AST_FLAG_INDEX = 34, TOY_AST_FLAG_INDEX = 34,
TOY_AST_FLAG_FN_ARGUMENTS = 35,
//unary flags //unary flags
TOY_AST_FLAG_NEGATE = 40, TOY_AST_FLAG_NEGATE = 40,
+14 -2
View File
@@ -580,6 +580,18 @@ static unsigned int writeInstructionAggregate(Toy_Bytecode** mb, Toy_AstAggregat
return 1; //leaves only 1 value on the stack return 1; //leaves only 1 value on the stack
} }
else if (ast.flag == TOY_AST_FLAG_FN_ARGUMENTS) {
//BUGFIX: invoking a function as an argument gets messy, so re-count the aggregate elements and discard 'result'
int count = ast.left != NULL ? 2 : 1;
Toy_Ast* iter = ast.right;
while (iter != NULL && iter->type == TOY_AST_AGGREGATE) {
iter = iter->aggregate.right;
count++;
}
return count;
}
else { else {
fprintf(stderr, TOY_CC_ERROR "ERROR: Invalid AST aggregate flag found\n" TOY_CC_RESET); fprintf(stderr, TOY_CC_ERROR "ERROR: Invalid AST aggregate flag found\n" TOY_CC_RESET);
exit(-1); exit(-1);
@@ -776,7 +788,7 @@ static unsigned int writeInstructionReturn(Toy_Bytecode** mb, Toy_AstReturn ast)
EMIT_BYTE(mb, code,0); EMIT_BYTE(mb, code,0);
EMIT_BYTE(mb, code,0); EMIT_BYTE(mb, code,0);
return 0; return retCount;
} }
static unsigned int writeInstructionPrint(Toy_Bytecode** mb, Toy_AstPrint ast) { static unsigned int writeInstructionPrint(Toy_Bytecode** mb, Toy_AstPrint ast) {
@@ -1114,7 +1126,7 @@ static unsigned int writeInstructionFnInvoke(Toy_Bytecode** mb, Toy_AstFnInvoke
EMIT_BYTE(mb, code, TOY_OPCODE_INVOKE); EMIT_BYTE(mb, code, TOY_OPCODE_INVOKE);
EMIT_BYTE(mb, code, TOY_VALUE_FUNCTION); EMIT_BYTE(mb, code, TOY_VALUE_FUNCTION);
EMIT_BYTE(mb, code, (unsigned char)argCount); EMIT_BYTE(mb, code, (unsigned char)argCount);
EMIT_BYTE(mb, code, 0); //IDK how many returns EMIT_BYTE(mb, code, 0); //BUG: IDK how many returns
return chainedInvoke ? 1 : 0; return chainedInvoke ? 1 : 0;
} }
+6 -2
View File
@@ -724,7 +724,7 @@ static Toy_AstFlag invoke(Toy_Bucket** bucketHandle, Toy_Parser* parser, Toy_Ast
parsePrecedence(bucketHandle, parser, &ast, PREC_GROUP); parsePrecedence(bucketHandle, parser, &ast, PREC_GROUP);
//add to the args aggregate (is added backwards, because weird) //add to the args aggregate (is added backwards, because weird)
Toy_private_emitAstAggregate(bucketHandle, &args, TOY_AST_FLAG_COLLECTION, ast); Toy_private_emitAstAggregate(bucketHandle, &args, TOY_AST_FLAG_FN_ARGUMENTS, ast);
} }
consume(parser, TOY_TOKEN_OPERATOR_PAREN_RIGHT, "Expected ')' at the end of argument list"); consume(parser, TOY_TOKEN_OPERATOR_PAREN_RIGHT, "Expected ')' at the end of argument list");
@@ -902,11 +902,15 @@ static void makeContinueStmt(Toy_Bucket** bucketHandle, Toy_Parser* parser, Toy_
} }
static void makeReturnStmt(Toy_Bucket** bucketHandle, Toy_Parser* parser, Toy_Ast** rootHandle) { static void makeReturnStmt(Toy_Bucket** bucketHandle, Toy_Parser* parser, Toy_Ast** rootHandle) {
if (match(parser, TOY_TOKEN_OPERATOR_SEMICOLON)) {
Toy_private_emitAstReturn(bucketHandle, rootHandle);
}
else {
parsePrecedence(bucketHandle, parser, rootHandle, PREC_GROUP); //expect an aggregate parsePrecedence(bucketHandle, parser, rootHandle, PREC_GROUP); //expect an aggregate
Toy_private_emitAstReturn(bucketHandle, rootHandle); Toy_private_emitAstReturn(bucketHandle, rootHandle);
consume(parser, TOY_TOKEN_OPERATOR_SEMICOLON, "Expected ';' at the end of return statement"); consume(parser, TOY_TOKEN_OPERATOR_SEMICOLON, "Expected ';' at the end of return statement");
} }
}
static void makePrintStmt(Toy_Bucket** bucketHandle, Toy_Parser* parser, Toy_Ast** rootHandle) { static void makePrintStmt(Toy_Bucket** bucketHandle, Toy_Parser* parser, Toy_Ast** rootHandle) {
makeExpr(bucketHandle, parser, rootHandle); makeExpr(bucketHandle, parser, rootHandle);
+32 -32
View File
@@ -20,28 +20,28 @@ typedef enum Toy_TokenType {
TOY_TOKEN_TYPE_ANY, TOY_TOKEN_TYPE_ANY,
//keywords and reserved words //keywords and reserved words
TOY_TOKEN_KEYWORD_AS, TOY_TOKEN_KEYWORD_AS, //unused
TOY_TOKEN_KEYWORD_ASSERT, TOY_TOKEN_KEYWORD_ASSERT,
TOY_TOKEN_KEYWORD_BREAK, TOY_TOKEN_KEYWORD_BREAK,
TOY_TOKEN_KEYWORD_CLASS, TOY_TOKEN_KEYWORD_CLASS, //unused
TOY_TOKEN_KEYWORD_CONST, TOY_TOKEN_KEYWORD_CONST,
TOY_TOKEN_KEYWORD_CONTINUE, TOY_TOKEN_KEYWORD_CONTINUE,
TOY_TOKEN_KEYWORD_DO, TOY_TOKEN_KEYWORD_DO, //unused
TOY_TOKEN_KEYWORD_ELSE, TOY_TOKEN_KEYWORD_ELSE,
TOY_TOKEN_KEYWORD_EXPORT, TOY_TOKEN_KEYWORD_EXPORT, //unused
TOY_TOKEN_KEYWORD_FOR, TOY_TOKEN_KEYWORD_FOR, //unused
TOY_TOKEN_KEYWORD_FOREACH, TOY_TOKEN_KEYWORD_FOREACH, //unused
TOY_TOKEN_KEYWORD_FUNCTION, TOY_TOKEN_KEYWORD_FUNCTION, //remapped 'fn'
TOY_TOKEN_KEYWORD_IF, TOY_TOKEN_KEYWORD_IF,
TOY_TOKEN_KEYWORD_IMPORT, TOY_TOKEN_KEYWORD_IMPORT, //unused
TOY_TOKEN_KEYWORD_IN, TOY_TOKEN_KEYWORD_IN, //unused
TOY_TOKEN_KEYWORD_OF, TOY_TOKEN_KEYWORD_OF, //unused
TOY_TOKEN_KEYWORD_PASS, TOY_TOKEN_KEYWORD_PASS,
TOY_TOKEN_KEYWORD_PRINT, TOY_TOKEN_KEYWORD_PRINT,
TOY_TOKEN_KEYWORD_RETURN, TOY_TOKEN_KEYWORD_RETURN,
TOY_TOKEN_KEYWORD_VAR, TOY_TOKEN_KEYWORD_VAR,
TOY_TOKEN_KEYWORD_WHILE, TOY_TOKEN_KEYWORD_WHILE,
TOY_TOKEN_KEYWORD_YIELD, TOY_TOKEN_KEYWORD_YIELD, //unused
//literal values //literal values
TOY_TOKEN_LITERAL_TRUE, TOY_TOKEN_LITERAL_TRUE,
@@ -51,19 +51,19 @@ typedef enum Toy_TokenType {
TOY_TOKEN_LITERAL_STRING, TOY_TOKEN_LITERAL_STRING,
//math operators //math operators
TOY_TOKEN_OPERATOR_ADD, TOY_TOKEN_OPERATOR_ADD, // +
TOY_TOKEN_OPERATOR_SUBTRACT, TOY_TOKEN_OPERATOR_SUBTRACT, // -
TOY_TOKEN_OPERATOR_MULTIPLY, TOY_TOKEN_OPERATOR_MULTIPLY, // *
TOY_TOKEN_OPERATOR_DIVIDE, TOY_TOKEN_OPERATOR_DIVIDE, // /
TOY_TOKEN_OPERATOR_MODULO, TOY_TOKEN_OPERATOR_MODULO, // %
TOY_TOKEN_OPERATOR_ADD_ASSIGN, TOY_TOKEN_OPERATOR_ADD_ASSIGN, // +=
TOY_TOKEN_OPERATOR_SUBTRACT_ASSIGN, TOY_TOKEN_OPERATOR_SUBTRACT_ASSIGN, // -=
TOY_TOKEN_OPERATOR_MULTIPLY_ASSIGN, TOY_TOKEN_OPERATOR_MULTIPLY_ASSIGN, // *=
TOY_TOKEN_OPERATOR_DIVIDE_ASSIGN, TOY_TOKEN_OPERATOR_DIVIDE_ASSIGN, // /=
TOY_TOKEN_OPERATOR_MODULO_ASSIGN, TOY_TOKEN_OPERATOR_MODULO_ASSIGN, // %=
TOY_TOKEN_OPERATOR_INCREMENT, TOY_TOKEN_OPERATOR_INCREMENT, // ++
TOY_TOKEN_OPERATOR_DECREMENT, TOY_TOKEN_OPERATOR_DECREMENT, // --
TOY_TOKEN_OPERATOR_ASSIGN, TOY_TOKEN_OPERATOR_ASSIGN, // =
//comparator operators //comparator operators
TOY_TOKEN_OPERATOR_COMPARE_EQUAL, // == TOY_TOKEN_OPERATOR_COMPARE_EQUAL, // ==
@@ -74,12 +74,12 @@ typedef enum Toy_TokenType {
TOY_TOKEN_OPERATOR_COMPARE_GREATER_EQUAL, // >= TOY_TOKEN_OPERATOR_COMPARE_GREATER_EQUAL, // >=
//structural operators //structural operators
TOY_TOKEN_OPERATOR_PAREN_LEFT, TOY_TOKEN_OPERATOR_PAREN_LEFT, // (
TOY_TOKEN_OPERATOR_PAREN_RIGHT, TOY_TOKEN_OPERATOR_PAREN_RIGHT, // )
TOY_TOKEN_OPERATOR_BRACKET_LEFT, TOY_TOKEN_OPERATOR_BRACKET_LEFT, // [
TOY_TOKEN_OPERATOR_BRACKET_RIGHT, TOY_TOKEN_OPERATOR_BRACKET_RIGHT, // ]
TOY_TOKEN_OPERATOR_BRACE_LEFT, TOY_TOKEN_OPERATOR_BRACE_LEFT, // {
TOY_TOKEN_OPERATOR_BRACE_RIGHT, TOY_TOKEN_OPERATOR_BRACE_RIGHT, // }
//other operators //other operators
TOY_TOKEN_OPERATOR_AND, // && TOY_TOKEN_OPERATOR_AND, // &&
@@ -100,7 +100,7 @@ typedef enum Toy_TokenType {
TOY_TOKEN_OPERATOR_PIPE, // | TOY_TOKEN_OPERATOR_PIPE, // |
//meta tokens //meta tokens
TOY_TOKEN_ERROR, TOY_TOKEN_ERROR, //meta
TOY_TOKEN_EOF, TOY_TOKEN_EOF, //meta
} Toy_TokenType; } Toy_TokenType;
+1 -1
View File
@@ -718,7 +718,7 @@ static void processAssert(Toy_VM* vm) {
//determine the args //determine the args
if (count == 1) { if (count == 1) {
message = TOY_VALUE_FROM_STRING(Toy_toString(&vm->memoryBucket, "assertion failed")); message = TOY_VALUE_FROM_STRING(Toy_toString(&vm->memoryBucket, "assertion failed")); //TODO: better default error message
value = Toy_popStack(&vm->stack); value = Toy_popStack(&vm->stack);
} }
else if (count == 2) { else if (count == 2) {
@@ -0,0 +1,11 @@
fn a(x) {
assert x == 42;
}
fn b() {
return 42;
}
a(b());
+1
View File
@@ -0,0 +1 @@
pass;
+8
View File
@@ -0,0 +1,8 @@
fn empty() { //BUG: there's an extra return in the bytecode
return;
}
fn full() {
return 42;
}