Implemented print keyword and associated tests

This commit is contained in:
2024-10-07 12:13:06 +11:00
parent 956ebbeb28
commit ff13b5cf38
16 changed files with 346 additions and 60 deletions

View File

@@ -72,6 +72,15 @@ void Toy_private_emitAstGroup(Toy_Bucket** bucketHandle, Toy_Ast** astHandle) {
(*astHandle) = tmp;
}
void Toy_private_emitAstPrint(Toy_Bucket** bucketHandle, Toy_Ast** astHandle) {
Toy_Ast* tmp = (Toy_Ast*)Toy_partitionBucket(bucketHandle, sizeof(Toy_Ast));
tmp->type = TOY_AST_PRINT;
tmp->print.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));

View File

@@ -14,6 +14,8 @@ typedef enum Toy_AstType {
TOY_AST_BINARY,
TOY_AST_GROUP,
TOY_AST_PRINT,
TOY_AST_PASS,
TOY_AST_ERROR,
TOY_AST_END,
@@ -85,6 +87,11 @@ typedef struct Toy_AstGroup {
Toy_Ast* child;
} Toy_AstGroup;
typedef struct Toy_AstPrint {
Toy_AstType type;
Toy_Ast* child;
} Toy_AstPrint;
typedef struct Toy_AstPass {
Toy_AstType type;
} Toy_AstPass;
@@ -105,6 +112,7 @@ union Toy_Ast { //32 | 64 BITNESS
Toy_AstUnary unary; //12 | 16
Toy_AstBinary binary; //16 | 24
Toy_AstGroup group; //8 | 16
Toy_AstPrint print; //8 | 16
Toy_AstPass pass; //4 | 4
Toy_AstError error; //4 | 4
Toy_AstEnd end; //4 | 4
@@ -118,6 +126,8 @@ void Toy_private_emitAstUnary(Toy_Bucket** bucketHandle, Toy_Ast** astHandle, To
void Toy_private_emitAstBinary(Toy_Bucket** bucketHandle, Toy_Ast** astHandle,Toy_AstFlag flag, Toy_Ast* right);
void Toy_private_emitAstGroup(Toy_Bucket** bucketHandle, Toy_Ast** astHandle);
void Toy_private_emitAstPrint(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);

View File

@@ -33,6 +33,10 @@ typedef enum Toy_OpcodeType {
//control instructions
TOY_OPCODE_RETURN,
//various action instructions
TOY_OPCODE_PRINT,
//TODO: clear the program stack
//meta instructions
TOY_OPCODE_PASS,
TOY_OPCODE_ERROR,

View File

@@ -482,20 +482,20 @@ static void makeExpr(Toy_Bucket** bucketHandle, Toy_Parser* parser, Toy_Ast** ro
parsePrecedence(bucketHandle, parser, rootHandle, PREC_ASSIGNMENT);
}
static void makeExprStmt(Toy_Bucket** bucketHandle, Toy_Parser* parser, Toy_Ast** rootHandle) {
//check for empty lines
if (match(parser, TOY_TOKEN_OPERATOR_SEMICOLON)) {
Toy_private_emitAstPass(bucketHandle, rootHandle);
return;
}
static void makePrintStmt(Toy_Bucket** bucketHandle, Toy_Parser* parser, Toy_Ast** rootHandle) {
makeExpr(bucketHandle, parser, rootHandle);
Toy_private_emitAstPrint(bucketHandle, rootHandle);
consume(parser, TOY_TOKEN_OPERATOR_SEMICOLON, "Expected ';' at the end of print statement");
}
static void makeExprStmt(Toy_Bucket** bucketHandle, Toy_Parser* parser, Toy_Ast** rootHandle) {
makeExpr(bucketHandle, parser, rootHandle);
consume(parser, TOY_TOKEN_OPERATOR_SEMICOLON, "Expected ';' at the end of expression statement");
}
static void makeStmt(Toy_Bucket** bucketHandle, Toy_Parser* parser, Toy_Ast** rootHandle) {
//block
//print
//assert
//if-then-else
//while-then
@@ -505,8 +505,22 @@ static void makeStmt(Toy_Bucket** bucketHandle, Toy_Parser* parser, Toy_Ast** ro
//return
//import
//default
makeExprStmt(bucketHandle, parser, rootHandle);
//check for empty lines
if (match(parser, TOY_TOKEN_OPERATOR_SEMICOLON)) {
Toy_private_emitAstPass(bucketHandle, rootHandle);
return;
}
else if (match(parser, TOY_TOKEN_KEYWORD_PRINT)) {
makePrintStmt(bucketHandle, parser, rootHandle);
return;
}
else {
//default
makeExprStmt(bucketHandle, parser, rootHandle);
return;
}
}
static void makeDeclarationStmt(Toy_Bucket** bucketHandle, Toy_Parser* parser, Toy_Ast** rootHandle) {

View File

@@ -33,6 +33,7 @@ void Toy_setPrintCallback(Toy_callbackType cb) {
void Toy_setErrorCallback(Toy_callbackType cb) {
errorCallback = cb;
}
void Toy_setAssertFailureCallback(Toy_callbackType cb) {
assertCallback = cb;
}
@@ -48,4 +49,3 @@ void Toy_resetErrorCallback() {
void Toy_resetAssertFailureCallback() {
assertCallback = errDefault;
}

View File

@@ -63,25 +63,25 @@ static void writeInstructionValue(Toy_Routine** rt, Toy_AstValue ast) {
if (TOY_VALUE_IS_NULL(ast.value)) {
//NOTHING - null's type data is enough
//BUGFIX: 4-byte alignment
//4-byte alignment
EMIT_BYTE(rt, 0);
EMIT_BYTE(rt, 0);
}
else if (TOY_VALUE_IS_BOOLEAN(ast.value)) {
EMIT_BYTE(rt, TOY_VALUE_AS_BOOLEAN(ast.value));
//BUGFIX: 4-byte alignment
//4-byte alignment
EMIT_BYTE(rt, 0);
}
else if (TOY_VALUE_IS_INTEGER(ast.value)) {
//BUGFIX: 4-byte alignment
//4-byte alignment
EMIT_BYTE(rt, 0);
EMIT_BYTE(rt, 0);
EMIT_INT(rt, code, TOY_VALUE_AS_INTEGER(ast.value));
}
else if (TOY_VALUE_IS_FLOAT(ast.value)) {
//BUGFIX: 4-byte alignment
//4-byte alignment
EMIT_BYTE(rt, 0);
EMIT_BYTE(rt, 0);
@@ -100,7 +100,7 @@ static void writeInstructionUnary(Toy_Routine** rt, Toy_AstUnary ast) {
if (ast.flag == TOY_AST_FLAG_NEGATE) {
EMIT_BYTE(rt, TOY_OPCODE_NEGATE);
//BUGFIX: 4-byte alignment
//4-byte alignment
EMIT_BYTE(rt, 0);
EMIT_BYTE(rt, 0);
EMIT_BYTE(rt, 0);
@@ -197,7 +197,20 @@ static void writeInstructionBinary(Toy_Routine** rt, Toy_AstBinary ast) {
exit(-1);
}
//BUGFIX: 4-byte alignment (covers most cases)
//4-byte alignment (covers most cases)
EMIT_BYTE(rt, 0);
EMIT_BYTE(rt, 0);
EMIT_BYTE(rt, 0);
}
static void writeInstructionPrint(Toy_Routine** rt, Toy_AstPrint ast) {
//the thing to print
writeRoutineCode(rt, ast.child);
//output the print opcode
EMIT_BYTE(rt, TOY_OPCODE_PRINT);
//4-byte alignment
EMIT_BYTE(rt, 0);
EMIT_BYTE(rt, 0);
EMIT_BYTE(rt, 0);
@@ -232,6 +245,10 @@ static void writeRoutineCode(Toy_Routine** rt, Toy_Ast* ast) {
writeInstructionBinary(rt, ast->binary);
break;
case TOY_AST_PRINT:
writeInstructionPrint(rt, ast->print);
break;
//other disallowed instructions
case TOY_AST_GROUP:
fprintf(stderr, TOY_CC_ERROR "ERROR: Invalid AST type found: Group shouldn't be used\n" TOY_CC_RESET);
@@ -271,7 +288,7 @@ static void* writeRoutine(Toy_Routine* rt, Toy_Ast* ast) {
//code
writeRoutineCode(&rt, ast);
EMIT_BYTE(&rt, TOY_OPCODE_RETURN); //temp terminator
EMIT_BYTE(&rt, 0); //BUGFIX: 4-byte alignment
EMIT_BYTE(&rt, 0); //4-byte alignment
EMIT_BYTE(&rt, 0);
EMIT_BYTE(&rt, 0);
//TODO: jumps

View File

@@ -58,4 +58,3 @@ TOY_API bool Toy_private_isTruthy(Toy_Value value);
TOY_API bool Toy_private_isEqual(Toy_Value left, Toy_Value right);
unsigned int Toy_hashValue(Toy_Value value);

View File

@@ -1,6 +1,7 @@
#include "toy_vm.h"
#include "toy_console_colors.h"
#include "toy_print.h"
#include "toy_opcodes.h"
#include "toy_value.h"
@@ -235,15 +236,55 @@ static void processLogical(Toy_VM* vm, Toy_OpcodeType opcode) {
}
}
static void processPrint(Toy_VM* vm) {
//print the value on top of the stack, popping it
Toy_Value value = Toy_popStack(&vm->stack);
//NOTE: don't append a newline - leave that choice to the host
switch(value.type) {
case TOY_VALUE_NULL:
Toy_print("null");
break;
case TOY_VALUE_BOOLEAN:
Toy_print(TOY_VALUE_AS_BOOLEAN(value) ? "true" : "false");
break;
case TOY_VALUE_INTEGER: {
char buffer[16];
sprintf(buffer, "%d", TOY_VALUE_AS_INTEGER(value));
Toy_print(buffer);
break;
}
case TOY_VALUE_FLOAT: {
char buffer[16];
sprintf(buffer, "%f", TOY_VALUE_AS_FLOAT(value));
Toy_print(buffer);
break;
}
case TOY_VALUE_STRING: //TODO: decide on how long strings, etc. live for in memory
case TOY_VALUE_ARRAY:
case TOY_VALUE_DICTIONARY:
case TOY_VALUE_FUNCTION:
case TOY_VALUE_OPAQUE:
fprintf(stderr, TOY_CC_ERROR "ERROR: Unknown value type %d passed to processPrint, exiting\n" TOY_CC_RESET, value.type);
exit(-1);
}
}
static void process(Toy_VM* vm) {
while(true) {
Toy_OpcodeType opcode = READ_BYTE(vm);
switch(opcode) {
//variable instructions
case TOY_OPCODE_READ:
processRead(vm);
break;
//arithmetic instructions
case TOY_OPCODE_ADD:
case TOY_OPCODE_SUBTRACT:
case TOY_OPCODE_MULTIPLY:
@@ -252,6 +293,7 @@ static void process(Toy_VM* vm) {
processArithmetic(vm, opcode);
break;
//comparison instructions
case TOY_OPCODE_COMPARE_EQUAL:
case TOY_OPCODE_COMPARE_LESS:
case TOY_OPCODE_COMPARE_LESS_EQUAL:
@@ -260,6 +302,7 @@ static void process(Toy_VM* vm) {
processComparison(vm, opcode);
break;
//logical instructions
case TOY_OPCODE_AND:
case TOY_OPCODE_OR:
case TOY_OPCODE_TRUTHY:
@@ -267,6 +310,17 @@ static void process(Toy_VM* vm) {
processLogical(vm, opcode);
break;
//control instructions
case TOY_OPCODE_RETURN:
//temp terminator
return;
//various action instructions
case TOY_OPCODE_PRINT:
processPrint(vm);
break;
//not yet implemented
case TOY_OPCODE_LOAD:
case TOY_OPCODE_LOAD_LONG:
case TOY_OPCODE_DECLARE:
@@ -277,10 +331,6 @@ static void process(Toy_VM* vm) {
case TOY_OPCODE_EOF:
fprintf(stderr, TOY_CC_ERROR "ERROR: Invalid opcode %d found, exiting\n" TOY_CC_RESET, opcode);
exit(-1);
case TOY_OPCODE_RETURN: //temp terminator, temp position
//
return;
}
//prepare for the next instruction