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

@@ -20,6 +20,7 @@ int test_sizeof_ast_64bit() {
TEST_SIZEOF(Toy_AstUnary, 16);
TEST_SIZEOF(Toy_AstBinary, 24);
TEST_SIZEOF(Toy_AstGroup, 16);
TEST_SIZEOF(Toy_AstPrint, 16);
TEST_SIZEOF(Toy_AstPass, 4);
TEST_SIZEOF(Toy_AstError, 4);
TEST_SIZEOF(Toy_AstEnd, 4);
@@ -47,6 +48,7 @@ int test_sizeof_ast_32bit() {
TEST_SIZEOF(Toy_AstUnary, 12);
TEST_SIZEOF(Toy_AstBinary, 16);
TEST_SIZEOF(Toy_AstGroup, 8);
TEST_SIZEOF(Toy_AstPrint, 8);
TEST_SIZEOF(Toy_AstPass, 4);
TEST_SIZEOF(Toy_AstError, 4);
TEST_SIZEOF(Toy_AstEnd, 4);
@@ -146,6 +148,33 @@ int test_type_emission(Toy_Bucket** bucketHandle) {
}
}
//emit print keyword
{
//build the AST
Toy_Ast* ast = NULL;
Toy_Ast* right = NULL;
Toy_private_emitAstValue(bucketHandle, &ast, TOY_VALUE_TO_INTEGER(42));
Toy_private_emitAstValue(bucketHandle, &right, TOY_VALUE_TO_INTEGER(69));
Toy_private_emitAstBinary(bucketHandle, &ast, TOY_AST_FLAG_ADD, right);
Toy_private_emitAstPrint(bucketHandle, &ast);
//check if it worked
if (
ast == NULL ||
ast->type != TOY_AST_PRINT ||
ast->print.child == NULL ||
ast->print.child->type != TOY_AST_BINARY ||
ast->print.child->binary.flag != TOY_AST_FLAG_ADD ||
ast->print.child->binary.left->type != TOY_AST_VALUE ||
TOY_VALUE_AS_INTEGER(ast->print.child->binary.left->value.value) != 42 ||
ast->print.child->binary.right->type != TOY_AST_VALUE ||
TOY_VALUE_AS_INTEGER(ast->print.child->binary.right->value.value) != 69)
{
fprintf(stderr, TOY_CC_ERROR "ERROR: failed to emit a print as 'Toy_Ast', state unknown\n" TOY_CC_RESET);
return -1;
}
}
//emit and append blocks of code
{
//initialize the root block

View File

@@ -10,7 +10,7 @@
#include <string.h>
//tests
int test_routine_header_and_values(Toy_Bucket** bucketHandle) {
int test_routine_expressions(Toy_Bucket** bucketHandle) {
//simple test to ensure the header looks right with an empty ast
{
//setup
@@ -248,7 +248,7 @@ int test_routine_header_and_values(Toy_Bucket** bucketHandle) {
*((unsigned char*)(buffer + 27)) != 0 ||
*(int*)(buffer + 28) != 42 ||
*((unsigned char*)(buffer + 32)) != TOY_OPCODE_RETURN ||
*((unsigned char*)(buffer + 23)) != 0 ||
*((unsigned char*)(buffer + 33)) != 0 ||
*((unsigned char*)(buffer + 34)) != 0 ||
*((unsigned char*)(buffer + 35)) != 0
)
@@ -302,7 +302,7 @@ int test_routine_header_and_values(Toy_Bucket** bucketHandle) {
*((unsigned char*)(buffer + 27)) != 0 ||
*(float*)(buffer + 28) != 3.1415f ||
*((unsigned char*)(buffer + 32)) != TOY_OPCODE_RETURN ||
*((unsigned char*)(buffer + 23)) != 0 ||
*((unsigned char*)(buffer + 33)) != 0 ||
*((unsigned char*)(buffer + 34)) != 0 ||
*((unsigned char*)(buffer + 35)) != 0
)
@@ -619,13 +619,75 @@ int test_routine_binary(Toy_Bucket** bucketHandle) {
return 0;
}
int test_routine_keywords(Toy_Bucket** bucketHandle) {
//print
{
//setup
const char* source = "print 42;";
Toy_Lexer lexer;
Toy_Parser parser;
Toy_bindLexer(&lexer, source);
Toy_bindParser(&parser, &lexer);
Toy_Ast* ast = Toy_scanParser(bucketHandle, &parser);
//run
void* buffer = Toy_compileRoutine(ast);
int len = ((int*)buffer)[0];
//check header
int* ptr = (int*)buffer;
if ((ptr++)[0] != 40 || //total size
(ptr++)[0] != 0 || //param count
(ptr++)[0] != 0 || //jump count
(ptr++)[0] != 0 || //data count
(ptr++)[0] != 0) //subs count
{
fprintf(stderr, TOY_CC_ERROR "ERROR: failed to produce the expected routine header, source: %s\n" TOY_CC_RESET, source);
//cleanup and return
free(buffer);
return -1;
}
//check code
if (*((unsigned char*)(buffer + 24)) != TOY_OPCODE_READ ||
*((unsigned char*)(buffer + 25)) != TOY_VALUE_INTEGER ||
*((unsigned char*)(buffer + 26)) != 0 ||
*((unsigned char*)(buffer + 27)) != 0 ||
*(int*)(buffer + 28) != 42 ||
*((unsigned char*)(buffer + 32)) != TOY_OPCODE_PRINT ||
*((unsigned char*)(buffer + 33)) != 0 ||
*((unsigned char*)(buffer + 34)) != 0 ||
*((unsigned char*)(buffer + 35)) != 0 ||
*((unsigned char*)(buffer + 36)) != TOY_OPCODE_RETURN ||
*((unsigned char*)(buffer + 37)) != 0 ||
*((unsigned char*)(buffer + 38)) != 0 ||
*((unsigned char*)(buffer + 39)) != 0
)
{
fprintf(stderr, TOY_CC_ERROR "ERROR: failed to produce the expected routine code, source: %s\n" TOY_CC_RESET, source);
//cleanup and return
free(buffer);
return -1;
}
//cleanup
free(buffer);
}
return 0;
}
int main() {
//run each test set, returning the total errors given
int total = 0, res = 0;
{
Toy_Bucket* bucket = Toy_allocateBucket(sizeof(Toy_Ast) * 32);
res = test_routine_header_and_values(&bucket);
res = test_routine_expressions(&bucket);
Toy_freeBucket(&bucket);
if (res == 0) {
printf(TOY_CC_NOTICE "All good\n" TOY_CC_RESET);
@@ -643,5 +705,15 @@ int main() {
total += res;
}
{
Toy_Bucket* bucket = Toy_allocateBucket(sizeof(Toy_Ast) * 32);
res = test_routine_keywords(&bucket);
Toy_freeBucket(&bucket);
if (res == 0) {
printf(TOY_CC_NOTICE "All good\n" TOY_CC_RESET);
}
total += res;
}
return total;
}

View File

@@ -4,8 +4,10 @@
#include "toy_lexer.h"
#include "toy_parser.h"
#include "toy_bytecode.h"
#include "toy_print.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
//utils
@@ -161,6 +163,59 @@ int test_opcode_not_equal(Toy_Bucket** bucketHandle) {
return 0;
}
static char* callbackUtilReceived = NULL;
static void callbackUtil(const char* msg) {
if (msg != NULL) {
free(callbackUtilReceived);
callbackUtilReceived = (char*)malloc(strlen(msg) + 1);
strcpy(callbackUtilReceived, msg);
}
}
int test_keywords(Toy_Bucket** bucketHandle) {
//test print
{
//setup
Toy_setPrintCallback(callbackUtil);
const char* source = "print 42;";
Toy_Lexer lexer;
Toy_bindLexer(&lexer, source);
Toy_Parser parser;
Toy_bindParser(&parser, &lexer);
Toy_Ast* ast = Toy_scanParser(bucketHandle, &parser);
Toy_Bytecode bc = Toy_compileBytecode(ast);
Toy_VM vm;
Toy_bindVM(&vm, bc.ptr);
//run
Toy_runVM(&vm);
//check the final state of the stack
if (callbackUtilReceived == NULL ||
strcmp(callbackUtilReceived, "42") != 0)
{
fprintf(stderr, TOY_CC_ERROR "ERROR: Unexpected value '%s' passed to print keyword, source: %s\n" TOY_CC_RESET, callbackUtilReceived != NULL ? callbackUtilReceived : "NULL", source);
//cleanup and return
Toy_resetPrintCallback();
free(callbackUtilReceived);
Toy_freeVM(&vm);
return -1;
}
//teadown
Toy_resetPrintCallback();
free(callbackUtilReceived);
Toy_freeVM(&vm);
}
return 0;
}
int main() {
//run each test set, returning the total errors given
int total = 0, res = 0;
@@ -195,5 +250,15 @@ int main() {
total += res;
}
{
Toy_Bucket* bucket = Toy_allocateBucket(sizeof(Toy_Ast) * 32);
res = test_keywords(&bucket);
Toy_freeBucket(&bucket);
if (res == 0) {
printf(TOY_CC_NOTICE "All good\n" TOY_CC_RESET);
}
total += res;
}
return total;
}