mirror of
https://github.com/krgamestudios/Toy.git
synced 2026-04-19 16:54:08 +10:00
Fixed stack overflow caused by expression statements
This is a longstanding bug, so I'm glad its fixed, even if its only a bandaid. This does break some tests, but I'm too tired and these tests are out of date.
This commit is contained in:
@@ -5,7 +5,6 @@ var counter: int = 0;
|
||||
var first: int = 1;
|
||||
var second: int = 0;
|
||||
|
||||
//BUG: This causes a stack overflow
|
||||
while (counter < 100_000) {
|
||||
var third: int = first + second;
|
||||
first = second;
|
||||
|
||||
@@ -234,6 +234,15 @@ void Toy_private_emitAstFunctionInvokation(Toy_Bucket** bucketHandle, Toy_Ast**
|
||||
(*astHandle) = tmp;
|
||||
}
|
||||
|
||||
void Toy_private_emitAstStackPop(Toy_Bucket** bucketHandle, Toy_Ast** astHandle) {
|
||||
Toy_Ast* tmp = (Toy_Ast*)Toy_partitionBucket(bucketHandle, sizeof(Toy_Ast));
|
||||
|
||||
tmp->type = TOY_AST_STACK_POP;
|
||||
tmp->stackPop.child = (*astHandle);
|
||||
|
||||
(*astHandle) = tmp;
|
||||
}
|
||||
|
||||
void Toy_private_emitAstPass(Toy_Bucket** bucketHandle, Toy_Ast** astHandle) {
|
||||
Toy_Ast* tmp = (Toy_Ast*)Toy_partitionBucket(bucketHandle, sizeof(Toy_Ast));
|
||||
|
||||
|
||||
@@ -34,6 +34,8 @@ typedef enum Toy_AstType {
|
||||
TOY_AST_FN_DECLARE,
|
||||
TOY_AST_FN_INVOKE,
|
||||
|
||||
TOY_AST_STACK_POP, //BUGFIX: force a single stack pop for expression statements
|
||||
|
||||
TOY_AST_PASS,
|
||||
TOY_AST_ERROR,
|
||||
TOY_AST_END,
|
||||
@@ -217,6 +219,11 @@ typedef struct Toy_AstFnInvoke {
|
||||
Toy_Ast* args;
|
||||
} Toy_AstFnInvoke;
|
||||
|
||||
typedef struct Toy_AstStackPop {
|
||||
Toy_AstType type;
|
||||
Toy_Ast* child;
|
||||
} Toy_AstStackPop;
|
||||
|
||||
typedef struct Toy_AstPass {
|
||||
Toy_AstType type;
|
||||
} Toy_AstPass;
|
||||
@@ -252,6 +259,7 @@ union Toy_Ast { //see 'test_ast.c' for bitness tests
|
||||
Toy_AstVarAccess varAccess;
|
||||
Toy_AstFnDeclare fnDeclare;
|
||||
Toy_AstFnInvoke fnInvoke;
|
||||
Toy_AstStackPop stackPop;
|
||||
Toy_AstPass pass;
|
||||
Toy_AstError error;
|
||||
Toy_AstEnd end;
|
||||
@@ -284,6 +292,8 @@ void Toy_private_emitAstVariableAccess(Toy_Bucket** bucketHandle, Toy_Ast** astH
|
||||
void Toy_private_emitAstFunctionDeclaration(Toy_Bucket** bucketHandle, Toy_Ast** astHandle, Toy_String* name, Toy_Ast* params, Toy_Ast* body);
|
||||
void Toy_private_emitAstFunctionInvokation(Toy_Bucket** bucketHandle, Toy_Ast** astHandle, Toy_Ast* params);
|
||||
|
||||
void Toy_private_emitAstStackPop(Toy_Bucket** bucketHandle, Toy_Ast** astHandle);
|
||||
|
||||
void Toy_private_emitAstPass(Toy_Bucket** bucketHandle, Toy_Ast** astHandle);
|
||||
void Toy_private_emitAstError(Toy_Bucket** bucketHandle, Toy_Ast** astHandle);
|
||||
void Toy_private_emitAstEnd(Toy_Bucket** bucketHandle, Toy_Ast** astHandle);
|
||||
|
||||
@@ -1080,6 +1080,19 @@ static unsigned int writeInstructionFnInvoke(Toy_Bytecode** mb, Toy_AstFnInvoke
|
||||
return 0;
|
||||
}
|
||||
|
||||
static unsigned int writeInstructionStackPop(Toy_Bytecode** mb, Toy_AstStackPop ast) {
|
||||
unsigned int result = writeBytecodeFromAst(mb, ast.child);
|
||||
|
||||
//dead simple
|
||||
EMIT_BYTE(mb, code,TOY_OPCODE_ELIMINATE);
|
||||
EMIT_BYTE(mb, code, 0);
|
||||
EMIT_BYTE(mb, code, 0);
|
||||
EMIT_BYTE(mb, code, 0);
|
||||
|
||||
return result - 1;
|
||||
}
|
||||
|
||||
|
||||
static unsigned int writeBytecodeFromAst(Toy_Bytecode** mb, Toy_Ast* ast) {
|
||||
if (ast == NULL) {
|
||||
return 0;
|
||||
@@ -1198,6 +1211,10 @@ static unsigned int writeBytecodeFromAst(Toy_Bytecode** mb, Toy_Ast* ast) {
|
||||
result += writeInstructionFnInvoke(mb, ast->fnInvoke);
|
||||
break;
|
||||
|
||||
case TOY_AST_STACK_POP:
|
||||
result += writeInstructionStackPop(mb, ast->stackPop);
|
||||
break;
|
||||
|
||||
case TOY_AST_PASS:
|
||||
//NO-OP
|
||||
break;
|
||||
|
||||
@@ -891,6 +891,11 @@ static void makePrintStmt(Toy_Bucket** bucketHandle, Toy_Parser* parser, Toy_Ast
|
||||
|
||||
static void makeExprStmt(Toy_Bucket** bucketHandle, Toy_Parser* parser, Toy_Ast** rootHandle) {
|
||||
makeExpr(bucketHandle, parser, rootHandle);
|
||||
//BUGFIX: don't leave anything on the stack after a unary statement
|
||||
if ((*rootHandle)->type == TOY_AST_VALUE || (*rootHandle)->type == TOY_AST_UNARY || (*rootHandle)->type == TOY_AST_COMPARE || (*rootHandle)->type == TOY_AST_GROUP || (*rootHandle)->type == TOY_AST_COMPOUND || (*rootHandle)->type == TOY_AST_AGGREGATE) {
|
||||
Toy_private_emitAstStackPop(bucketHandle, rootHandle);
|
||||
}
|
||||
|
||||
consume(parser, TOY_TOKEN_OPERATOR_SEMICOLON, "Expected ';' at the end of expression statement");
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user