diff --git a/tests/cases/test_parser.c b/tests/cases/test_parser.c index 790ce18..9f95dcc 100644 --- a/tests/cases/test_parser.c +++ b/tests/cases/test_parser.c @@ -456,7 +456,112 @@ int test_binary(Toy_Bucket** bucketHandle) { } int test_compound(Toy_Bucket** bucketHandle) { - //TODO: implement test_compound() + //test collections (do it first, because it's used below) + { + char* source = "1, 2, 3;"; + Toy_Ast* ast = makeAstFromSource(bucketHandle, source); + + //check if it worked + if ( + ast == NULL || + ast->type != TOY_AST_BLOCK || + ast->block.child == NULL || + + ast->block.child->type != TOY_AST_COMPOUND || + ast->block.child->compound.flag != TOY_AST_FLAG_COMPOUND_COLLECTION || + + ast->block.child->compound.left == NULL || + ast->block.child->compound.left->type != TOY_AST_VALUE || + TOY_VALUE_IS_INTEGER(ast->block.child->compound.left->value.value) != true || + TOY_VALUE_AS_INTEGER(ast->block.child->compound.left->value.value) != 1 || + + ast->block.child->compound.right == NULL || + ast->block.child->compound.right->type != TOY_AST_COMPOUND || + ast->block.child->compound.right->compound.flag != TOY_AST_FLAG_COMPOUND_COLLECTION || + + ast->block.child->compound.right->compound.left == NULL || + ast->block.child->compound.right->compound.left->type != TOY_AST_VALUE || + TOY_VALUE_IS_INTEGER(ast->block.child->compound.right->compound.left->value.value) != true || + TOY_VALUE_AS_INTEGER(ast->block.child->compound.right->compound.left->value.value) != 2 || + + ast->block.child->compound.right->compound.right == NULL || + ast->block.child->compound.right->compound.right->type != TOY_AST_VALUE || + TOY_VALUE_IS_INTEGER(ast->block.child->compound.right->compound.right->value.value) != true || + TOY_VALUE_AS_INTEGER(ast->block.child->compound.right->compound.right->value.value) != 3 || + + false) + { + fprintf(stderr, TOY_CC_ERROR "ERROR: failed to run the parser, source: %s\n" TOY_CC_RESET, source); + return -1; + } + } + + //test index + { + char* source = "name[0];"; + Toy_Ast* ast = makeAstFromSource(bucketHandle, source); + + //check if it worked + if ( + ast == NULL || + ast->type != TOY_AST_BLOCK || + ast->block.child == NULL || + + ast->block.child->type != TOY_AST_COMPOUND || + ast->block.child->compound.flag != TOY_AST_FLAG_COMPOUND_INDEX || + + ast->block.child->compound.left == NULL || + ast->block.child->compound.left->type != TOY_AST_VAR_ACCESS || + ast->block.child->compound.left->varAccess.name->type != TOY_STRING_NAME || + strcmp(ast->block.child->compound.left->varAccess.name->as.name.data, "name") != 0 || + + ast->block.child->compound.right->type != TOY_AST_VALUE || + TOY_VALUE_IS_INTEGER(ast->block.child->compound.right->value.value) != true || + TOY_VALUE_AS_INTEGER(ast->block.child->compound.right->value.value) != 0 || + + false) + { + fprintf(stderr, TOY_CC_ERROR "ERROR: failed to run the parser, source: %s\n" TOY_CC_RESET, source); + return -1; + } + } + + //test index, length + { + char* source = "name[0, 1];"; + Toy_Ast* ast = makeAstFromSource(bucketHandle, source); + + //check if it worked + if ( + ast == NULL || + ast->type != TOY_AST_BLOCK || + ast->block.child == NULL || + + ast->block.child->type != TOY_AST_COMPOUND || + ast->block.child->compound.flag != TOY_AST_FLAG_COMPOUND_INDEX || + + ast->block.child->compound.left == NULL || + ast->block.child->compound.left->type != TOY_AST_VAR_ACCESS || + ast->block.child->compound.left->varAccess.name->type != TOY_STRING_NAME || + strcmp(ast->block.child->compound.left->varAccess.name->as.name.data, "name") != 0 || + + ast->block.child->compound.right->type != TOY_AST_COMPOUND || + ast->block.child->compound.right->compound.flag != TOY_AST_FLAG_COMPOUND_COLLECTION || + ast->block.child->compound.right->compound.left->type != TOY_AST_VALUE || + + TOY_VALUE_IS_INTEGER(ast->block.child->compound.right->compound.left->value.value) != true || + TOY_VALUE_AS_INTEGER(ast->block.child->compound.right->compound.left->value.value) != 0 || + + TOY_VALUE_IS_INTEGER(ast->block.child->compound.right->compound.right->value.value) != true || + TOY_VALUE_AS_INTEGER(ast->block.child->compound.right->compound.right->value.value) != 1 || + + false) + { + fprintf(stderr, TOY_CC_ERROR "ERROR: failed to run the parser, source: %s\n" TOY_CC_RESET, source); + return -1; + } + } + return 0; } diff --git a/tests/cases/test_routine.c b/tests/cases/test_routine.c index 4698010..83f7cf4 100644 --- a/tests/cases/test_routine.c +++ b/tests/cases/test_routine.c @@ -719,9 +719,131 @@ int test_routine_binary(Toy_Bucket** bucketHandle) { } int test_routine_keywords(Toy_Bucket** bucketHandle) { - //TODO: implement assert - //TODO: implement if-then - //TODO: implement if-then-else + //assert + { + //setup + const char* source = "assert true;"; + 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] != 36 || //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_BOOLEAN || + *((bool*)(buffer + 26)) != true || //bools are packed + *((unsigned char*)(buffer + 27)) != 0 || + + *((unsigned char*)(buffer + 28)) != TOY_OPCODE_ASSERT || + *((unsigned char*)(buffer + 29)) != 1 || //one parameter + *((unsigned char*)(buffer + 30)) != 0 || + *((unsigned char*)(buffer + 31)) != 0 || + + *((unsigned char*)(buffer + 32)) != TOY_OPCODE_RETURN || + *((unsigned char*)(buffer + 33)) != 0 || + *((unsigned char*)(buffer + 34)) != 0 || + *((unsigned char*)(buffer + 35)) != 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); + } + + //assert (with message) + { + //setup + const char* source = "assert true, false;"; + 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_BOOLEAN || + *((bool*)(buffer + 26)) != true || //bools are packed + *((unsigned char*)(buffer + 27)) != 0 || + + *((unsigned char*)(buffer + 28)) != TOY_OPCODE_READ || + *((unsigned char*)(buffer + 29)) != TOY_VALUE_BOOLEAN || + *((bool*)(buffer + 30)) != false || //bools are packed + *((unsigned char*)(buffer + 31)) != 0 || + + *((unsigned char*)(buffer + 32)) != TOY_OPCODE_ASSERT || + *((unsigned char*)(buffer + 33)) != 2 || //two parameters + *((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); + } + + //TODO: implement test if-then + //TODO: implement test if-then-else //print {