TMP: Brain broke, I need a break, don't use this commit

This commit is contained in:
2026-05-23 14:40:32 +10:00
parent 813da3e1aa
commit 2a82b0052d
6 changed files with 209 additions and 26 deletions
+23
View File
@@ -0,0 +1,23 @@
```toy
for (var name in array) {
//
}
```
pushStack name
pushStack array
pushStack counter //tracks the index for each loop
OPCODE iterable:
pushScope
declare name = array.next() if next is not null else jump to end
(user code)
popScope
jump to beginning
popStack counter, array, name
+4 -9
View File
@@ -1,12 +1,7 @@
var array = ["foo", "bar"];
fn a(x) { for (var i in array) {
print x; print i;
} }
fn b() {
return 42;
}
a(b(), b());
+62 -5
View File
@@ -226,6 +226,7 @@ static unsigned int writeBytecodeFromAst(Toy_Bytecode** mb, Toy_Ast* ast); //for
static void writeBytecodeBody(Toy_Bytecode* mb, Toy_Ast* ast); static void writeBytecodeBody(Toy_Bytecode* mb, Toy_Ast* ast);
static unsigned char* collateBytecodeBody(Toy_Bytecode* mb); static unsigned char* collateBytecodeBody(Toy_Bytecode* mb);
static unsigned int writeInstructionAssign(Toy_Bytecode** mb, Toy_AstVarAssign ast, bool chainedAssignment); //forward declare for chaining of var declarations static unsigned int writeInstructionAssign(Toy_Bytecode** mb, Toy_AstVarAssign ast, bool chainedAssignment); //forward declare for chaining of var declarations
static unsigned int writeInstructionAccess(Toy_Bytecode** mb, Toy_AstVarAccess ast);
static unsigned int writeInstructionFnInvoke(Toy_Bytecode** mb, Toy_AstFnInvoke ast, bool chainedInvoke); static unsigned int writeInstructionFnInvoke(Toy_Bytecode** mb, Toy_AstFnInvoke ast, bool chainedInvoke);
static unsigned int writeInstructionValue(Toy_Bytecode** mb, Toy_AstValue ast) { static unsigned int writeInstructionValue(Toy_Bytecode** mb, Toy_AstValue ast) {
@@ -456,7 +457,7 @@ static unsigned int writeInstructionBinaryShortCircuit(Toy_Bytecode** mb, Toy_As
//if the lhs value isn't needed, pop it //if the lhs value isn't needed, pop it
EMIT_BYTE(mb, code,TOY_OPCODE_ELIMINATE); EMIT_BYTE(mb, code,TOY_OPCODE_ELIMINATE);
EMIT_BYTE(mb, code, 0); EMIT_BYTE(mb, code, 1);
EMIT_BYTE(mb, code, 0); EMIT_BYTE(mb, code, 0);
EMIT_BYTE(mb, code, 0); EMIT_BYTE(mb, code, 0);
@@ -719,9 +720,65 @@ static unsigned int writeInstructionWhileThen(Toy_Bytecode** mb, Toy_AstWhileThe
} }
static unsigned int writeInstructionForThen(Toy_Bytecode** mb, Toy_AstForThen ast) { static unsigned int writeInstructionForThen(Toy_Bytecode** mb, Toy_AstForThen ast) {
//URGENT: WIP //check the operands
(void)mb; if (ast.condBranch->type != TOY_AST_ITERABLE || ast.condBranch->iterable.left->type != TOY_AST_VAR_DECLARE || ast.condBranch->iterable.right->type != TOY_AST_VAR_ACCESS) {
(void)ast; fprintf(stderr, TOY_CC_ERROR "COMPILER ERROR: Invalid conditional found in a 'for' loop\n" TOY_CC_RESET);
(*mb)->panic = true;
return 0;
}
//set up the iterable, and the counter
writeInstructionAccess(mb, ast.condBranch->iterable.right->varAccess);
EMIT_BYTE(mb, code, TOY_OPCODE_READ);
EMIT_BYTE(mb, code, TOY_VALUE_INTEGER);
EMIT_BYTE(mb, code, 0);
EMIT_BYTE(mb, code, 0);
EMIT_INT(mb, code, 0); //start from zero
//access [-1] from [-2], incrementing [-1] afterwards
//then if null, execute relative jump
EMIT_BYTE(mb, code, TOY_OPCODE_ITERABLE);
EMIT_BYTE(mb, code, TOY_OP_PARAM_JUMP_RELATIVE);
EMIT_BYTE(mb, code, TOY_OP_PARAM_JUMP_IF_NULL);
EMIT_BYTE(mb, code, 0);
unsigned int thenParamAddr = SKIP_INT(mb, code); //parameter to be written later
//push scope (built-into the keyword)
EMIT_BYTE(mb, code, TOY_OPCODE_SCOPE_PUSH);
EMIT_BYTE(mb, code, 0);
EMIT_BYTE(mb, code, 0);
EMIT_BYTE(mb, code, 0);
(*mb)->currentScopeDepth++;
//delcare the iterator with the given string
EMIT_BYTE(mb, code, TOY_OPCODE_DECLARE);
EMIT_BYTE(mb, code, ast.condBranch->iterable.left->varDeclare.valueType);
EMIT_BYTE(mb, code, ast.condBranch->iterable.left->varDeclare.name->info.length); //quick optimisation to skip a 'strlen()' call
EMIT_BYTE(mb, code, ast.condBranch->iterable.left->varDeclare.constant); //check for constness
emitString(mb, ast.condBranch->iterable.left->varDeclare.name);
//write the body
writeBytecodeFromAst(mb, ast.thenBranch);
//pop scope after each iteration
EMIT_BYTE(mb, code, TOY_OPCODE_SCOPE_POP);
EMIT_BYTE(mb, code, 0);
EMIT_BYTE(mb, code, 0);
EMIT_BYTE(mb, code, 0);
(*mb)->currentScopeDepth--;
//end of the loop, overwrite the parameter
OVERWRITE_INT(mb, code, thenParamAddr, CURRENT_ADDRESS(mb, code) - (thenParamAddr + 4));
//pop the conditional stuff from the stack
EMIT_BYTE(mb, code,TOY_OPCODE_ELIMINATE);
EMIT_BYTE(mb, code, 2);
EMIT_BYTE(mb, code, 0);
EMIT_BYTE(mb, code, 0);
(*mb)->panic = true; (*mb)->panic = true;
return 1; return 1;
@@ -1163,7 +1220,7 @@ static unsigned int writeInstructionStackPop(Toy_Bytecode** mb, Toy_AstStackPop
//dead simple //dead simple
EMIT_BYTE(mb, code,TOY_OPCODE_ELIMINATE); EMIT_BYTE(mb, code,TOY_OPCODE_ELIMINATE);
EMIT_BYTE(mb, code, 0); EMIT_BYTE(mb, code, 1);
EMIT_BYTE(mb, code, 0); EMIT_BYTE(mb, code, 0);
EMIT_BYTE(mb, code, 0); EMIT_BYTE(mb, code, 0);
+2 -1
View File
@@ -12,9 +12,9 @@ typedef enum Toy_OpcodeType {
TOY_OPCODE_ACCESS, TOY_OPCODE_ACCESS,
TOY_OPCODE_INVOKE, //for calling functions TOY_OPCODE_INVOKE, //for calling functions
TOY_OPCODE_ATTRIBUTE, //for accessing parts of compounds TOY_OPCODE_ATTRIBUTE, //for accessing parts of compounds
TOY_OPCODE_ITERABLE, //for operating on all members of a compound
TOY_OPCODE_DUPLICATE, //duplicate the top of the stack TOY_OPCODE_DUPLICATE, //duplicate the top of the stack
TOY_OPCODE_ELIMINATE, //remove the top of the stack TOY_OPCODE_ELIMINATE, //remove the top of the stack
TOY_OPCODE_ITERABLE, //for operating on all members of a compound
//arithmetic instructions //arithmetic instructions
TOY_OPCODE_ADD, TOY_OPCODE_ADD,
@@ -67,5 +67,6 @@ typedef enum Toy_OpParamJumpConditional {
TOY_OP_PARAM_JUMP_ALWAYS = 0, TOY_OP_PARAM_JUMP_ALWAYS = 0,
TOY_OP_PARAM_JUMP_IF_TRUE = 1, TOY_OP_PARAM_JUMP_IF_TRUE = 1,
TOY_OP_PARAM_JUMP_IF_FALSE = 2, TOY_OP_PARAM_JUMP_IF_FALSE = 2,
TOY_OP_PARAM_JUMP_IF_NULL = 3,
} Toy_OpParamJumpConditional; } Toy_OpParamJumpConditional;
+50 -7
View File
@@ -765,11 +765,17 @@ static Toy_AstFlag iterable(Toy_Bucket** bucketHandle, Toy_Parser* parser, Toy_A
//infix must advance //infix must advance
advance(parser); advance(parser);
Toy_Ast* expr = NULL; //check for the correct operands
parsePrecedence(bucketHandle, parser, &expr, PREC_CALL); if ((*rootHandle)->type != TOY_AST_VAR_DECLARE) {
Toy_private_emitAstIterable(bucketHandle, rootHandle, expr); printError(parser, parser->previous, "Expected iterator name not found");
Toy_private_emitAstError(bucketHandle, rootHandle);
return TOY_AST_FLAG_NONE;
}
//TODO: check for var declare without assignment Toy_Ast* expr = NULL;
parsePrecedence(bucketHandle, parser, rootHandle, PREC_CALL);
Toy_private_emitAstIterable(bucketHandle, rootHandle, expr);
return TOY_AST_FLAG_NONE; return TOY_AST_FLAG_NONE;
} }
@@ -785,7 +791,7 @@ static void parsePrecedence(Toy_Bucket** bucketHandle, Toy_Parser* parser, Toy_A
if (prefix == NULL) { if (prefix == NULL) {
//make a nice error message //make a nice error message
if (Toy_private_findKeywordByType(parser->previous.type)) { if (Toy_private_findKeywordByType(parser->previous.type)) {
printError(parser, parser->previous, "Found reserved keyword instead"); printError(parser, parser->previous, "Expected expression, found reserved keyword instead");
} }
else { else {
printError(parser, parser->previous, "Expected expression"); printError(parser, parser->previous, "Expected expression");
@@ -909,12 +915,49 @@ static void makeForStmt(Toy_Bucket** bucketHandle, Toy_Parser* parser, Toy_Ast**
Toy_Ast* condBranch = NULL; Toy_Ast* condBranch = NULL;
Toy_Ast* thenBranch = NULL; Toy_Ast* thenBranch = NULL;
//BUG: wtf am I doing here?
//for (condBranch) //for (condBranch)
consume(parser, TOY_TOKEN_OPERATOR_PAREN_LEFT, "Expected '(' after 'for' keyword"); consume(parser, TOY_TOKEN_OPERATOR_PAREN_LEFT, "Expected '(' after 'for' keyword");
consume(parser, TOY_TOKEN_KEYWORD_VAR, "Expected 'var' in 'for' conditional");
//WARN: duped from var declare
consume(parser, TOY_TOKEN_NAME, "Expected variable name after 'var' keyword");
if (parser->previous.length > 255) {
printError(parser, parser->previous, "Can't have a variable name longer than 255 characters");
Toy_private_emitAstError(bucketHandle, rootHandle);
return;
}
Toy_Token nameToken = parser->previous;
//read the type specifier if present
Toy_ValueType varType = TOY_VALUE_ANY;
bool constant = false;
if (match(parser, TOY_TOKEN_OPERATOR_COLON)) {
varType = readType(parser);
if (match(parser, TOY_TOKEN_KEYWORD_CONST)) {
constant = true;
}
}
//build the name string & emit a var declare
Toy_String* nameStr = Toy_toStringLength(bucketHandle, nameToken.lexeme, nameToken.length);
Toy_private_emitAstVariableDeclaration(bucketHandle, &condBranch, nameStr, varType, constant, NULL);
//continue to the 'in' keyword
consume(parser, TOY_TOKEN_KEYWORD_IN, "Expected 'in' inside 'for' condition");
makeExpr(bucketHandle, parser, &condBranch); makeExpr(bucketHandle, parser, &condBranch);
consume(parser, TOY_TOKEN_OPERATOR_PAREN_RIGHT, "Expected ')' after 'for' condition"); consume(parser, TOY_TOKEN_OPERATOR_PAREN_RIGHT, "Expected ')' after 'for' condition");
//TODO: check for an iterable node if (condBranch->type != TOY_AST_ITERABLE) {
printError(parser, parser->previous, "Expected 'in' in for condition");
Toy_private_emitAstError(bucketHandle, rootHandle);
return;
}
//{ thenBranch } //{ thenBranch }
makeDeclarationStmt(bucketHandle, parser, &thenBranch, true); makeDeclarationStmt(bucketHandle, parser, &thenBranch, true);
@@ -1125,7 +1168,7 @@ static void makeStmt(Toy_Bucket** bucketHandle, Toy_Parser* parser, Toy_Ast** ro
return; return;
} }
//TODO: import //import?
//print //print
else if (match(parser, TOY_TOKEN_KEYWORD_PRINT)) { else if (match(parser, TOY_TOKEN_KEYWORD_PRINT)) {
+68 -4
View File
@@ -33,6 +33,9 @@ static inline void fixAlignment(Toy_VM* vm) {
vm->programCounter = (vm->programCounter + 3) & ~3; vm->programCounter = (vm->programCounter + 3) & ~3;
} }
//forward declarations for delegations
static void processJump(Toy_VM* vm);
//instruction handlers //instruction handlers
static void processRead(Toy_VM* vm) { static void processRead(Toy_VM* vm) {
Toy_ValueType type = READ_BYTE(vm); Toy_ValueType type = READ_BYTE(vm);
@@ -470,9 +473,56 @@ static void processDuplicate(Toy_VM* vm) {
} }
static void processEliminate(Toy_VM* vm) { static void processEliminate(Toy_VM* vm) {
//discard the stack top //discard the stack top, X times
Toy_Value value = Toy_popStack(&vm->stack); unsigned int x = (unsigned int)READ_BYTE(vm);
Toy_freeValue(value); for (unsigned int i = 0; i < x; i++) {
Toy_Value value = Toy_popStack(&vm->stack);
Toy_freeValue(value);
}
}
static void processIterable(Toy_VM* vm) {
//access [-1] from [-2], incrementing [-1] afterwards
//if null, delegate to 'processJump' and exit
Toy_Value counter = Toy_popStack(&vm->stack);
Toy_Value compound = Toy_popStack(&vm->stack);
if (!TOY_VALUE_IS_INTEGER(counter)) {
fprintf(stderr, TOY_CC_ERROR "ERROR: Unknown counter type '%s' found in for loop, exiting\n" TOY_CC_RESET, Toy_getValueTypeAsCString(counter.type));
exit(-1);
}
if (TOY_VALUE_IS_ARRAY(compound)) {
Toy_Array* array = TOY_VALUE_AS_ARRAY(compound);
int index = TOY_VALUE_AS_INTEGER(counter);
//check out-of-bounds
if (index < 0 || (unsigned int)index >= array->count) {
Toy_freeValue(counter);
Toy_freeValue(compound);
Toy_pushStack(&vm->stack, TOY_VALUE_FROM_NULL());
processJump(vm);
return;
}
//get the desired element
Toy_Value value = Toy_copyValue(&vm->memoryBucket, array->data[index]);
//push everything back onto the stack
Toy_pushStack(&vm->stack, compound);
Toy_pushStack(&vm->stack, TOY_VALUE_FROM_INTEGER(index + 1));
Toy_pushStack(&vm->stack, value);
//cleanup & delegate
Toy_freeValue(compound);
Toy_freeValue(counter);
processJump(vm);
}
else {
fprintf(stderr, TOY_CC_ERROR "ERROR: Unknown value type '%s' found in for loop, exiting\n" TOY_CC_RESET, Toy_getValueTypeAsCString(compound.type));
exit(-1);
}
} }
static void processArithmetic(Toy_VM* vm, Toy_OpcodeType opcode) { static void processArithmetic(Toy_VM* vm, Toy_OpcodeType opcode) {
@@ -682,6 +732,17 @@ static void processJump(Toy_VM* vm) {
Toy_freeValue(value); Toy_freeValue(value);
return; return;
} }
case TOY_OP_PARAM_JUMP_IF_NULL: {
Toy_Value value = Toy_popStack(&vm->stack);
if (TOY_VALUE_IS_NULL(value)) {
Toy_freeValue(value);
break;
}
Toy_freeValue(value);
return;
}
} }
//do the jump //do the jump
@@ -997,6 +1058,10 @@ static unsigned int process(Toy_VM* vm) {
processEliminate(vm); processEliminate(vm);
break; break;
case TOY_OPCODE_ITERABLE:
processIterable(vm);
break;
//arithmetic instructions //arithmetic instructions
case TOY_OPCODE_ADD: case TOY_OPCODE_ADD:
case TOY_OPCODE_SUBTRACT: case TOY_OPCODE_SUBTRACT:
@@ -1060,7 +1125,6 @@ static unsigned int process(Toy_VM* vm) {
processIndex(vm); processIndex(vm);
break; break;
case TOY_OPCODE_ITERABLE: //tmp
case TOY_OPCODE_UNUSED: case TOY_OPCODE_UNUSED:
case TOY_OPCODE_PASS: case TOY_OPCODE_PASS:
case TOY_OPCODE_ERROR: case TOY_OPCODE_ERROR: