From 0947430c29b30ccc53b038063ad5cd7db8f1c891 Mon Sep 17 00:00:00 2001 From: Kayne Ruse Date: Tue, 26 Nov 2024 11:30:28 +1100 Subject: [PATCH] Finished if-then-else tests, finally. --- tests/cases/test_routine.c | 118 ++++++++++++++++++++++- tests/cases/test_vm.c | 189 ++++++++++++++++++++++++++++++++++++- 2 files changed, 303 insertions(+), 4 deletions(-) diff --git a/tests/cases/test_routine.c b/tests/cases/test_routine.c index 354fa1e..9437002 100644 --- a/tests/cases/test_routine.c +++ b/tests/cases/test_routine.c @@ -842,9 +842,6 @@ int test_routine_keywords(Toy_Bucket** bucketHandle) { free(buffer); } - //TODO: implement test if-then - //TODO: implement test if-then-else - //if-then { //setup @@ -936,6 +933,121 @@ int test_routine_keywords(Toy_Bucket** bucketHandle) { free(buffer); } + //if-then-else + { + //setup + const char* source = "if (true) print \"hello world\"; else print \"goodbye world\";"; + 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] != 116 || //total size + (ptr++)[0] != 0 || //param count + (ptr++)[0] != 8 || //jump count + (ptr++)[0] != 28 || //data count + (ptr++)[0] != 0 || //subs count + + (ptr++)[0] != 32 || //code addr + (ptr++)[0] != 80 || //jump addr + (ptr++)[0] != 88 || //data addr + + //header size: 32 + + false) + { + 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 (//cond + *((unsigned char*)(buffer + 32)) != TOY_OPCODE_READ || + *((unsigned char*)(buffer + 33)) != TOY_VALUE_BOOLEAN || + *((bool*)(buffer + 34)) != true || //bools are packed + *((unsigned char*)(buffer + 35)) != 0 || + + *((unsigned char*)(buffer + 36)) != TOY_OPCODE_JUMP || + *((unsigned char*)(buffer + 37)) != TOY_OP_PARAM_JUMP_RELATIVE || + *((unsigned char*)(buffer + 38)) != TOY_OP_PARAM_JUMP_IF_FALSE || + *((unsigned char*)(buffer + 39)) != 0 || + + *((int*)(buffer + 40)) != 20 || //param: jump distance (relative) + + //then branch + *((unsigned char*)(buffer + 44)) != TOY_OPCODE_READ || + *((unsigned char*)(buffer + 45)) != TOY_VALUE_STRING || + *((unsigned char*)(buffer + 46)) != TOY_STRING_LEAF || + *((unsigned char*)(buffer + 47)) != 0 || + + *((int*)(buffer + 48)) != 0 || //first indirection + + *((unsigned char*)(buffer + 52)) != TOY_OPCODE_PRINT || + *((unsigned char*)(buffer + 53)) != 0 || + *((unsigned char*)(buffer + 54)) != 0 || + *((unsigned char*)(buffer + 55)) != 0 || + + //jump to the end + *((unsigned char*)(buffer + 56)) != TOY_OPCODE_JUMP || + *((unsigned char*)(buffer + 57)) != TOY_OP_PARAM_JUMP_RELATIVE || + *((unsigned char*)(buffer + 58)) != TOY_OP_PARAM_JUMP_ALWAYS || + *((unsigned char*)(buffer + 59)) != 0 || + + *((int*)(buffer + 60)) != 12 || //param: jump distance (relative) + + //else branch + *((unsigned char*)(buffer + 64)) != TOY_OPCODE_READ || + *((unsigned char*)(buffer + 65)) != TOY_VALUE_STRING || + *((unsigned char*)(buffer + 66)) != TOY_STRING_LEAF || + *((unsigned char*)(buffer + 67)) != 0 || + + *((int*)(buffer + 68)) != 4 || //second indirection + + *((unsigned char*)(buffer + 72)) != TOY_OPCODE_PRINT || + *((unsigned char*)(buffer + 73)) != 0 || + *((unsigned char*)(buffer + 74)) != 0 || + *((unsigned char*)(buffer + 75)) != 0 || + + //EOF + *((unsigned char*)(buffer + 76)) != TOY_OPCODE_RETURN || + *((unsigned char*)(buffer + 77)) != 0 || + *((unsigned char*)(buffer + 78)) != 0 || + *((unsigned char*)(buffer + 79)) != 0 || + + //jump region + *((int*)(buffer + 80)) != 0 || + *((int*)(buffer + 84)) != 12 || + + //data region (strings begin at 4-byte words) + strcmp((char*)(buffer + 88), "hello world") != 0 || + + strcmp((char*)(buffer + 100), "goodbye world") != 0 || + + false) + { + 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); + } + //print { //setup diff --git a/tests/cases/test_vm.c b/tests/cases/test_vm.c index 2620c86..173629d 100644 --- a/tests/cases/test_vm.c +++ b/tests/cases/test_vm.c @@ -452,6 +452,185 @@ int test_keyword_print(Toy_Bucket** bucketHandle) { return 0; } +int test_keyword_ifThenElse(Toy_Bucket** bucketHandle) { + //test if-then (truthy) + { + //setup + Toy_setPrintCallback(callbackUtil); + const char* source = "if (true) print \"hello world\";"; + + 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_initVM(&vm); + Toy_bindVM(&vm, &bc); + + //run + Toy_runVM(&vm); + + //check + if (callbackUtilReceived == NULL || + strcmp(callbackUtilReceived, "hello world") != 0) + { + fprintf(stderr, TOY_CC_ERROR "ERROR: Unexpected value '%s' passed to print in if keyword, source: %s\n" TOY_CC_RESET, callbackUtilReceived != NULL ? callbackUtilReceived : "NULL", source); + + //cleanup and return + Toy_resetPrintCallback(); + free(callbackUtilReceived); + Toy_freeVM(&vm); + Toy_freeBytecode(bc); + return -1; + } + + //teadown + Toy_resetPrintCallback(); + free(callbackUtilReceived); + callbackUtilReceived = NULL; + Toy_freeVM(&vm); + Toy_freeBytecode(bc); + } + + //test if-then (falsy) + { + //setup + Toy_setPrintCallback(callbackUtil); + const char* source = "if (false) print \"hello world\";"; + + 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_initVM(&vm); + Toy_bindVM(&vm, &bc); + + //run + Toy_runVM(&vm); + + //check + if (callbackUtilReceived != NULL) + { + fprintf(stderr, TOY_CC_ERROR "ERROR: Unexpected value '%s' passed to print in if keyword, source: %s\n" TOY_CC_RESET, callbackUtilReceived != NULL ? callbackUtilReceived : "NULL", source); + + //cleanup and return + Toy_resetPrintCallback(); + free(callbackUtilReceived); + Toy_freeVM(&vm); + Toy_freeBytecode(bc); + return -1; + } + + //teadown + Toy_resetPrintCallback(); + free(callbackUtilReceived); + callbackUtilReceived = NULL; + Toy_freeVM(&vm); + Toy_freeBytecode(bc); + } + + //test if-then-else (truthy) + { + //setup + Toy_setPrintCallback(callbackUtil); + const char* source = "if (true) print \"hello world\"; else print \"failed\";"; + + 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_initVM(&vm); + Toy_bindVM(&vm, &bc); + + //run + Toy_runVM(&vm); + + //check + if (callbackUtilReceived == NULL || + strcmp(callbackUtilReceived, "hello world") != 0) + { + fprintf(stderr, TOY_CC_ERROR "ERROR: Unexpected value '%s' passed to print in if keyword, source: %s\n" TOY_CC_RESET, callbackUtilReceived != NULL ? callbackUtilReceived : "NULL", source); + + //cleanup and return + Toy_resetPrintCallback(); + free(callbackUtilReceived); + Toy_freeVM(&vm); + Toy_freeBytecode(bc); + return -1; + } + + //teadown + Toy_resetPrintCallback(); + free(callbackUtilReceived); + callbackUtilReceived = NULL; + Toy_freeVM(&vm); + Toy_freeBytecode(bc); + } + + //test if-then-else (falsy) + { + //setup + Toy_setPrintCallback(callbackUtil); + const char* source = "if (false) print \"hello world\"; else print \"failed\";"; + + 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_initVM(&vm); + Toy_bindVM(&vm, &bc); + + //run + Toy_runVM(&vm); + + //check + if (callbackUtilReceived == NULL || + strcmp(callbackUtilReceived, "failed") != 0) + { + fprintf(stderr, TOY_CC_ERROR "ERROR: Unexpected value '%s' passed to print in if keyword, source: %s\n" TOY_CC_RESET, callbackUtilReceived != NULL ? callbackUtilReceived : "NULL", source); + + //cleanup and return + Toy_resetPrintCallback(); + free(callbackUtilReceived); + Toy_freeVM(&vm); + Toy_freeBytecode(bc); + return -1; + } + + //teadown + Toy_resetPrintCallback(); + free(callbackUtilReceived); + callbackUtilReceived = NULL; + Toy_freeVM(&vm); + Toy_freeBytecode(bc); + } + + return 0; +} + int test_scope(Toy_Bucket** bucketHandle) { //test declaration with initial value { @@ -681,7 +860,15 @@ int main() { total += res; } - //TODO: test_ifThenElse() + { + Toy_Bucket* bucket = Toy_allocateBucket(TOY_BUCKET_IDEAL); + res = test_keyword_ifThenElse(&bucket); + Toy_freeBucket(&bucket); + if (res == 0) { + printf(TOY_CC_NOTICE "All good\n" TOY_CC_RESET); + } + total += res; + } { Toy_Bucket* bucket = Toy_allocateBucket(TOY_BUCKET_IDEAL);