Files
Toy/tests/cases/test_ast.c
Kayne Ruse 898b8efc04 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.
2024-09-13 18:08:52 +10:00

194 lines
5.4 KiB
C

#include "toy_ast.h"
#include "toy_console_colors.h"
#include <stdio.h>
int test_sizeof_ast_32bit() {
#define TEST_SIZEOF(type, size) \
if (sizeof(type) != size) { \
fprintf(stderr, TOY_CC_ERROR "ERROR: sizeof(" #type ") is %d, expected %d\n" TOY_CC_RESET, (int)sizeof(type), size); \
++err; \
}
//count errors
int err = 0;
//run for each type
TEST_SIZEOF(Toy_AstType, 4);
TEST_SIZEOF(Toy_AstBlock, 16);
TEST_SIZEOF(Toy_AstValue, 12);
TEST_SIZEOF(Toy_AstUnary, 12);
TEST_SIZEOF(Toy_AstBinary, 16);
TEST_SIZEOF(Toy_AstGroup, 8);
TEST_SIZEOF(Toy_AstPass, 4);
TEST_SIZEOF(Toy_AstError, 4);
TEST_SIZEOF(Toy_Ast, 16);
#undef TEST_SIZEOF
return -err;
}
int test_type_emission(Toy_Bucket* bucket) {
//emit value
{
//emit to an AST
Toy_Ast* ast = NULL;
Toy_private_emitAstValue(&bucket, &ast, TOY_VALUE_TO_INTEGER(42));
//check if it worked
if (
ast == NULL ||
ast->type != TOY_AST_VALUE ||
TOY_VALUE_AS_INTEGER(ast->value.value) != 42)
{
fprintf(stderr, TOY_CC_ERROR "ERROR: failed to emit a value as 'Toy_Ast', state unknown\n" TOY_CC_RESET);
return -1;
}
}
//emit unary
{
//build the AST
Toy_Ast* ast = NULL;
Toy_private_emitAstValue(&bucket, &ast, TOY_VALUE_TO_INTEGER(42));
Toy_private_emitAstUnary(&bucket, &ast, TOY_AST_FLAG_NEGATE);
//check if it worked
if (
ast == NULL ||
ast->type != TOY_AST_UNARY ||
ast->unary.flag != TOY_AST_FLAG_NEGATE ||
ast->unary.child->type != TOY_AST_VALUE ||
TOY_VALUE_AS_INTEGER(ast->unary.child->value.value) != 42)
{
fprintf(stderr, TOY_CC_ERROR "ERROR: failed to emit a unary as 'Toy_Ast', state unknown\n" TOY_CC_RESET);
return -1;
}
}
//emit binary
{
//build the AST
Toy_Ast* ast = NULL;
Toy_Ast* right = NULL;
Toy_private_emitAstValue(&bucket, &ast, TOY_VALUE_TO_INTEGER(42));
Toy_private_emitAstValue(&bucket, &right, TOY_VALUE_TO_INTEGER(69));
Toy_private_emitAstBinary(&bucket, &ast, TOY_AST_FLAG_ADD, right);
//check if it worked
if (
ast == NULL ||
ast->type != TOY_AST_BINARY ||
ast->binary.flag != TOY_AST_FLAG_ADD ||
ast->binary.left->type != TOY_AST_VALUE ||
TOY_VALUE_AS_INTEGER(ast->binary.left->value.value) != 42 ||
ast->binary.right->type != TOY_AST_VALUE ||
TOY_VALUE_AS_INTEGER(ast->binary.right->value.value) != 69)
{
fprintf(stderr, TOY_CC_ERROR "ERROR: failed to emit a binary as 'Toy_Ast', state unknown\n" TOY_CC_RESET);
return -1;
}
}
//emit group
{
//build the AST
Toy_Ast* ast = NULL;
Toy_Ast* right = NULL;
Toy_private_emitAstValue(&bucket, &ast, TOY_VALUE_TO_INTEGER(42));
Toy_private_emitAstValue(&bucket, &right, TOY_VALUE_TO_INTEGER(69));
Toy_private_emitAstBinary(&bucket, &ast, TOY_AST_FLAG_ADD, right);
Toy_private_emitAstGroup(&bucket, &ast);
//check if it worked
if (
ast == NULL ||
ast->type != TOY_AST_GROUP ||
ast->group.child == NULL ||
ast->group.child->type != TOY_AST_BINARY ||
ast->group.child->binary.flag != TOY_AST_FLAG_ADD ||
ast->group.child->binary.left->type != TOY_AST_VALUE ||
TOY_VALUE_AS_INTEGER(ast->group.child->binary.left->value.value) != 42 ||
ast->group.child->binary.right->type != TOY_AST_VALUE ||
TOY_VALUE_AS_INTEGER(ast->group.child->binary.right->value.value) != 69)
{
fprintf(stderr, TOY_CC_ERROR "ERROR: failed to emit a group as 'Toy_Ast', state unknown\n" TOY_CC_RESET);
return -1;
}
}
//emit and append blocks of code
{
//initialize the root block
Toy_Ast* block = NULL;
Toy_private_initAstBlock(&bucket, &block);
//loop over the ast emissions, appending each one as you go
for (int i = 0; i < 5; i++) {
//build the AST
Toy_Ast* ast = NULL;
Toy_Ast* right = NULL;
Toy_private_emitAstValue(&bucket, &ast, TOY_VALUE_TO_INTEGER(42));
Toy_private_emitAstValue(&bucket, &right, TOY_VALUE_TO_INTEGER(69));
Toy_private_emitAstBinary(&bucket, &ast, TOY_AST_FLAG_ADD, right);
Toy_private_emitAstGroup(&bucket, &ast);
Toy_private_appendAstBlock(&bucket, &block, ast);
}
//check if it worked
Toy_Ast* iter = block;
while(iter != NULL) {
if (
iter->type != TOY_AST_BLOCK ||
iter->block.child == NULL ||
iter->block.child->type != TOY_AST_GROUP ||
iter->block.child->group.child == NULL ||
iter->block.child->group.child->type != TOY_AST_BINARY ||
iter->block.child->group.child->binary.flag != TOY_AST_FLAG_ADD ||
iter->block.child->group.child->binary.left->type != TOY_AST_VALUE ||
TOY_VALUE_AS_INTEGER(iter->block.child->group.child->binary.left->value.value) != 42 ||
iter->block.child->group.child->binary.right->type != TOY_AST_VALUE ||
TOY_VALUE_AS_INTEGER(iter->block.child->group.child->binary.right->value.value) != 69)
{
fprintf(stderr, TOY_CC_ERROR "ERROR: failed to emit a block as 'Toy_Ast', state unknown\n" TOY_CC_RESET);
return -1;
}
iter = iter->block.next;
}
}
return 0;
}
int main() {
//run each test set, returning the total errors given
int total = 0, res = 0;
#if TOY_BITNESS == 32
res = test_sizeof_ast_32bit();
total += res;
if (res == 0) {
printf(TOY_CC_NOTICE "All good\n" TOY_CC_RESET);
}
#else
fprintf(stderr, TOY_CC_WARN "WARNING: Skipping test_sizeof_ast_32bit(); Can't determine the 'bitness' of this platform\n" TOY_CC_RESET);
#endif
{
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;
}