While is working but untested, read more

* TODO: break and continue keywords need to be implemented
* TODO: while-then needs testing
* Fixed the parser not liking zero-length strings
This commit is contained in:
2024-11-26 14:48:24 +11:00
parent 0947430c29
commit 6cc331d462
7 changed files with 139 additions and 25 deletions

27
scripts/fizzbuzz.toy Normal file
View File

@@ -0,0 +1,27 @@
//moment of truth
var counter: int = 1;
while (counter <= 100) {
var result: string = "";
if (counter % 3 == 0) {
result = result .. "fizz";
}
if (counter % 5 == 0) {
result = result .. "buzz";
}
//finally
if (result == "") {
print counter;
}
else {
print result;
}
counter += 1;
}

9
scripts/looping.toy Normal file
View File

@@ -0,0 +1,9 @@
var a: int = 0;
while(a < 10) {
print a;
a += 1;
}
print "Finished";

View File

@@ -116,6 +116,16 @@ void Toy_private_emitAstIfThenElse(Toy_Bucket** bucketHandle, Toy_Ast** astHandl
(*astHandle) = tmp; (*astHandle) = tmp;
} }
void Toy_private_emitAstWhileThen(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_WHILE_THEN;
tmp->whileThen.condBranch = condBranch;
tmp->whileThen.thenBranch = thenBranch;
(*astHandle) = tmp;
}
void Toy_private_emitAstPrint(Toy_Bucket** bucketHandle, Toy_Ast** astHandle) { void Toy_private_emitAstPrint(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));

View File

@@ -19,6 +19,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_PRINT, TOY_AST_PRINT,
TOY_AST_VAR_DECLARE, TOY_AST_VAR_DECLARE,
@@ -131,6 +132,12 @@ typedef struct Toy_AstIfThenElse {
Toy_Ast* elseBranch; Toy_Ast* elseBranch;
} Toy_AstIfThenElse; } Toy_AstIfThenElse;
typedef struct Toy_AstWhileThen {
Toy_AstType type;
Toy_Ast* condBranch;
Toy_Ast* thenBranch;
} Toy_AstWhileThen;
typedef struct Toy_AstPrint { typedef struct Toy_AstPrint {
Toy_AstType type; Toy_AstType type;
Toy_Ast* child; Toy_Ast* child;
@@ -177,6 +184,7 @@ union Toy_Ast { //32 | 64 BITNESS
Toy_AstCompound compound; //16 | 24 Toy_AstCompound compound; //16 | 24
Toy_AstAssert assert; //16 | 24 Toy_AstAssert assert; //16 | 24
Toy_AstIfThenElse ifThenElse; //16 | 32 Toy_AstIfThenElse ifThenElse; //16 | 32
Toy_AstWhileThen whileThen; //16 | 24
Toy_AstPrint print; //8 | 16 Toy_AstPrint print; //8 | 16
Toy_AstVarDeclare varDeclare; //16 | 24 Toy_AstVarDeclare varDeclare; //16 | 24
Toy_AstVarAssign varAssign; //16 | 24 Toy_AstVarAssign varAssign; //16 | 24
@@ -198,6 +206,7 @@ void Toy_private_emitAstCompound(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_emitAstPrint(Toy_Bucket** bucketHandle, Toy_Ast** astHandle); void Toy_private_emitAstPrint(Toy_Bucket** bucketHandle, Toy_Ast** astHandle);
void Toy_private_emitAstVariableDeclaration(Toy_Bucket** bucketHandle, Toy_Ast** astHandle, Toy_String* name, Toy_Ast* expr); void Toy_private_emitAstVariableDeclaration(Toy_Bucket** bucketHandle, Toy_Ast** astHandle, Toy_String* name, Toy_Ast* expr);

View File

@@ -352,31 +352,33 @@ static Toy_AstFlag literal(Toy_Bucket** bucketHandle, Toy_Parser* parser, Toy_As
case TOY_TOKEN_LITERAL_STRING: { case TOY_TOKEN_LITERAL_STRING: {
char buffer[parser->previous.length + 1]; char buffer[parser->previous.length + 1];
unsigned int escapeCounter = 0; unsigned int escapeCounter = 0;
unsigned int i = 0, o = 0; unsigned int i = 0, o = 0;
do {
buffer[i] = parser->previous.lexeme[o];
if (buffer[i] == '\\' && parser->previous.lexeme[++o]) {
escapeCounter++;
//also handle escape characters if (parser->previous.length > 0) { //BUGFIX: compensate for zero-length strings
switch(parser->previous.lexeme[o]) { do {
case 'n': buffer[i] = parser->previous.lexeme[o];
buffer[i] = '\n'; if (buffer[i] == '\\' && parser->previous.lexeme[++o]) {
break; escapeCounter++;
case 't':
buffer[i] = '\t'; //also handle escape characters
break; switch(parser->previous.lexeme[o]) {
case '\\': case 'n':
buffer[i] = '\\'; buffer[i] = '\n';
break; break;
case '"': case 't':
buffer[i] = '"'; buffer[i] = '\t';
break; break;
case '\\':
buffer[i] = '\\';
break;
case '"':
buffer[i] = '"';
break;
}
} }
} i++;
i++; } while (parser->previous.lexeme[o++] && i < parser->previous.length);
} while (parser->previous.lexeme[o++] && i < parser->previous.length); }
buffer[i] = '\0'; buffer[i] = '\0';
unsigned int len = i - escapeCounter; //NOTE: len is ONLY the string length unsigned int len = i - escapeCounter; //NOTE: len is ONLY the string length
@@ -699,6 +701,21 @@ static void makeIfThenElseStmt(Toy_Bucket** bucketHandle, Toy_Parser* parser, To
Toy_private_emitAstIfThenElse(bucketHandle, rootHandle, condBranch, thenBranch, elseBranch); Toy_private_emitAstIfThenElse(bucketHandle, rootHandle, condBranch, thenBranch, elseBranch);
} }
static void makeWhileStmt(Toy_Bucket** bucketHandle, Toy_Parser* parser, Toy_Ast** rootHandle) {
Toy_Ast* condBranch = NULL;
Toy_Ast* thenBranch = NULL;
//while (condBranch)
consume(parser, TOY_TOKEN_OPERATOR_PAREN_LEFT, "Expected '(' after 'while' keyword");
makeExpr(bucketHandle, parser, &condBranch);
consume(parser, TOY_TOKEN_OPERATOR_PAREN_RIGHT, "Expected ')' after 'while' condition");
// { thenBranch }
makeDeclarationStmt(bucketHandle, parser, &thenBranch);
Toy_private_emitAstWhileThen(bucketHandle, rootHandle, condBranch, thenBranch);
}
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);
Toy_private_emitAstPrint(bucketHandle, rootHandle); Toy_private_emitAstPrint(bucketHandle, rootHandle);
@@ -771,10 +788,15 @@ static void makeStmt(Toy_Bucket** bucketHandle, Toy_Parser* parser, Toy_Ast** ro
return; return;
} }
//TODO: break & continue
//while-then //while-then
else if (match(parser, TOY_TOKEN_KEYWORD_WHILE)) {
makeWhileStmt(bucketHandle, parser, rootHandle);
return;
}
//for-pre-clause-post-then //for-pre-clause-post-then
//break
//continue
//return //return
//import //import

View File

@@ -319,7 +319,7 @@ static unsigned int writeInstructionIfThenElse(Toy_Routine** rt, Toy_AstIfThenEl
unsigned int thenEndAddr = SKIP_INT(rt, code); //parameter to be written later unsigned int thenEndAddr = SKIP_INT(rt, code); //parameter to be written later
//emit then branch //emit then-branch
writeRoutineCode(rt, ast.thenBranch); writeRoutineCode(rt, ast.thenBranch);
if (ast.elseBranch != NULL) { if (ast.elseBranch != NULL) {
@@ -349,6 +349,37 @@ static unsigned int writeInstructionIfThenElse(Toy_Routine** rt, Toy_AstIfThenEl
return 0; return 0;
} }
static unsigned int writeInstructionWhileThen(Toy_Routine** rt, Toy_AstWhileThen ast) {
//TODO: begin
unsigned int beginAddr = CURRENT_ADDRESS(rt, code);
//cond-branch
writeRoutineCode(rt, ast.condBranch);
//emit the jump word (opcode, type, condition, padding)
EMIT_BYTE(rt, code, TOY_OPCODE_JUMP);
EMIT_BYTE(rt, code, TOY_OP_PARAM_JUMP_RELATIVE);
EMIT_BYTE(rt, code, TOY_OP_PARAM_JUMP_IF_FALSE);
EMIT_BYTE(rt, code, 0);
unsigned int endAddr = SKIP_INT(rt, code); //parameter to be written later
//emit then-branch
writeRoutineCode(rt, ast.thenBranch);
//jump to begin to repeat the conditional test
EMIT_BYTE(rt, code, TOY_OPCODE_JUMP);
EMIT_BYTE(rt, code, TOY_OP_PARAM_JUMP_RELATIVE);
EMIT_BYTE(rt, code, TOY_OP_PARAM_JUMP_ALWAYS);
EMIT_BYTE(rt, code, 0);
EMIT_INT(rt, code, beginAddr - (CURRENT_ADDRESS(rt, code) + 4)); //this sets a negative value
OVERWRITE_INT(rt, code, endAddr, CURRENT_ADDRESS(rt, code) - (endAddr + 4));
return 0;
}
static unsigned int writeInstructionPrint(Toy_Routine** rt, Toy_AstPrint ast) { static unsigned int writeInstructionPrint(Toy_Routine** rt, Toy_AstPrint ast) {
//the thing to print //the thing to print
writeRoutineCode(rt, ast.child); writeRoutineCode(rt, ast.child);
@@ -603,6 +634,10 @@ static unsigned int writeRoutineCode(Toy_Routine** rt, Toy_Ast* ast) {
result += writeInstructionIfThenElse(rt, ast->ifThenElse); result += writeInstructionIfThenElse(rt, ast->ifThenElse);
break; break;
case TOY_AST_WHILE_THEN:
result += writeInstructionWhileThen(rt, ast->whileThen);
break;
case TOY_AST_PRINT: case TOY_AST_PRINT:
result += writeInstructionPrint(rt, ast->print); result += writeInstructionPrint(rt, ast->print);
break; break;

View File

@@ -26,6 +26,7 @@ int test_sizeof_ast_64bit() {
TEST_SIZEOF(Toy_AstCompound, 24); TEST_SIZEOF(Toy_AstCompound, 24);
TEST_SIZEOF(Toy_AstAssert, 24); TEST_SIZEOF(Toy_AstAssert, 24);
TEST_SIZEOF(Toy_AstIfThenElse, 32); TEST_SIZEOF(Toy_AstIfThenElse, 32);
TEST_SIZEOF(Toy_AstWhileThen, 24);
TEST_SIZEOF(Toy_AstPrint, 16); TEST_SIZEOF(Toy_AstPrint, 16);
TEST_SIZEOF(Toy_AstVarDeclare, 24); TEST_SIZEOF(Toy_AstVarDeclare, 24);
TEST_SIZEOF(Toy_AstVarAssign, 24); TEST_SIZEOF(Toy_AstVarAssign, 24);
@@ -61,6 +62,7 @@ int test_sizeof_ast_32bit() {
TEST_SIZEOF(Toy_AstCompound, 16); TEST_SIZEOF(Toy_AstCompound, 16);
TEST_SIZEOF(Toy_AstAssert, 12); TEST_SIZEOF(Toy_AstAssert, 12);
TEST_SIZEOF(Toy_AstIfThenElse, 16); TEST_SIZEOF(Toy_AstIfThenElse, 16);
TEST_SIZEOF(Toy_AstWhileThen, 12);
TEST_SIZEOF(Toy_AstPrint, 8); TEST_SIZEOF(Toy_AstPrint, 8);
TEST_SIZEOF(Toy_AstVarDeclare, 12); TEST_SIZEOF(Toy_AstVarDeclare, 12);
TEST_SIZEOF(Toy_AstVarAssign, 16); TEST_SIZEOF(Toy_AstVarAssign, 16);