mirror of
https://github.com/krgamestudios/Toy.git
synced 2026-04-15 14:54:07 +10:00
Implemented tests for Toy_Parser
The parser now correctly produces a workable AST. I think I'll skip over the optimizer, and begin on the compiler next session. The optimizer will act directly on the AST, but it isn't totally necessary. Other tools can also operate on the AST, such as for debugging - I'll have to ask what kinds are out there.
This commit is contained in:
@@ -29,13 +29,9 @@ int test_sizeof_ast_32bit() {
|
||||
return -err;
|
||||
}
|
||||
|
||||
int test_type_emission() {
|
||||
int test_type_emission(Toy_Bucket* bucket) {
|
||||
//emit value
|
||||
{
|
||||
//bucket setup
|
||||
Toy_Bucket* bucket = NULL;
|
||||
TOY_BUCKET_INIT(Toy_Ast, bucket, 8);
|
||||
|
||||
//emit to an AST
|
||||
Toy_Ast* ast = NULL;
|
||||
Toy_private_emitAstValue(&bucket, &ast, TOY_VALUE_TO_INTEGER(42));
|
||||
@@ -49,17 +45,10 @@ int test_type_emission() {
|
||||
fprintf(stderr, TOY_CC_ERROR "ERROR: failed to emit a value as 'Toy_Ast', state unknown\n" TOY_CC_RESET);
|
||||
return -1;
|
||||
}
|
||||
|
||||
//bucket free
|
||||
TOY_BUCKET_FREE(bucket);
|
||||
}
|
||||
|
||||
//emit unary
|
||||
{
|
||||
//bucket setup
|
||||
Toy_Bucket* bucket = NULL;
|
||||
TOY_BUCKET_INIT(Toy_Ast, bucket, 8);
|
||||
|
||||
//build the AST
|
||||
Toy_Ast* ast = NULL;
|
||||
Toy_private_emitAstValue(&bucket, &ast, TOY_VALUE_TO_INTEGER(42));
|
||||
@@ -76,17 +65,10 @@ int test_type_emission() {
|
||||
fprintf(stderr, TOY_CC_ERROR "ERROR: failed to emit a unary as 'Toy_Ast', state unknown\n" TOY_CC_RESET);
|
||||
return -1;
|
||||
}
|
||||
|
||||
//bucket free
|
||||
TOY_BUCKET_FREE(bucket);
|
||||
}
|
||||
|
||||
//emit binary
|
||||
{
|
||||
//bucket setup
|
||||
Toy_Bucket* bucket = NULL;
|
||||
TOY_BUCKET_INIT(Toy_Ast, bucket, 8);
|
||||
|
||||
//build the AST
|
||||
Toy_Ast* ast = NULL;
|
||||
Toy_Ast* right = NULL;
|
||||
@@ -107,17 +89,10 @@ int test_type_emission() {
|
||||
fprintf(stderr, TOY_CC_ERROR "ERROR: failed to emit a binary as 'Toy_Ast', state unknown\n" TOY_CC_RESET);
|
||||
return -1;
|
||||
}
|
||||
|
||||
//bucket free
|
||||
TOY_BUCKET_FREE(bucket);
|
||||
}
|
||||
|
||||
//emit group
|
||||
{
|
||||
//bucket setup
|
||||
Toy_Bucket* bucket = NULL;
|
||||
TOY_BUCKET_INIT(Toy_Ast, bucket, 8);
|
||||
|
||||
//build the AST
|
||||
Toy_Ast* ast = NULL;
|
||||
Toy_Ast* right = NULL;
|
||||
@@ -141,17 +116,10 @@ int test_type_emission() {
|
||||
fprintf(stderr, TOY_CC_ERROR "ERROR: failed to emit a group as 'Toy_Ast', state unknown\n" TOY_CC_RESET);
|
||||
return -1;
|
||||
}
|
||||
|
||||
//bucket free
|
||||
TOY_BUCKET_FREE(bucket);
|
||||
}
|
||||
|
||||
//emit and append blocks of code
|
||||
{
|
||||
//bucket setup
|
||||
Toy_Bucket* bucket = NULL;
|
||||
TOY_BUCKET_INIT(Toy_Ast, bucket, 8);
|
||||
|
||||
//initialize the root block
|
||||
Toy_Ast* block = NULL;
|
||||
Toy_private_initAstBlock(&bucket, &block);
|
||||
@@ -191,23 +159,6 @@ int test_type_emission() {
|
||||
|
||||
iter = iter->block.next;
|
||||
}
|
||||
|
||||
//additional check: count the bucket's total allocations
|
||||
Toy_Bucket* biter = bucket;
|
||||
int total = 0;
|
||||
|
||||
while(biter != NULL) {
|
||||
total += biter->count;
|
||||
biter = biter->next;
|
||||
}
|
||||
|
||||
if (total != 25 * (int)sizeof(Toy_Ast)) {
|
||||
fprintf(stderr, TOY_CC_ERROR "ERROR: unexpected number of allocations found in a bucket, expected %d, found %d\n" TOY_CC_RESET, 25 * (int)sizeof(Toy_Ast), total);
|
||||
return -1;
|
||||
}
|
||||
|
||||
//bucket free
|
||||
TOY_BUCKET_FREE(bucket);
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -228,11 +179,15 @@ int main() {
|
||||
fprintf(stderr, TOY_CC_WARN "WARNING: Skipping test_sizeof_ast_32bit(); Can't determine the 'bitness' of this platform\n" TOY_CC_RESET);
|
||||
#endif
|
||||
|
||||
res = test_type_emission();
|
||||
total += res;
|
||||
|
||||
if (res == 0) {
|
||||
printf(TOY_CC_NOTICE "All good\n" TOY_CC_RESET);
|
||||
{
|
||||
Toy_Bucket* bucket = NULL;
|
||||
TOY_BUCKET_INIT(Toy_Ast, bucket, 32);
|
||||
res = test_type_emission(bucket);
|
||||
TOY_BUCKET_FREE(bucket);
|
||||
if (res == 0) {
|
||||
printf(TOY_CC_NOTICE "All good\n" TOY_CC_RESET);
|
||||
}
|
||||
total += res;
|
||||
}
|
||||
|
||||
return total;
|
||||
|
||||
@@ -3,7 +3,630 @@
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
int main() {
|
||||
fprintf(stderr, TOY_CC_WARN "WARNING: Test suite for Toy_Parser is not yet implemented\n" TOY_CC_RESET);
|
||||
//utils
|
||||
Toy_Ast* makeAstFromSource(Toy_Bucket** bucket, const char* source) {
|
||||
Toy_Lexer lexer;
|
||||
Toy_bindLexer(&lexer, source);
|
||||
|
||||
Toy_Parser parser;
|
||||
Toy_bindParser(&parser, &lexer);
|
||||
|
||||
return Toy_scanParser(bucket, &parser);
|
||||
}
|
||||
|
||||
//tests
|
||||
int test_simple_empty_parsers(Toy_Bucket* bucket) {
|
||||
//simple parser setup and cleanup
|
||||
{
|
||||
//raw source code and lexer
|
||||
const char* source = "";
|
||||
Toy_Lexer lexer;
|
||||
Toy_bindLexer(&lexer, source);
|
||||
|
||||
//parser
|
||||
Toy_Parser parser;
|
||||
Toy_bindParser(&parser, &lexer);
|
||||
|
||||
Toy_Ast* ast = Toy_scanParser(&bucket, &parser);
|
||||
|
||||
//check if it worked
|
||||
if (
|
||||
ast == NULL ||
|
||||
ast->type != TOY_AST_END)
|
||||
{
|
||||
fprintf(stderr, TOY_CC_ERROR "ERROR: failed to run the parser with empty source\n" TOY_CC_RESET);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
//repeat above, but with one semicolon
|
||||
{
|
||||
//raw source code and lexer
|
||||
const char* source = ";";
|
||||
Toy_Lexer lexer;
|
||||
Toy_bindLexer(&lexer, source);
|
||||
|
||||
//parser
|
||||
Toy_Parser parser;
|
||||
Toy_bindParser(&parser, &lexer);
|
||||
|
||||
Toy_Ast* ast = Toy_scanParser(&bucket, &parser);
|
||||
|
||||
//check if it worked
|
||||
if (
|
||||
ast == NULL ||
|
||||
ast->type != TOY_AST_BLOCK ||
|
||||
ast->block.child == NULL ||
|
||||
ast->block.child->type != TOY_AST_PASS)
|
||||
{
|
||||
fprintf(stderr, TOY_CC_ERROR "ERROR: failed to run the parser with one semicolon\n" TOY_CC_RESET);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
//repeat above, but with multiple semicolons
|
||||
{
|
||||
//raw source code and lexer
|
||||
const char* source = ";;;;;";
|
||||
Toy_Lexer lexer;
|
||||
Toy_bindLexer(&lexer, source);
|
||||
|
||||
//parser
|
||||
Toy_Parser parser;
|
||||
Toy_bindParser(&parser, &lexer);
|
||||
|
||||
Toy_Ast* ast = Toy_scanParser(&bucket, &parser);
|
||||
|
||||
Toy_Ast* iter = ast;
|
||||
|
||||
while(iter != NULL) {
|
||||
//check each link and child
|
||||
if (
|
||||
iter == NULL ||
|
||||
iter->type != TOY_AST_BLOCK ||
|
||||
iter->block.child == NULL ||
|
||||
iter->block.child->type != TOY_AST_PASS)
|
||||
{
|
||||
fprintf(stderr, TOY_CC_ERROR "ERROR: failed to run the parser with multiple semicolons\n" TOY_CC_RESET);
|
||||
return -1;
|
||||
}
|
||||
|
||||
iter = iter->block.next;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int test_values(Toy_Bucket* bucket) {
|
||||
//test boolean true
|
||||
{
|
||||
Toy_Ast* ast = makeAstFromSource(&bucket, "true;");
|
||||
|
||||
//check if it worked
|
||||
if (
|
||||
ast == NULL ||
|
||||
ast->type != TOY_AST_BLOCK ||
|
||||
ast->block.child == NULL ||
|
||||
ast->block.child->type != TOY_AST_VALUE ||
|
||||
TOY_VALUE_IS_BOOLEAN(ast->block.child->value.value) == false ||
|
||||
TOY_VALUE_AS_BOOLEAN(ast->block.child->value.value) != true)
|
||||
{
|
||||
fprintf(stderr, TOY_CC_ERROR "ERROR: failed to run the parser with boolean value true\n" TOY_CC_RESET);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
//test boolean false (just to be safe)
|
||||
{
|
||||
Toy_Ast* ast = makeAstFromSource(&bucket, "false;");
|
||||
|
||||
//check if it worked
|
||||
if (
|
||||
ast == NULL ||
|
||||
ast->type != TOY_AST_BLOCK ||
|
||||
ast->block.child == NULL ||
|
||||
ast->block.child->type != TOY_AST_VALUE ||
|
||||
TOY_VALUE_IS_BOOLEAN(ast->block.child->value.value) == false ||
|
||||
TOY_VALUE_AS_BOOLEAN(ast->block.child->value.value) != false)
|
||||
{
|
||||
fprintf(stderr, TOY_CC_ERROR "ERROR: failed to run the parser with boolean value false\n" TOY_CC_RESET);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
//test integer
|
||||
{
|
||||
Toy_Ast* ast = makeAstFromSource(&bucket, "42;");
|
||||
|
||||
//check if it worked
|
||||
if (
|
||||
ast == NULL ||
|
||||
ast->type != TOY_AST_BLOCK ||
|
||||
ast->block.child == NULL ||
|
||||
ast->block.child->type != TOY_AST_VALUE ||
|
||||
TOY_VALUE_IS_INTEGER(ast->block.child->value.value) == false ||
|
||||
TOY_VALUE_AS_INTEGER(ast->block.child->value.value) != 42)
|
||||
{
|
||||
fprintf(stderr, TOY_CC_ERROR "ERROR: failed to run the parser with integer value 42\n" TOY_CC_RESET);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
//test float
|
||||
{
|
||||
Toy_Ast* ast = makeAstFromSource(&bucket, "3.1415;");
|
||||
|
||||
//check if it worked
|
||||
if (
|
||||
ast == NULL ||
|
||||
ast->type != TOY_AST_BLOCK ||
|
||||
ast->block.child == NULL ||
|
||||
ast->block.child->type != TOY_AST_VALUE ||
|
||||
TOY_VALUE_IS_FLOAT(ast->block.child->value.value) == false ||
|
||||
TOY_VALUE_AS_FLOAT(ast->block.child->value.value) != 3.1415f)
|
||||
{
|
||||
fprintf(stderr, TOY_CC_ERROR "ERROR: failed to run the parser with float value 3.1415\n" TOY_CC_RESET);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
//test integer with separators
|
||||
{
|
||||
Toy_Ast* ast = makeAstFromSource(&bucket, "1_234_567_890;");
|
||||
|
||||
//check if it worked
|
||||
if (
|
||||
ast == NULL ||
|
||||
ast->type != TOY_AST_BLOCK ||
|
||||
ast->block.child == NULL ||
|
||||
ast->block.child->type != TOY_AST_VALUE ||
|
||||
TOY_VALUE_IS_INTEGER(ast->block.child->value.value) == false ||
|
||||
TOY_VALUE_AS_INTEGER(ast->block.child->value.value) != 1234567890)
|
||||
{
|
||||
fprintf(stderr, TOY_CC_ERROR "ERROR: failed to run the parser with integer value 42 with separators\n" TOY_CC_RESET);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
//test float with separators
|
||||
{
|
||||
Toy_Ast* ast = makeAstFromSource(&bucket, "3.141_592_65;");
|
||||
|
||||
//check if it worked
|
||||
if (
|
||||
ast == NULL ||
|
||||
ast->type != TOY_AST_BLOCK ||
|
||||
ast->block.child == NULL ||
|
||||
ast->block.child->type != TOY_AST_VALUE ||
|
||||
TOY_VALUE_IS_FLOAT(ast->block.child->value.value) == false ||
|
||||
TOY_VALUE_AS_FLOAT(ast->block.child->value.value) != 3.14159265f)
|
||||
{
|
||||
fprintf(stderr, TOY_CC_ERROR "ERROR: failed to run the parser with float value 3.1415 with separators\n" TOY_CC_RESET);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int test_unary(Toy_Bucket* bucket) {
|
||||
//test unary boolean negation (!true)
|
||||
{
|
||||
Toy_Ast* ast = makeAstFromSource(&bucket, "!true;");
|
||||
|
||||
//check if it worked
|
||||
if (
|
||||
ast == NULL ||
|
||||
ast->type != TOY_AST_BLOCK ||
|
||||
ast->block.child == NULL ||
|
||||
ast->block.child->type != TOY_AST_VALUE ||
|
||||
TOY_VALUE_IS_BOOLEAN(ast->block.child->value.value) == false ||
|
||||
TOY_VALUE_AS_BOOLEAN(ast->block.child->value.value) != false)
|
||||
{
|
||||
fprintf(stderr, TOY_CC_ERROR "ERROR: failed to run the parser with boolean value !true (unary negation)\n" TOY_CC_RESET);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
//test unary boolean negation (!false, just to be safe)
|
||||
{
|
||||
Toy_Ast* ast = makeAstFromSource(&bucket, "!false;");
|
||||
|
||||
//check if it worked
|
||||
if (
|
||||
ast == NULL ||
|
||||
ast->type != TOY_AST_BLOCK ||
|
||||
ast->block.child == NULL ||
|
||||
ast->block.child->type != TOY_AST_VALUE ||
|
||||
TOY_VALUE_IS_BOOLEAN(ast->block.child->value.value) == false ||
|
||||
TOY_VALUE_AS_BOOLEAN(ast->block.child->value.value) != true)
|
||||
{
|
||||
fprintf(stderr, TOY_CC_ERROR "ERROR: failed to run the parser with boolean value !false (unary negation)\n" TOY_CC_RESET);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
//test unary integer negation
|
||||
{
|
||||
Toy_Ast* ast = makeAstFromSource(&bucket, "-42;");
|
||||
|
||||
//check if it worked
|
||||
if (
|
||||
ast == NULL ||
|
||||
ast->type != TOY_AST_BLOCK ||
|
||||
ast->block.child == NULL ||
|
||||
ast->block.child->type != TOY_AST_VALUE ||
|
||||
TOY_VALUE_IS_INTEGER(ast->block.child->value.value) == false ||
|
||||
TOY_VALUE_AS_INTEGER(ast->block.child->value.value) != -42)
|
||||
{
|
||||
fprintf(stderr, TOY_CC_ERROR "ERROR: failed to run the parser with integer value -42 (unary negation)\n" TOY_CC_RESET);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
//test unary float negation
|
||||
{
|
||||
Toy_Ast* ast = makeAstFromSource(&bucket, "-3.1415;");
|
||||
|
||||
//check if it worked
|
||||
if (
|
||||
ast == NULL ||
|
||||
ast->type != TOY_AST_BLOCK ||
|
||||
ast->block.child == NULL ||
|
||||
ast->block.child->type != TOY_AST_VALUE ||
|
||||
TOY_VALUE_IS_FLOAT(ast->block.child->value.value) == false ||
|
||||
TOY_VALUE_AS_FLOAT(ast->block.child->value.value) != -3.1415f)
|
||||
{
|
||||
fprintf(stderr, TOY_CC_ERROR "ERROR: failed to run the parser with float value -3.1415 (unary negation)\n" TOY_CC_RESET);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
//ensure unary negation doesn't affect other things (such as group)
|
||||
{
|
||||
Toy_Ast* ast = makeAstFromSource(&bucket, "-(42);");
|
||||
|
||||
//check if it worked
|
||||
if (
|
||||
ast == NULL ||
|
||||
ast->type != TOY_AST_BLOCK ||
|
||||
ast->block.child == NULL ||
|
||||
ast->block.child->type != TOY_AST_UNARY ||
|
||||
ast->block.child->unary.child == NULL ||
|
||||
ast->block.child->unary.child->type != TOY_AST_GROUP ||
|
||||
ast->block.child->unary.child->group.child == NULL ||
|
||||
ast->block.child->unary.child->group.child->type != TOY_AST_VALUE ||
|
||||
TOY_VALUE_IS_INTEGER(ast->block.child->unary.child->group.child->value.value) == false ||
|
||||
TOY_VALUE_AS_INTEGER(ast->block.child->unary.child->group.child->value.value) != 42)
|
||||
{
|
||||
fprintf(stderr, TOY_CC_ERROR "ERROR: unexpected successful unary negation in parser with grouped value -(42)\n" TOY_CC_RESET);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int test_binary(Toy_Bucket* bucket) {
|
||||
//test binary add (term); also covers subtract
|
||||
{
|
||||
Toy_Ast* ast = makeAstFromSource(&bucket, "1 + 2;");
|
||||
|
||||
//check if it worked
|
||||
if (
|
||||
ast == NULL ||
|
||||
ast->type != TOY_AST_BLOCK ||
|
||||
ast->block.child == NULL ||
|
||||
ast->block.child->type != TOY_AST_BINARY ||
|
||||
ast->block.child->binary.flag != TOY_AST_FLAG_ADD ||
|
||||
|
||||
ast->block.child->binary.left == NULL ||
|
||||
ast->block.child->binary.left->type != TOY_AST_VALUE ||
|
||||
TOY_VALUE_IS_INTEGER(ast->block.child->binary.left->value.value) == false ||
|
||||
TOY_VALUE_AS_INTEGER(ast->block.child->binary.left->value.value) != 1 ||
|
||||
|
||||
ast->block.child->binary.right == NULL ||
|
||||
ast->block.child->binary.right->type != TOY_AST_VALUE ||
|
||||
TOY_VALUE_IS_INTEGER(ast->block.child->binary.right->value.value) == false ||
|
||||
TOY_VALUE_AS_INTEGER(ast->block.child->binary.right->value.value) != 2)
|
||||
{
|
||||
fprintf(stderr, TOY_CC_ERROR "ERROR: failed to run the parser with binary add '1 + 2' (term)\n" TOY_CC_RESET);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
//test binary multiply (factor); also covers divide and modulo
|
||||
{
|
||||
Toy_Ast* ast = makeAstFromSource(&bucket, "3 * 5;");
|
||||
|
||||
//check if it worked
|
||||
if (
|
||||
ast == NULL ||
|
||||
ast->type != TOY_AST_BLOCK ||
|
||||
ast->block.child == NULL ||
|
||||
ast->block.child->type != TOY_AST_BINARY ||
|
||||
ast->block.child->binary.flag != TOY_AST_FLAG_MULTIPLY ||
|
||||
|
||||
ast->block.child->binary.left == NULL ||
|
||||
ast->block.child->binary.left->type != TOY_AST_VALUE ||
|
||||
TOY_VALUE_IS_INTEGER(ast->block.child->binary.left->value.value) == false ||
|
||||
TOY_VALUE_AS_INTEGER(ast->block.child->binary.left->value.value) != 3 ||
|
||||
|
||||
ast->block.child->binary.right == NULL ||
|
||||
ast->block.child->binary.right->type != TOY_AST_VALUE ||
|
||||
TOY_VALUE_IS_INTEGER(ast->block.child->binary.right->value.value) == false ||
|
||||
TOY_VALUE_AS_INTEGER(ast->block.child->binary.right->value.value) != 5)
|
||||
{
|
||||
fprintf(stderr, TOY_CC_ERROR "ERROR: failed to run the parser with binary multiply '3 * 5' (factor)\n" TOY_CC_RESET);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
//test binary assign (using numbers for now, as identifiers aren't coded yet)
|
||||
{
|
||||
Toy_Ast* ast = makeAstFromSource(&bucket, "1 = 2;");
|
||||
|
||||
//check if it worked
|
||||
if (
|
||||
ast == NULL ||
|
||||
ast->type != TOY_AST_BLOCK ||
|
||||
ast->block.child == NULL ||
|
||||
ast->block.child->type != TOY_AST_BINARY ||
|
||||
ast->block.child->binary.flag != TOY_AST_FLAG_ASSIGN ||
|
||||
|
||||
ast->block.child->binary.left == NULL ||
|
||||
ast->block.child->binary.left->type != TOY_AST_VALUE ||
|
||||
TOY_VALUE_IS_INTEGER(ast->block.child->binary.left->value.value) == false ||
|
||||
TOY_VALUE_AS_INTEGER(ast->block.child->binary.left->value.value) != 1 ||
|
||||
|
||||
ast->block.child->binary.right == NULL ||
|
||||
ast->block.child->binary.right->type != TOY_AST_VALUE ||
|
||||
TOY_VALUE_IS_INTEGER(ast->block.child->binary.right->value.value) == false ||
|
||||
TOY_VALUE_AS_INTEGER(ast->block.child->binary.right->value.value) != 2)
|
||||
{
|
||||
fprintf(stderr, TOY_CC_ERROR "ERROR: failed to run the parser with binary assign '1 = 2'\n" TOY_CC_RESET);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
//test binary compare (equality)
|
||||
{
|
||||
Toy_Ast* ast = makeAstFromSource(&bucket, "42 == 69;");
|
||||
|
||||
//check if it worked
|
||||
if (
|
||||
ast == NULL ||
|
||||
ast->type != TOY_AST_BLOCK ||
|
||||
ast->block.child == NULL ||
|
||||
ast->block.child->type != TOY_AST_BINARY ||
|
||||
ast->block.child->binary.flag != TOY_AST_FLAG_COMPARE_EQUAL ||
|
||||
|
||||
ast->block.child->binary.left == NULL ||
|
||||
ast->block.child->binary.left->type != TOY_AST_VALUE ||
|
||||
TOY_VALUE_IS_INTEGER(ast->block.child->binary.left->value.value) == false ||
|
||||
TOY_VALUE_AS_INTEGER(ast->block.child->binary.left->value.value) != 42 ||
|
||||
|
||||
ast->block.child->binary.right == NULL ||
|
||||
ast->block.child->binary.right->type != TOY_AST_VALUE ||
|
||||
TOY_VALUE_IS_INTEGER(ast->block.child->binary.right->value.value) == false ||
|
||||
TOY_VALUE_AS_INTEGER(ast->block.child->binary.right->value.value) != 69)
|
||||
{
|
||||
fprintf(stderr, TOY_CC_ERROR "ERROR: failed to run the parser with binary compare '42 == 69'\n" TOY_CC_RESET);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int test_precedence(Toy_Bucket* bucket) {
|
||||
//test term-factor precedence
|
||||
{
|
||||
Toy_Ast* ast = makeAstFromSource(&bucket, "1 * 2 + 3 * 4;");
|
||||
|
||||
//check if it worked
|
||||
if (
|
||||
ast == NULL ||
|
||||
ast->type != TOY_AST_BLOCK ||
|
||||
ast->block.child == NULL ||
|
||||
ast->block.child->type != TOY_AST_BINARY ||
|
||||
ast->block.child->binary.flag != TOY_AST_FLAG_ADD ||
|
||||
|
||||
ast->block.child->binary.left == NULL ||
|
||||
ast->block.child->binary.left->type != TOY_AST_BINARY ||
|
||||
ast->block.child->binary.left->binary.flag != TOY_AST_FLAG_MULTIPLY ||
|
||||
ast->block.child->binary.left->binary.left == NULL ||
|
||||
ast->block.child->binary.left->binary.left->type != TOY_AST_VALUE ||
|
||||
TOY_VALUE_IS_INTEGER(ast->block.child->binary.left->binary.left->value.value) == false ||
|
||||
TOY_VALUE_AS_INTEGER(ast->block.child->binary.left->binary.left->value.value) != 1 ||
|
||||
ast->block.child->binary.left->binary.right == NULL ||
|
||||
ast->block.child->binary.left->binary.right->type != TOY_AST_VALUE ||
|
||||
TOY_VALUE_IS_INTEGER(ast->block.child->binary.left->binary.right->value.value) == false ||
|
||||
TOY_VALUE_AS_INTEGER(ast->block.child->binary.left->binary.right->value.value) != 2 ||
|
||||
|
||||
ast->block.child->binary.right == NULL ||
|
||||
ast->block.child->binary.right->type != TOY_AST_BINARY ||
|
||||
ast->block.child->binary.right->binary.flag != TOY_AST_FLAG_MULTIPLY ||
|
||||
ast->block.child->binary.right->binary.left == NULL ||
|
||||
ast->block.child->binary.right->binary.left->type != TOY_AST_VALUE ||
|
||||
TOY_VALUE_IS_INTEGER(ast->block.child->binary.right->binary.left->value.value) == false ||
|
||||
TOY_VALUE_AS_INTEGER(ast->block.child->binary.right->binary.left->value.value) != 3 ||
|
||||
ast->block.child->binary.right->binary.right == NULL ||
|
||||
ast->block.child->binary.right->binary.right->type != TOY_AST_VALUE ||
|
||||
TOY_VALUE_IS_INTEGER(ast->block.child->binary.right->binary.right->value.value) == false ||
|
||||
TOY_VALUE_AS_INTEGER(ast->block.child->binary.right->binary.right->value.value) != 4)
|
||||
{
|
||||
fprintf(stderr, TOY_CC_ERROR "ERROR: failed to run the parser precedence '1 * 2 + 3 * 4' (term-factor)\n" TOY_CC_RESET);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
//test left-recrusive precedence
|
||||
{
|
||||
Toy_Ast* ast = makeAstFromSource(&bucket, "1 + 2 + 3 + 4 + 5 + 6;");
|
||||
|
||||
//check if it worked
|
||||
if (
|
||||
ast == NULL ||
|
||||
ast->type != TOY_AST_BLOCK ||
|
||||
ast->block.child == NULL ||
|
||||
ast->block.child->type != TOY_AST_BINARY ||
|
||||
ast->block.child->binary.flag != TOY_AST_FLAG_ADD ||
|
||||
|
||||
// start from the right and work backwards
|
||||
ast->block.child->binary.right == NULL ||
|
||||
ast->block.child->binary.right->type != TOY_AST_VALUE ||
|
||||
TOY_VALUE_IS_INTEGER(ast->block.child->binary.right->value.value) == false ||
|
||||
TOY_VALUE_AS_INTEGER(ast->block.child->binary.right->value.value) != 6 ||
|
||||
|
||||
ast->block.child->binary.left == NULL ||
|
||||
ast->block.child->binary.left->type != TOY_AST_BINARY ||
|
||||
ast->block.child->binary.left->binary.right == NULL ||
|
||||
ast->block.child->binary.left->binary.right->type != TOY_AST_VALUE ||
|
||||
TOY_VALUE_IS_INTEGER(ast->block.child->binary.left->binary.right->value.value) == false ||
|
||||
TOY_VALUE_AS_INTEGER(ast->block.child->binary.left->binary.right->value.value) != 5 ||
|
||||
|
||||
ast->block.child->binary.left->binary.left == NULL ||
|
||||
ast->block.child->binary.left->binary.left->type != TOY_AST_BINARY ||
|
||||
ast->block.child->binary.left->binary.left->binary.right == NULL ||
|
||||
ast->block.child->binary.left->binary.left->binary.right->type != TOY_AST_VALUE ||
|
||||
TOY_VALUE_IS_INTEGER(ast->block.child->binary.left->binary.left->binary.right->value.value) == false ||
|
||||
TOY_VALUE_AS_INTEGER(ast->block.child->binary.left->binary.left->binary.right->value.value) != 4 ||
|
||||
|
||||
ast->block.child->binary.left->binary.left->binary.left == NULL ||
|
||||
ast->block.child->binary.left->binary.left->binary.left->type != TOY_AST_BINARY ||
|
||||
ast->block.child->binary.left->binary.left->binary.left->binary.right == NULL ||
|
||||
ast->block.child->binary.left->binary.left->binary.left->binary.right->type != TOY_AST_VALUE ||
|
||||
TOY_VALUE_IS_INTEGER(ast->block.child->binary.left->binary.left->binary.left->binary.right->value.value) == false ||
|
||||
TOY_VALUE_AS_INTEGER(ast->block.child->binary.left->binary.left->binary.left->binary.right->value.value) != 3 ||
|
||||
|
||||
ast->block.child->binary.left->binary.left->binary.left->binary.left == NULL ||
|
||||
ast->block.child->binary.left->binary.left->binary.left->binary.left->type != TOY_AST_BINARY ||
|
||||
ast->block.child->binary.left->binary.left->binary.left->binary.left->binary.right == NULL ||
|
||||
ast->block.child->binary.left->binary.left->binary.left->binary.left->binary.right->type != TOY_AST_VALUE ||
|
||||
TOY_VALUE_IS_INTEGER(ast->block.child->binary.left->binary.left->binary.left->binary.left->binary.right->value.value) == false ||
|
||||
TOY_VALUE_AS_INTEGER(ast->block.child->binary.left->binary.left->binary.left->binary.left->binary.right->value.value) != 2 ||
|
||||
|
||||
ast->block.child->binary.left->binary.left->binary.left->binary.left->binary.left == NULL ||
|
||||
ast->block.child->binary.left->binary.left->binary.left->binary.left->binary.left->type != TOY_AST_VALUE ||
|
||||
TOY_VALUE_IS_INTEGER(ast->block.child->binary.left->binary.left->binary.left->binary.left->binary.left->value.value) == false ||
|
||||
TOY_VALUE_AS_INTEGER(ast->block.child->binary.left->binary.left->binary.left->binary.left->binary.left->value.value) != 1)
|
||||
|
||||
{
|
||||
fprintf(stderr, TOY_CC_ERROR "ERROR: failed to run the parser precedence '1 + 2 + 3 + 4 + 5 + 6' (left-recursive)\n" TOY_CC_RESET);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
//test group precedence
|
||||
{
|
||||
Toy_Ast* ast = makeAstFromSource(&bucket, "(1 + 2) * (3 + 4);");
|
||||
|
||||
//check if it worked
|
||||
if (
|
||||
ast == NULL ||
|
||||
ast->type != TOY_AST_BLOCK ||
|
||||
ast->block.child == NULL ||
|
||||
ast->block.child->type != TOY_AST_BINARY ||
|
||||
ast->block.child->binary.flag != TOY_AST_FLAG_MULTIPLY ||
|
||||
|
||||
ast->block.child->binary.left == NULL ||
|
||||
ast->block.child->binary.left->type != TOY_AST_GROUP ||
|
||||
ast->block.child->binary.left->group.child == NULL ||
|
||||
|
||||
ast->block.child->binary.left->group.child->type != TOY_AST_BINARY ||
|
||||
ast->block.child->binary.left->group.child->binary.flag != TOY_AST_FLAG_ADD ||
|
||||
ast->block.child->binary.left->group.child->binary.left == NULL ||
|
||||
ast->block.child->binary.left->group.child->binary.left->type != TOY_AST_VALUE ||
|
||||
TOY_VALUE_IS_INTEGER(ast->block.child->binary.left->group.child->binary.left->value.value) == false ||
|
||||
TOY_VALUE_AS_INTEGER(ast->block.child->binary.left->group.child->binary.left->value.value) != 1 ||
|
||||
ast->block.child->binary.left->group.child->binary.right == NULL ||
|
||||
ast->block.child->binary.left->group.child->binary.right->type != TOY_AST_VALUE ||
|
||||
TOY_VALUE_IS_INTEGER(ast->block.child->binary.left->group.child->binary.right->value.value) == false ||
|
||||
TOY_VALUE_AS_INTEGER(ast->block.child->binary.left->group.child->binary.right->value.value) != 2 ||
|
||||
|
||||
ast->block.child->binary.right == NULL ||
|
||||
ast->block.child->binary.right->type != TOY_AST_GROUP ||
|
||||
ast->block.child->binary.right->group.child == NULL ||
|
||||
|
||||
ast->block.child->binary.right->group.child->type != TOY_AST_BINARY ||
|
||||
ast->block.child->binary.right->group.child->binary.flag != TOY_AST_FLAG_ADD ||
|
||||
ast->block.child->binary.right->group.child->binary.left == NULL ||
|
||||
ast->block.child->binary.right->group.child->binary.left->type != TOY_AST_VALUE ||
|
||||
TOY_VALUE_IS_INTEGER(ast->block.child->binary.right->group.child->binary.left->value.value) == false ||
|
||||
TOY_VALUE_AS_INTEGER(ast->block.child->binary.right->group.child->binary.left->value.value) != 3 ||
|
||||
ast->block.child->binary.right->group.child->binary.right == NULL ||
|
||||
ast->block.child->binary.right->group.child->binary.right->type != TOY_AST_VALUE ||
|
||||
TOY_VALUE_IS_INTEGER(ast->block.child->binary.right->group.child->binary.right->value.value) == false ||
|
||||
TOY_VALUE_AS_INTEGER(ast->block.child->binary.right->group.child->binary.right->value.value) != 4)
|
||||
{
|
||||
fprintf(stderr, TOY_CC_ERROR "ERROR: failed to run the parser precedence '(1 + 2) * (3 + 4)' (group)\n" TOY_CC_RESET);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main() {
|
||||
//run each test set, returning the total errors given
|
||||
int total = 0, res = 0;
|
||||
|
||||
{
|
||||
Toy_Bucket* bucket = NULL;
|
||||
TOY_BUCKET_INIT(Toy_Ast, bucket, 32);
|
||||
res = test_simple_empty_parsers(bucket);
|
||||
TOY_BUCKET_FREE(bucket);
|
||||
if (res == 0) {
|
||||
printf(TOY_CC_NOTICE "All good\n" TOY_CC_RESET);
|
||||
}
|
||||
total += res;
|
||||
}
|
||||
|
||||
{
|
||||
Toy_Bucket* bucket = NULL;
|
||||
TOY_BUCKET_INIT(Toy_Ast, bucket, 32);
|
||||
res = test_values(bucket);
|
||||
TOY_BUCKET_FREE(bucket);
|
||||
if (res == 0) {
|
||||
printf(TOY_CC_NOTICE "All good\n" TOY_CC_RESET);
|
||||
}
|
||||
total += res;
|
||||
}
|
||||
|
||||
{
|
||||
Toy_Bucket* bucket = NULL;
|
||||
TOY_BUCKET_INIT(Toy_Ast, bucket, 32);
|
||||
res = test_unary(bucket);
|
||||
TOY_BUCKET_FREE(bucket);
|
||||
if (res == 0) {
|
||||
printf(TOY_CC_NOTICE "All good\n" TOY_CC_RESET);
|
||||
}
|
||||
total += res;
|
||||
}
|
||||
|
||||
{
|
||||
Toy_Bucket* bucket = NULL;
|
||||
TOY_BUCKET_INIT(Toy_Ast, bucket, 32);
|
||||
res = test_binary(bucket);
|
||||
TOY_BUCKET_FREE(bucket);
|
||||
if (res == 0) {
|
||||
printf(TOY_CC_NOTICE "All good\n" TOY_CC_RESET);
|
||||
}
|
||||
total += res;
|
||||
}
|
||||
|
||||
{
|
||||
Toy_Bucket* bucket = NULL;
|
||||
TOY_BUCKET_INIT(Toy_Ast, bucket, 32);
|
||||
res = test_precedence(bucket);
|
||||
TOY_BUCKET_FREE(bucket);
|
||||
if (res == 0) {
|
||||
printf(TOY_CC_NOTICE "All good\n" TOY_CC_RESET);
|
||||
}
|
||||
total += res;
|
||||
}
|
||||
|
||||
return total;
|
||||
}
|
||||
Reference in New Issue
Block a user