diff --git a/repl/main.c b/repl/main.c index a44eeda..cffd394 100644 --- a/repl/main.c +++ b/repl/main.c @@ -262,5 +262,3 @@ int main(int argc, const char* argv[]) { return 0; } - -//TODO: simple and consistent way to print an AST and Toy_Value diff --git a/source/makefile b/source/makefile index e008fed..949fdf3 100644 --- a/source/makefile +++ b/source/makefile @@ -16,7 +16,6 @@ SRC_SOURCEFILES=$(wildcard $(SRC_SOURCEDIR)/*.c) SRC_OBJFILES=$(addprefix $(SRC_OBJDIR)/,$(notdir $(SRC_SOURCEFILES:.c=.o))) SRC_TARGETNAME=Toy -#TODO: fix windows & macos #SRC_LIBLINE is a fancy way of making the linker work correctly ifeq ($(shell uname),Linux) SRC_TARGETEXT=.so diff --git a/source/toy_ast.c b/source/toy_ast.c index 266cf60..ce089fc 100644 --- a/source/toy_ast.c +++ b/source/toy_ast.c @@ -42,7 +42,6 @@ void Toy_private_emitAstValue(Toy_Bucket** bucket, Toy_Ast** handle, Toy_Value v (*handle) = tmp; } -//TODO: flag range checks void Toy_private_emitAstUnary(Toy_Bucket** bucket, Toy_Ast** handle, Toy_AstFlag flag) { Toy_Ast* tmp = (Toy_Ast*)Toy_partitionBucket(bucket, sizeof(Toy_Ast)); diff --git a/source/toy_routine.c b/source/toy_routine.c index b73f2e1..f876cbb 100644 --- a/source/toy_routine.c +++ b/source/toy_routine.c @@ -167,12 +167,7 @@ static void writeInstructionBinary(Toy_Routine** rt, Toy_AstBinary ast) { } else if (ast.flag == TOY_AST_FLAG_COMPARE_NOT) { EMIT_BYTE(rt, TOY_OPCODE_COMPARE_EQUAL); - EMIT_BYTE(rt, 0); - EMIT_BYTE(rt, 0); - EMIT_BYTE(rt, 0); - - EMIT_BYTE(rt, TOY_OPCODE_NEGATE); //TODO: squeeze these into one word - EMIT_BYTE(rt, 0); + EMIT_BYTE(rt, TOY_OPCODE_NEGATE); //squeezed into one word EMIT_BYTE(rt, 0); EMIT_BYTE(rt, 0); diff --git a/source/toy_string.c b/source/toy_string.c index c62406b..19f5d2f 100644 --- a/source/toy_string.c +++ b/source/toy_string.c @@ -69,7 +69,7 @@ Toy_String* Toy_deepCopyString(Toy_Bucket** bucket, Toy_String* str) { } Toy_String* ret = (Toy_String*)Toy_partitionBucket(bucket, sizeof(Toy_String) + str->length + 1); //TODO: compensate for partitioning more space than bucket capacity - //TODO + // ret->type = TOY_STRING_LEAF; ret->length = str->length; ret->refCount = 1; diff --git a/source/toy_vm.c b/source/toy_vm.c index 60384c3..10c5403 100644 --- a/source/toy_vm.c +++ b/source/toy_vm.c @@ -165,7 +165,16 @@ static void processComparison(Toy_VM* vm, Toy_OpcodeType opcode) { //most things can be equal, so handle it separately if (opcode == TOY_OPCODE_COMPARE_EQUAL) { - Toy_pushStack(&vm->stack, TOY_VALUE_TO_BOOLEAN(TOY_VALUE_IS_EQUAL(left, right)) ); + bool equal = TOY_VALUE_IS_EQUAL(left, right); + + //equality has an optional "negate" opcode within it's word + if (READ_BYTE(vm) != TOY_OPCODE_NEGATE) { + Toy_pushStack(&vm->stack, TOY_VALUE_TO_BOOLEAN(equal) ); + } + else { + Toy_pushStack(&vm->stack, TOY_VALUE_TO_BOOLEAN(!equal) ); + } + return; } @@ -254,7 +263,7 @@ static void process(Toy_VM* vm) { case TOY_OPCODE_AND: case TOY_OPCODE_OR: case TOY_OPCODE_TRUTHY: - case TOY_OPCODE_NEGATE: //TODO: squeeze into != + case TOY_OPCODE_NEGATE: processLogical(vm, opcode); break; diff --git a/tests/cases/test_routine.c b/tests/cases/test_routine.c index 76fca12..7b8093c 100644 --- a/tests/cases/test_routine.c +++ b/tests/cases/test_routine.c @@ -322,7 +322,7 @@ int test_routine_header_and_values(Toy_Bucket** bucket) { } // int test_routine_unary(Toy_Bucket** bucket) { -// //TODO: Nothing produces a unary instruction yet +// //Nothing produces a unary instruction yet // } int test_routine_binary(Toy_Bucket** bucket) { @@ -476,7 +476,7 @@ int test_routine_binary(Toy_Bucket** bucket) { //check header int* ptr = (int*)buffer; - if ((ptr++)[0] != 52 || //total size + if ((ptr++)[0] != 48 || //total size (ptr++)[0] != 0 || //param count (ptr++)[0] != 0 || //jump count (ptr++)[0] != 0 || //data count @@ -503,19 +503,14 @@ int test_routine_binary(Toy_Bucket** bucket) { *(int*)(buffer + 36) != 5 || *((unsigned char*)(buffer + 40)) != TOY_OPCODE_COMPARE_EQUAL || - *((unsigned char*)(buffer + 41)) != 0 || + *((unsigned char*)(buffer + 41)) != TOY_OPCODE_NEGATE || *((unsigned char*)(buffer + 42)) != 0 || *((unsigned char*)(buffer + 43)) != 0 || - *((unsigned char*)(buffer + 44)) != TOY_OPCODE_NEGATE || + *((unsigned char*)(buffer + 44)) != TOY_OPCODE_RETURN || *((unsigned char*)(buffer + 45)) != 0 || *((unsigned char*)(buffer + 46)) != 0 || - *((unsigned char*)(buffer + 47)) != 0 || - - *((unsigned char*)(buffer + 48)) != TOY_OPCODE_RETURN || - *((unsigned char*)(buffer + 49)) != 0 || - *((unsigned char*)(buffer + 50)) != 0 || - *((unsigned char*)(buffer + 51)) != 0 + *((unsigned char*)(buffer + 47)) != 0 ) { fprintf(stderr, TOY_CC_ERROR "ERROR: failed to produce the expected routine code, source: %s\n" TOY_CC_RESET, source); diff --git a/tests/cases/test_vm.c b/tests/cases/test_vm.c index a8e7893..5e08456 100644 --- a/tests/cases/test_vm.c +++ b/tests/cases/test_vm.c @@ -73,9 +73,8 @@ int test_setup_and_teardown(Toy_Bucket** bucket) { return 0; } -//tests int test_simple_execution(Toy_Bucket** bucket) { - //basic init & quit + //test execution { //generate bytecode for testing const char* source = "(1 + 2) * (3 + 4);"; @@ -104,7 +103,51 @@ int test_simple_execution(Toy_Bucket** bucket) { TOY_VALUE_AS_INTEGER( Toy_peekStack(&vm.stack) ) != 21 ) { - fprintf(stderr, TOY_CC_ERROR "ERROR: failed run the Toy_VM, source: %s\n" TOY_CC_RESET, source); + fprintf(stderr, TOY_CC_ERROR "ERROR: Unexpected result in 'Toy_VM', source: %s\n" TOY_CC_RESET, source); + + //cleanup and return + Toy_freeVM(&vm); + return -1; + } + + //teadown + Toy_freeVM(&vm); + } + + return 0; +} + +int test_opcode_not_equal(Toy_Bucket** bucket) { + //testing a specific opcode; '!=' is compressed into a single word, so lets check it works + { + //generate bytecode for testing + const char* source = "3 != 5;"; + + Toy_Lexer lexer; + Toy_bindLexer(&lexer, source); + + Toy_Parser parser; + Toy_bindParser(&parser, &lexer); + + Toy_Ast* ast = Toy_scanParser(bucket, &parser); + + Toy_Bytecode bc = Toy_compileBytecode(ast); + + //run the setup + Toy_VM vm; + Toy_bindVM(&vm, bc.ptr, bc.capacity); + + //run + Toy_runVM(&vm); + + //check the final state of the stack + if (vm.stack == NULL || + vm.stack->count != 1 || + TOY_VALUE_IS_BOOLEAN( Toy_peekStack(&vm.stack) ) != true || + TOY_VALUE_AS_BOOLEAN( Toy_peekStack(&vm.stack) ) != true + ) + { + fprintf(stderr, TOY_CC_ERROR "ERROR: Unexpected result in 'Toy_VM', source: %s\n" TOY_CC_RESET, source); //cleanup and return Toy_freeVM(&vm); @@ -142,5 +185,15 @@ int main() { total += res; } + { + Toy_Bucket* bucket = Toy_allocateBucket(sizeof(Toy_Ast) * 32); + res = test_opcode_not_equal(&bucket); + Toy_freeBucket(&bucket); + if (res == 0) { + printf(TOY_CC_NOTICE "All good\n" TOY_CC_RESET); + } + total += res; + } + return total; }