Compare commits

..

2 Commits

Author SHA1 Message Date
Kayne Ruse 2a82b0052d TMP: Brain broke, I need a break, don't use this commit 2026-05-23 14:40:32 +10:00
Kayne Ruse 813da3e1aa WIP Adding for-loop to parser & compiler 2026-05-21 11:26:59 +10:00
10 changed files with 302 additions and 22 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
+3 -8
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());
+22
View File
@@ -147,6 +147,16 @@ void Toy_private_emitAstWhileThen(Toy_Bucket** bucketHandle, Toy_Ast** astHandle
(*astHandle) = tmp; (*astHandle) = tmp;
} }
void Toy_private_emitAstForThen(Toy_Bucket** bucketHandle, Toy_Ast** astHandle, Toy_Ast* condBranch, Toy_Ast* thenBranch) {
Toy_Ast* tmp = (Toy_Ast*)Toy_partitionBucket(bucketHandle, sizeof(Toy_Ast));
tmp->type = TOY_AST_FOR_THEN;
tmp->forThen.condBranch = condBranch;
tmp->forThen.thenBranch = thenBranch;
(*astHandle) = tmp;
}
void Toy_private_emitAstBreak(Toy_Bucket** bucketHandle, Toy_Ast** astHandle) { void Toy_private_emitAstBreak(Toy_Bucket** bucketHandle, Toy_Ast** astHandle) {
Toy_Ast* tmp = (Toy_Ast*)Toy_partitionBucket(bucketHandle, sizeof(Toy_Ast)); Toy_Ast* tmp = (Toy_Ast*)Toy_partitionBucket(bucketHandle, sizeof(Toy_Ast));
@@ -244,6 +254,16 @@ void Toy_private_emitAstAttribute(Toy_Bucket** bucketHandle, Toy_Ast** astHandle
(*astHandle) = tmp; (*astHandle) = tmp;
} }
void Toy_private_emitAstIterable(Toy_Bucket** bucketHandle, Toy_Ast** astHandle, Toy_Ast* expr) {
Toy_Ast* tmp = (Toy_Ast*)Toy_partitionBucket(bucketHandle, sizeof(Toy_Ast));
tmp->type = TOY_AST_ITERABLE;
tmp->iterable.left = (*astHandle);
tmp->iterable.right = expr;
(*astHandle) = tmp;
}
void Toy_private_emitAstStackPop(Toy_Bucket** bucketHandle, Toy_Ast** astHandle) { void Toy_private_emitAstStackPop(Toy_Bucket** bucketHandle, Toy_Ast** astHandle) {
Toy_Ast* tmp = (Toy_Ast*)Toy_partitionBucket(bucketHandle, sizeof(Toy_Ast)); Toy_Ast* tmp = (Toy_Ast*)Toy_partitionBucket(bucketHandle, sizeof(Toy_Ast));
@@ -293,6 +313,7 @@ const char* Toy_private_getAstTypeAsCString(Toy_AstType type) {
case TOY_AST_ASSERT: return "ASSERT"; case TOY_AST_ASSERT: return "ASSERT";
case TOY_AST_IF_THEN_ELSE: return "IF_THEN_ELSE"; case TOY_AST_IF_THEN_ELSE: return "IF_THEN_ELSE";
case TOY_AST_WHILE_THEN: return "WHILE_THEN"; case TOY_AST_WHILE_THEN: return "WHILE_THEN";
case TOY_AST_FOR_THEN: return "FOR_THEN";
case TOY_AST_BREAK: return "BREAK"; case TOY_AST_BREAK: return "BREAK";
case TOY_AST_CONTINUE: return "CONTINUE"; case TOY_AST_CONTINUE: return "CONTINUE";
case TOY_AST_RETURN: return "RETURN"; case TOY_AST_RETURN: return "RETURN";
@@ -305,6 +326,7 @@ const char* Toy_private_getAstTypeAsCString(Toy_AstType type) {
case TOY_AST_FN_DECLARE: return "FN_DECLARE"; case TOY_AST_FN_DECLARE: return "FN_DECLARE";
case TOY_AST_FN_INVOKE: return "FN_INVOKE"; case TOY_AST_FN_INVOKE: return "FN_INVOKE";
case TOY_AST_ATTRIBUTE: return "ATTRIBUTE"; case TOY_AST_ATTRIBUTE: return "ATTRIBUTE";
case TOY_AST_ITERABLE: return "ITERABLE";
case TOY_AST_STACK_POP: return "STACK_POP"; case TOY_AST_STACK_POP: return "STACK_POP";
+18
View File
@@ -22,6 +22,7 @@ typedef enum Toy_AstType {
TOY_AST_ASSERT, TOY_AST_ASSERT,
TOY_AST_IF_THEN_ELSE, TOY_AST_IF_THEN_ELSE,
TOY_AST_WHILE_THEN, TOY_AST_WHILE_THEN,
TOY_AST_FOR_THEN,
TOY_AST_BREAK, TOY_AST_BREAK,
TOY_AST_CONTINUE, TOY_AST_CONTINUE,
TOY_AST_RETURN, TOY_AST_RETURN,
@@ -34,6 +35,7 @@ typedef enum Toy_AstType {
TOY_AST_FN_DECLARE, TOY_AST_FN_DECLARE,
TOY_AST_FN_INVOKE, TOY_AST_FN_INVOKE,
TOY_AST_ATTRIBUTE, TOY_AST_ATTRIBUTE,
TOY_AST_ITERABLE,
TOY_AST_STACK_POP, //BUGFIX: force a single stack pop for expression statements TOY_AST_STACK_POP, //BUGFIX: force a single stack pop for expression statements
@@ -171,6 +173,12 @@ typedef struct Toy_AstWhileThen {
Toy_Ast* thenBranch; Toy_Ast* thenBranch;
} Toy_AstWhileThen; } Toy_AstWhileThen;
typedef struct Toy_AstForThen {
Toy_AstType type;
Toy_Ast* condBranch;
Toy_Ast* thenBranch;
} Toy_AstForThen;
typedef struct Toy_AstBreak { typedef struct Toy_AstBreak {
Toy_AstType type; Toy_AstType type;
} Toy_AstBreak; } Toy_AstBreak;
@@ -228,6 +236,12 @@ typedef struct Toy_AstAttribute {
Toy_Ast* right; Toy_Ast* right;
} Toy_AstAttribute; } Toy_AstAttribute;
typedef struct Toy_AstIterable {
Toy_AstType type;
Toy_Ast* left;
Toy_Ast* right;
} Toy_AstIterable;
typedef struct Toy_AstStackPop { typedef struct Toy_AstStackPop {
Toy_AstType type; Toy_AstType type;
Toy_Ast* child; Toy_Ast* child;
@@ -259,6 +273,7 @@ union Toy_Ast { //see 'test_ast.c' for bitness tests
Toy_AstAssert assert; Toy_AstAssert assert;
Toy_AstIfThenElse ifThenElse; Toy_AstIfThenElse ifThenElse;
Toy_AstWhileThen whileThen; Toy_AstWhileThen whileThen;
Toy_AstForThen forThen;
Toy_AstBreak breakPoint; Toy_AstBreak breakPoint;
Toy_AstContinue continuePoint; Toy_AstContinue continuePoint;
Toy_AstReturn fnReturn; Toy_AstReturn fnReturn;
@@ -269,6 +284,7 @@ union Toy_Ast { //see 'test_ast.c' for bitness tests
Toy_AstFnDeclare fnDeclare; Toy_AstFnDeclare fnDeclare;
Toy_AstFnInvoke fnInvoke; Toy_AstFnInvoke fnInvoke;
Toy_AstAttribute attribute; Toy_AstAttribute attribute;
Toy_AstIterable iterable;
Toy_AstStackPop stackPop; Toy_AstStackPop stackPop;
Toy_AstPass pass; Toy_AstPass pass;
Toy_AstError error; Toy_AstError error;
@@ -290,6 +306,7 @@ void Toy_private_emitAstAggregate(Toy_Bucket** bucketHandle, Toy_Ast** astHandle
void Toy_private_emitAstAssert(Toy_Bucket** bucketHandle, Toy_Ast** astHandle, Toy_Ast* child, Toy_Ast* msg); void Toy_private_emitAstAssert(Toy_Bucket** bucketHandle, Toy_Ast** astHandle, Toy_Ast* child, Toy_Ast* msg);
void Toy_private_emitAstIfThenElse(Toy_Bucket** bucketHandle, Toy_Ast** astHandle, Toy_Ast* condBranch, Toy_Ast* thenBranch, Toy_Ast* elseBranch); void Toy_private_emitAstIfThenElse(Toy_Bucket** bucketHandle, Toy_Ast** astHandle, Toy_Ast* condBranch, Toy_Ast* thenBranch, Toy_Ast* elseBranch);
void Toy_private_emitAstWhileThen(Toy_Bucket** bucketHandle, Toy_Ast** astHandle, Toy_Ast* condBranch, Toy_Ast* thenBranch); void Toy_private_emitAstWhileThen(Toy_Bucket** bucketHandle, Toy_Ast** astHandle, Toy_Ast* condBranch, Toy_Ast* thenBranch);
void Toy_private_emitAstForThen(Toy_Bucket** bucketHandle, Toy_Ast** astHandle, Toy_Ast* condBranch, Toy_Ast* thenBranch);
void Toy_private_emitAstBreak(Toy_Bucket** bucketHandle, Toy_Ast** rootHandle); void Toy_private_emitAstBreak(Toy_Bucket** bucketHandle, Toy_Ast** rootHandle);
void Toy_private_emitAstContinue(Toy_Bucket** bucketHandle, Toy_Ast** rootHandle); void Toy_private_emitAstContinue(Toy_Bucket** bucketHandle, Toy_Ast** rootHandle);
void Toy_private_emitAstReturn(Toy_Bucket** bucketHandle, Toy_Ast** astHandle); void Toy_private_emitAstReturn(Toy_Bucket** bucketHandle, Toy_Ast** astHandle);
@@ -302,6 +319,7 @@ 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_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_emitAstFunctionInvokation(Toy_Bucket** bucketHandle, Toy_Ast** astHandle, Toy_Ast* params);
void Toy_private_emitAstAttribute(Toy_Bucket** bucketHandle, Toy_Ast** astHandle, Toy_Ast* expr); void Toy_private_emitAstAttribute(Toy_Bucket** bucketHandle, Toy_Ast** astHandle, Toy_Ast* expr);
void Toy_private_emitAstIterable(Toy_Bucket** bucketHandle, Toy_Ast** astHandle, Toy_Ast* expr);
void Toy_private_emitAstStackPop(Toy_Bucket** bucketHandle, Toy_Ast** astHandle); void Toy_private_emitAstStackPop(Toy_Bucket** bucketHandle, Toy_Ast** astHandle);
+2 -1
View File
@@ -91,6 +91,7 @@ static void attr_arrayPopBack(Toy_VM* vm, Toy_FunctionNative* self) {
} }
static void attr_arrayForEach(Toy_VM* vm, Toy_FunctionNative* self) { static void attr_arrayForEach(Toy_VM* vm, Toy_FunctionNative* self) {
//URGENT: replace with for-loop
(void)self; (void)self;
Toy_Value compound = Toy_popStack(&vm->stack); Toy_Value compound = Toy_popStack(&vm->stack);
@@ -241,7 +242,7 @@ static void attr_tableForEach(Toy_VM* vm, Toy_FunctionNative* self) {
(void)vm; (void)vm;
(void)self; (void)self;
//URGENT: attr_tableForEach //URGENT: replace with for-loop
} }
Toy_Value Toy_private_handleTableAttributes(Toy_VM* vm, Toy_Value compound, Toy_Value attribute) { Toy_Value Toy_private_handleTableAttributes(Toy_VM* vm, Toy_Value compound, Toy_Value attribute) {
+78 -2
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);
@@ -718,6 +719,71 @@ static unsigned int writeInstructionWhileThen(Toy_Bytecode** mb, Toy_AstWhileThe
return 0; return 0;
} }
static unsigned int writeInstructionForThen(Toy_Bytecode** mb, Toy_AstForThen ast) {
//check the operands
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) {
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;
return 1;
}
static unsigned int writeInstructionBreak(Toy_Bytecode** mb, Toy_AstBreak ast) { static unsigned int writeInstructionBreak(Toy_Bytecode** mb, Toy_AstBreak ast) {
//unused //unused
(void)ast; (void)ast;
@@ -1154,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);
@@ -1244,6 +1310,10 @@ static unsigned int writeBytecodeFromAst(Toy_Bytecode** mb, Toy_Ast* ast) {
result += writeInstructionWhileThen(mb, ast->whileThen); result += writeInstructionWhileThen(mb, ast->whileThen);
break; break;
case TOY_AST_FOR_THEN:
result += writeInstructionForThen(mb, ast->forThen);
break;
case TOY_AST_BREAK: case TOY_AST_BREAK:
result += writeInstructionBreak(mb, ast->breakPoint); result += writeInstructionBreak(mb, ast->breakPoint);
break; break;
@@ -1284,6 +1354,12 @@ static unsigned int writeBytecodeFromAst(Toy_Bytecode** mb, Toy_Ast* ast) {
result += writeInstructionAttribute(mb, ast->attribute); result += writeInstructionAttribute(mb, ast->attribute);
break; break;
case TOY_AST_ITERABLE:
//the 'in' keyword is only valid within a for-loop's condition
fprintf(stderr, TOY_CC_ERROR "COMPILER ERROR: the 'in' keyword is only valid within a for-loop's condition\n" TOY_CC_RESET);
(*mb)->panic = true;
break;
case TOY_AST_STACK_POP: case TOY_AST_STACK_POP:
result += writeInstructionStackPop(mb, ast->stackPop); result += writeInstructionStackPop(mb, ast->stackPop);
break; break;
+2
View File
@@ -14,6 +14,7 @@ typedef enum Toy_OpcodeType {
TOY_OPCODE_ATTRIBUTE, //for accessing parts of compounds TOY_OPCODE_ATTRIBUTE, //for accessing parts of compounds
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,
@@ -66,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;
+84 -6
View File
@@ -122,6 +122,7 @@ static Toy_AstFlag aggregate(Toy_Bucket** bucketHandle, Toy_Parser* parser, Toy_
static Toy_AstFlag unaryPostfix(Toy_Bucket** bucketHandle, Toy_Parser* parser, Toy_Ast** rootHandle); static Toy_AstFlag unaryPostfix(Toy_Bucket** bucketHandle, Toy_Parser* parser, Toy_Ast** rootHandle);
static Toy_AstFlag invoke(Toy_Bucket** bucketHandle, Toy_Parser* parser, Toy_Ast** rootHandle); static Toy_AstFlag invoke(Toy_Bucket** bucketHandle, Toy_Parser* parser, Toy_Ast** rootHandle);
static Toy_AstFlag attribute(Toy_Bucket** bucketHandle, Toy_Parser* parser, Toy_Ast** rootHandle); static Toy_AstFlag attribute(Toy_Bucket** bucketHandle, Toy_Parser* parser, Toy_Ast** rootHandle);
static Toy_AstFlag iterable(Toy_Bucket** bucketHandle, Toy_Parser* parser, Toy_Ast** rootHandle);
//precedence definitions //precedence definitions
static ParsingTuple parsingRulesetTable[] = { static ParsingTuple parsingRulesetTable[] = {
@@ -156,7 +157,7 @@ static ParsingTuple parsingRulesetTable[] = {
{PREC_NONE,NULL,NULL},// TOY_TOKEN_KEYWORD_FUNCTION, {PREC_NONE,NULL,NULL},// TOY_TOKEN_KEYWORD_FUNCTION,
{PREC_NONE,NULL,NULL},// TOY_TOKEN_KEYWORD_IF, {PREC_NONE,NULL,NULL},// TOY_TOKEN_KEYWORD_IF,
{PREC_NONE,NULL,NULL},// TOY_TOKEN_KEYWORD_IMPORT, {PREC_NONE,NULL,NULL},// TOY_TOKEN_KEYWORD_IMPORT,
{PREC_NONE,NULL,NULL},// TOY_TOKEN_KEYWORD_IN, {PREC_CALL,NULL,iterable},// TOY_TOKEN_KEYWORD_IN,
{PREC_NONE,NULL,NULL},// TOY_TOKEN_KEYWORD_OF, {PREC_NONE,NULL,NULL},// TOY_TOKEN_KEYWORD_OF,
{PREC_NONE,NULL,NULL},// TOY_TOKEN_KEYWORD_PASS, {PREC_NONE,NULL,NULL},// TOY_TOKEN_KEYWORD_PASS,
{PREC_NONE,NULL,NULL},// TOY_TOKEN_KEYWORD_PRINT, {PREC_NONE,NULL,NULL},// TOY_TOKEN_KEYWORD_PRINT,
@@ -760,6 +761,25 @@ static Toy_AstFlag attribute(Toy_Bucket** bucketHandle, Toy_Parser* parser, Toy_
} }
} }
static Toy_AstFlag iterable(Toy_Bucket** bucketHandle, Toy_Parser* parser, Toy_Ast** rootHandle) {
//infix must advance
advance(parser);
//check for the correct operands
if ((*rootHandle)->type != TOY_AST_VAR_DECLARE) {
printError(parser, parser->previous, "Expected iterator name not found");
Toy_private_emitAstError(bucketHandle, rootHandle);
return TOY_AST_FLAG_NONE;
}
Toy_Ast* expr = NULL;
parsePrecedence(bucketHandle, parser, rootHandle, PREC_CALL);
Toy_private_emitAstIterable(bucketHandle, rootHandle, expr);
return TOY_AST_FLAG_NONE;
}
//grammar rules //grammar rules
static void parsePrecedence(Toy_Bucket** bucketHandle, Toy_Parser* parser, Toy_Ast** rootHandle, ParsingPrecedence precRule) { static void parsePrecedence(Toy_Bucket** bucketHandle, Toy_Parser* parser, Toy_Ast** rootHandle, ParsingPrecedence precRule) {
//'step over' the token to parse //'step over' the token to parse
@@ -771,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");
@@ -865,7 +885,7 @@ static void makeIfThenElseStmt(Toy_Bucket** bucketHandle, Toy_Parser* parser, To
makeExpr(bucketHandle, parser, &condBranch); makeExpr(bucketHandle, parser, &condBranch);
consume(parser, TOY_TOKEN_OPERATOR_PAREN_RIGHT, "Expected ')' after 'if' condition"); consume(parser, TOY_TOKEN_OPERATOR_PAREN_RIGHT, "Expected ')' after 'if' condition");
// { thenBranch } //{ thenBranch }
makeDeclarationStmt(bucketHandle, parser, &thenBranch, true); makeDeclarationStmt(bucketHandle, parser, &thenBranch, true);
//else { elseBranch } //else { elseBranch }
@@ -885,12 +905,66 @@ static void makeWhileStmt(Toy_Bucket** bucketHandle, Toy_Parser* parser, Toy_Ast
makeExpr(bucketHandle, parser, &condBranch); makeExpr(bucketHandle, parser, &condBranch);
consume(parser, TOY_TOKEN_OPERATOR_PAREN_RIGHT, "Expected ')' after 'while' condition"); consume(parser, TOY_TOKEN_OPERATOR_PAREN_RIGHT, "Expected ')' after 'while' condition");
// { thenBranch } //{ thenBranch }
makeDeclarationStmt(bucketHandle, parser, &thenBranch, true); makeDeclarationStmt(bucketHandle, parser, &thenBranch, true);
Toy_private_emitAstWhileThen(bucketHandle, rootHandle, condBranch, thenBranch); Toy_private_emitAstWhileThen(bucketHandle, rootHandle, condBranch, thenBranch);
} }
static void makeForStmt(Toy_Bucket** bucketHandle, Toy_Parser* parser, Toy_Ast** rootHandle) {
Toy_Ast* condBranch = NULL;
Toy_Ast* thenBranch = NULL;
//BUG: wtf am I doing here?
//for (condBranch)
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);
consume(parser, TOY_TOKEN_OPERATOR_PAREN_RIGHT, "Expected ')' after 'for' condition");
if (condBranch->type != TOY_AST_ITERABLE) {
printError(parser, parser->previous, "Expected 'in' in for condition");
Toy_private_emitAstError(bucketHandle, rootHandle);
return;
}
//{ thenBranch }
makeDeclarationStmt(bucketHandle, parser, &thenBranch, true);
Toy_private_emitAstForThen(bucketHandle, rootHandle, condBranch, thenBranch);
}
static void makeBreakStmt(Toy_Bucket** bucketHandle, Toy_Parser* parser, Toy_Ast** rootHandle) { static void makeBreakStmt(Toy_Bucket** bucketHandle, Toy_Parser* parser, Toy_Ast** rootHandle) {
Toy_private_emitAstBreak(bucketHandle, rootHandle); Toy_private_emitAstBreak(bucketHandle, rootHandle);
consume(parser, TOY_TOKEN_OPERATOR_SEMICOLON, "Expected ';' at the end of break statement"); consume(parser, TOY_TOKEN_OPERATOR_SEMICOLON, "Expected ';' at the end of break statement");
@@ -1070,7 +1144,11 @@ static void makeStmt(Toy_Bucket** bucketHandle, Toy_Parser* parser, Toy_Ast** ro
return; return;
} }
//URGENT: for-pre-clause-post-then //for
else if (match(parser, TOY_TOKEN_KEYWORD_FOR)) {
makeForStmt(bucketHandle, parser, rootHandle);
return;
}
//break //break
else if (match(parser, TOY_TOKEN_KEYWORD_BREAK)) { else if (match(parser, TOY_TOKEN_KEYWORD_BREAK)) {
@@ -1090,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)) {
+1 -1
View File
@@ -29,7 +29,7 @@ typedef enum Toy_TokenType {
TOY_TOKEN_KEYWORD_DO, //unused TOY_TOKEN_KEYWORD_DO, //unused
TOY_TOKEN_KEYWORD_ELSE, TOY_TOKEN_KEYWORD_ELSE,
TOY_TOKEN_KEYWORD_EXPORT, //unused TOY_TOKEN_KEYWORD_EXPORT, //unused
TOY_TOKEN_KEYWORD_FOR, //unused TOY_TOKEN_KEYWORD_FOR,
TOY_TOKEN_KEYWORD_FOREACH, //unused TOY_TOKEN_KEYWORD_FOREACH, //unused
TOY_TOKEN_KEYWORD_FUNCTION, //remapped 'fn' TOY_TOKEN_KEYWORD_FUNCTION, //remapped 'fn'
TOY_TOKEN_KEYWORD_IF, TOY_TOKEN_KEYWORD_IF,
+66 -1
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
unsigned int x = (unsigned int)READ_BYTE(vm);
for (unsigned int i = 0; i < x; i++) {
Toy_Value value = Toy_popStack(&vm->stack); Toy_Value value = Toy_popStack(&vm->stack);
Toy_freeValue(value); 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: