Bytecode and Routine working, Routine tests incomplete

There may be a build issue on windows
This commit is contained in:
2024-09-20 16:15:27 +10:00
parent e35af3d84b
commit ad6f1c3067
9 changed files with 391 additions and 46 deletions

View File

@@ -28,24 +28,17 @@ Things to consider later:
=== ===
//general instructions //variable instructions
READ READ
read one value from C onto S read one value from C onto S
LOAD LOAD
read one value from .data onto S read one value from .data onto S
ASSERT
if S(-1) is falsy, print S(0) and exit
PRINT
pop S(0), and print the output
SET
read one word from C, saves the key E[SYMBOL(word)] to the value S(0), popping S(0)
GET
read one word from C, finds the value of E[SYMBOL(word)], leaves the value on S
DECLARE DECLARE
read two words from C, create a new entry in E with the key E[SYMBOL(word1)], the type defined by word2, the value 'null' read two words from C, create a new entry in E with the key E[SYMBOL(word1)], the type defined by word2, the value 'null'
DEFINE DEFINE
read two words from C, create a new entry in E with the key E[SYMBOL(word1)], the type defined by word2, the value popped from S(0) read one word from C, saves the pre-existing key E[SYMBOL(word)] to the value S(0), popping S(0)
ACCESS
read one word from C, finds the pre-existing value of E[SYMBOL(word)], leaves the value on S
//arithmetic instructions //arithmetic instructions
ADD ADD
@@ -80,7 +73,7 @@ OR
pops S(-1) and S(0), replacing it with TRUE or FALSE, depending on truthiness pops S(-1) and S(0), replacing it with TRUE or FALSE, depending on truthiness
TRUTHY TRUTHY
pops S(0), replacing it with TRUE or FALSE, depending on truthiness pops S(0), replacing it with TRUE or FALSE, depending on truthiness
INVERT NEGATE
pops S(0), replacing it with TRUE or FALSE, depending on truthiness pops S(0), replacing it with TRUE or FALSE, depending on truthiness
@@ -92,10 +85,13 @@ JUMP_IF_FALSE
FN_CALL FN_CALL
*read a list of arguments specified in C into 'A', store (S, E, C, D) as D, push S, move the stack pointer to the specified routine, push a new E based on the contents of 'A' *read a list of arguments specified in C into 'A', store (S, E, C, D) as D, push S, move the stack pointer to the specified routine, push a new E based on the contents of 'A'
FN_RETURN FN_RETURN
This
*read a list of return values specified in C into 'R', pop S, restore (S, E, C, D) from D(0) popping it, store the contents of 'R' in E or S based on the next few parts of C *read a list of return values specified in C into 'R', pop S, restore (S, E, C, D) from D(0) popping it, store the contents of 'R' in E or S based on the next few parts of C
//bespoke utility instructions //bespoke utility instructions
ASSERT
if S(-1) is falsy, print S(0) and exit
PRINT
pop S(0), and print the output
IMPORT IMPORT
//invoke an external library into the current scope //invoke an external library into the current scope
CONCAT CONCAT

View File

@@ -37,7 +37,7 @@ Additional information may be added later, or multiple 'modules' listed sequenti
# where 'module' can be omitted if it's local to this module ('identifier' within the symbols is calculated at the module level, it's always unique) # where 'module' can be omitted if it's local to this module ('identifier' within the symbols is calculated at the module level, it's always unique)
.header: .header:
total size # size of this routine, including all data and subroutines N total size # size of this routine, including all data and subroutines
N .param count # the number of parameter fields expected N .param count # the number of parameter fields expected
N .data count # the number of data fields expected N .data count # the number of data fields expected
N .routine count # the number of routines present N .routine count # the number of routines present

View File

@@ -29,12 +29,12 @@ typedef enum Toy_AstFlag {
TOY_AST_FLAG_MULTIPLY, TOY_AST_FLAG_MULTIPLY,
TOY_AST_FLAG_DIVIDE, TOY_AST_FLAG_DIVIDE,
TOY_AST_FLAG_MODULO, TOY_AST_FLAG_MODULO,
TOY_AST_FLAG_ASSIGN, //TODO: implement the declare statement
TOY_AST_FLAG_ADD_ASSIGN, TOY_AST_FLAG_ADD_ASSIGN,
TOY_AST_FLAG_SUBTRACT_ASSIGN, TOY_AST_FLAG_SUBTRACT_ASSIGN,
TOY_AST_FLAG_MULTIPLY_ASSIGN, TOY_AST_FLAG_MULTIPLY_ASSIGN,
TOY_AST_FLAG_DIVIDE_ASSIGN, TOY_AST_FLAG_DIVIDE_ASSIGN,
TOY_AST_FLAG_MODULO_ASSIGN, TOY_AST_FLAG_MODULO_ASSIGN,
TOY_AST_FLAG_ASSIGN,
TOY_AST_FLAG_COMPARE_EQUAL, TOY_AST_FLAG_COMPARE_EQUAL,
TOY_AST_FLAG_COMPARE_NOT, TOY_AST_FLAG_COMPARE_NOT,
TOY_AST_FLAG_COMPARE_LESS, TOY_AST_FLAG_COMPARE_LESS,

View File

@@ -1,4 +1,5 @@
#include "toy_bytecode.h" #include "toy_bytecode.h"
#include "toy_console_colors.h"
#include "toy_memory.h" #include "toy_memory.h"
#include "toy_routine.h" #include "toy_routine.h"
@@ -21,10 +22,6 @@ static void emitByte(Toy_Bytecode* bc, unsigned char byte) {
bc->ptr[bc->count++] = byte; bc->ptr[bc->count++] = byte;
} }
static void writeModule(Toy_Bytecode* bc, Toy_Ast* ast) {
//TODO: routines
}
//bytecode //bytecode
static void writeBytecodeHeader(Toy_Bytecode* bc) { static void writeBytecodeHeader(Toy_Bytecode* bc) {
emitByte(bc, TOY_VERSION_MAJOR); emitByte(bc, TOY_VERSION_MAJOR);
@@ -36,7 +33,7 @@ static void writeBytecodeHeader(Toy_Bytecode* bc) {
int len = (int)strlen(build) + 1; int len = (int)strlen(build) + 1;
expand(bc, len); expand(bc, len);
sprintf((char*)(bc->ptr + bc->count), "%.*s", len, build); memcpy(bc->ptr + bc->count, build, len);
bc->count += len; bc->count += len;
} }
@@ -44,7 +41,13 @@ static void writeBytecodeBody(Toy_Bytecode* bc, Toy_Ast* ast) {
//a 'module' is a routine that runs at the root-level of a file //a 'module' is a routine that runs at the root-level of a file
//since routines can be recursive, this distinction is important //since routines can be recursive, this distinction is important
//eventually, the bytecode may support multiple modules packed into one file //eventually, the bytecode may support multiple modules packed into one file
writeModule(bc, ast); void* module = Toy_compileRoutine(ast);
int len = ((int*)module)[0];
expand(bc, len);
memcpy(bc->ptr + bc->count, module, len);
bc->count += len;
} }
//exposed functions //exposed functions

View File

@@ -1,10 +1,40 @@
#pragma once #pragma once
typedef enum Toy_OpcodeType { typedef enum Toy_OpcodeType {
// //variable instructions
TOY_OPCODE_READ,
TOY_OPCODE_LOAD,
TOY_OPCODE_LOAD_LONG, //corner case
TOY_OPCODE_DECLARE,
TOY_OPCODE_ASSIGN,
TOY_OPCODE_ACCESS,
//arithmetic instructions
TOY_OPCODE_ADD,
TOY_OPCODE_SUBTRACT,
TOY_OPCODE_MULTIPLY,
TOY_OPCODE_DIVIDE,
TOY_OPCODE_MODULO,
//comparison instructions
TOY_OPCODE_COMPARE_EQUAL,
// TOY_OPCODE_COMPARE_NOT,
TOY_OPCODE_COMPARE_LESS,
TOY_OPCODE_COMPARE_LESS_EQUAL,
TOY_OPCODE_COMPARE_GREATER,
TOY_OPCODE_COMPARE_GREATER_EQUAL,
//logical instructions
TOY_OPCODE_AND,
TOY_OPCODE_OR,
TOY_OPCODE_TRUTHY,
TOY_OPCODE_NEGATE,
//control instructions
TOY_OPCODE_RETURN,
//meta instructions
TOY_OPCODE_PASS, TOY_OPCODE_PASS,
TOY_OPCODE_ERROR, TOY_OPCODE_ERROR,
TOY_OPCODE_EOF, TOY_OPCODE_EOF,
} Toy_OpcodeType; } Toy_OpcodeType;

View File

@@ -1,8 +1,12 @@
#include "toy_routine.h" #include "toy_routine.h"
#include "toy_console_colors.h"
#include "toy_memory.h" #include "toy_memory.h"
#include "toy_opcodes.h"
#include "toy_value.h"
#include <stdio.h> #include <stdio.h>
#include <stdlib.h>
#include <string.h> #include <string.h>
//utils //utils
@@ -10,7 +14,7 @@ static void expand(void** handle, int* capacity, int* count, int amount) {
while ((*count) + amount > (*capacity)) { while ((*count) + amount > (*capacity)) {
int oldCapacity = (*capacity); int oldCapacity = (*capacity);
(*capacity) = TOY_GROW_CAPACITY(oldCapacity); (*capacity) = TOY_GROW_CAPACITY(oldCapacity); //TODO: don't need GROW
(*handle) = TOY_GROW_ARRAY(unsigned char, (*handle), oldCapacity, (*capacity)); (*handle) = TOY_GROW_ARRAY(unsigned char, (*handle), oldCapacity, (*capacity));
} }
} }
@@ -20,11 +24,273 @@ static void emitByte(void** handle, int* capacity, int* count, unsigned char byt
((unsigned char*)(*handle))[(*count)++] = byte; ((unsigned char*)(*handle))[(*count)++] = byte;
} }
//routine static void emitInt(void** handle, int* capacity, int* count, int bytes) {
//TODO char* ptr = (char*)&bytes;
emitByte(handle, capacity, count, *(ptr++));
emitByte(handle, capacity, count, *(ptr++));
emitByte(handle, capacity, count, *(ptr++));
emitByte(handle, capacity, count, *(ptr++));
}
static void emitFloat(void** handle, int* capacity, int* count, float bytes) {
char* ptr = (char*)&bytes;
emitByte(handle, capacity, count, *(ptr++));
emitByte(handle, capacity, count, *(ptr++));
emitByte(handle, capacity, count, *(ptr++));
emitByte(handle, capacity, count, *(ptr++));
}
//write instructions based on the AST types
#define EMIT_BYTE(rt, byte) \
emitByte((void**)(&((*rt)->code)), &((*rt)->codeCapacity), &((*rt)->codeCount), byte);
#define EMIT_INT(rt, code, byte) \
emitInt((void**)(&((*rt)->code)), &((*rt)->codeCapacity), &((*rt)->codeCount), byte);
#define EMIT_FLOAT(rt, code, byte) \
emitFloat((void**)(&((*rt)->code)), &((*rt)->codeCapacity), &((*rt)->codeCount), byte);
static void writeRoutineCode(Toy_Routine** rt, Toy_Ast* ast); //forward declare for recursion
static void writeInstructionValue(Toy_Routine** rt, Toy_AstValue ast) {
//TODO: store more complex values in the data code
EMIT_BYTE(rt, TOY_OPCODE_READ);
EMIT_BYTE(rt, ast.value.type);
//emit the raw value based on the type
if (TOY_VALUE_IS_NULL(ast.value)) {
//NOTHING - null's type data is enough
}
else if (TOY_VALUE_IS_BOOLEAN(ast.value)) {
EMIT_BYTE(rt, TOY_VALUE_AS_BOOLEAN(ast.value));
}
else if (TOY_VALUE_IS_INTEGER(ast.value)) {
EMIT_INT(rt, code, TOY_VALUE_AS_INTEGER(ast.value));
}
else if (TOY_VALUE_IS_FLOAT(ast.value)) {
EMIT_FLOAT(rt, code, TOY_VALUE_AS_FLOAT(ast.value));
}
else {
fprintf(stderr, TOY_CC_ERROR "Invalid AST type found: Unknown value type\n" TOY_CC_RESET);
exit(-1);
}
}
static void writeInstructionUnary(Toy_Routine** rt, Toy_AstUnary ast) {
//working with a stack means the child gets placed first
writeRoutineCode(rt, ast.child);
if (ast.flag == TOY_AST_FLAG_NEGATE) {
EMIT_BYTE(rt, TOY_OPCODE_NEGATE);
}
else {
fprintf(stderr, TOY_CC_ERROR "Invalid AST unary flag found\n" TOY_CC_RESET);
exit(-1);
}
}
static void writeInstructionBinary(Toy_Routine** rt, Toy_AstBinary ast) {
//left, then right, then the binary's operation
writeRoutineCode(rt, ast.left);
writeRoutineCode(rt, ast.right);
if (ast.flag == TOY_AST_FLAG_ADD) {
EMIT_BYTE(rt, TOY_OPCODE_ADD);
}
if (ast.flag == TOY_AST_FLAG_SUBTRACT) {
EMIT_BYTE(rt, TOY_OPCODE_SUBTRACT);
}
if (ast.flag == TOY_AST_FLAG_MULTIPLY) {
EMIT_BYTE(rt, TOY_OPCODE_MULTIPLY);
}
if (ast.flag == TOY_AST_FLAG_DIVIDE) {
EMIT_BYTE(rt, TOY_OPCODE_DIVIDE);
}
if (ast.flag == TOY_AST_FLAG_MODULO) {
EMIT_BYTE(rt, TOY_OPCODE_MODULO);
}
// if (ast.flag == TOY_AST_FLAG_ASSIGN) {
// EMIT_BYTE(rt, TOY_OPCODE_ASSIGN);
// //TODO: emit the env symbol to store TOP(S) within
// }
// if (ast.flag == TOY_AST_FLAG_ADD_ASSIGN) {
// EMIT_BYTE(rt, TOY_OPCODE_ADD);
// EMIT_BYTE(rt, TOY_OPCODE_ASSIGN);
// //TODO: emit the env symbol to store TOP(S) within
// }
// if (ast.flag == TOY_AST_FLAG_SUBTRACT_ASSIGN) {
// EMIT_BYTE(rt, TOY_OPCODE_SUBTRACT);
// EMIT_BYTE(rt, TOY_OPCODE_ASSIGN);
// //TODO: emit the env symbol to store TOP(S) within
// }
// if (ast.flag == TOY_AST_FLAG_MULTIPLY_ASSIGN) {
// EMIT_BYTE(rt, TOY_OPCODE_MULTIPLY);
// EMIT_BYTE(rt, TOY_OPCODE_ASSIGN);
// //TODO: emit the env symbol to store TOP(S) within
// }
// if (ast.flag == TOY_AST_FLAG_DIVIDE_ASSIGN) {
// EMIT_BYTE(rt, TOY_OPCODE_DIVIDE);
// EMIT_BYTE(rt, TOY_OPCODE_ASSIGN);
// //TODO: emit the env symbol to store TOP(S) within
// }
// if (ast.flag == TOY_AST_FLAG_MODULO_ASSIGN) {
// EMIT_BYTE(rt, TOY_OPCODE_MODULO);
// EMIT_BYTE(rt, TOY_OPCODE_ASSIGN);
// //TODO: emit the env symbol to store TOP(S) within
// }
if (ast.flag == TOY_AST_FLAG_COMPARE_EQUAL) {
EMIT_BYTE(rt, TOY_OPCODE_COMPARE_EQUAL);
}
if (ast.flag == TOY_AST_FLAG_COMPARE_NOT) {
EMIT_BYTE(rt, TOY_OPCODE_COMPARE_EQUAL);
EMIT_BYTE(rt, TOY_OPCODE_NEGATE);
}
if (ast.flag == TOY_AST_FLAG_COMPARE_LESS) {
EMIT_BYTE(rt, TOY_OPCODE_COMPARE_LESS);
}
if (ast.flag == TOY_AST_FLAG_COMPARE_LESS_EQUAL) {
EMIT_BYTE(rt, TOY_OPCODE_COMPARE_LESS_EQUAL);
}
if (ast.flag == TOY_AST_FLAG_COMPARE_GREATER) {
EMIT_BYTE(rt, TOY_OPCODE_COMPARE_GREATER);
}
if (ast.flag == TOY_AST_FLAG_COMPARE_GREATER_EQUAL) {
EMIT_BYTE(rt, TOY_OPCODE_COMPARE_GREATER_EQUAL);
}
if (ast.flag == TOY_AST_FLAG_AND) {
EMIT_BYTE(rt, TOY_OPCODE_AND);
}
if (ast.flag == TOY_AST_FLAG_OR) {
EMIT_BYTE(rt, TOY_OPCODE_OR);
}
else {
fprintf(stderr, TOY_CC_ERROR "Invalid AST binary flag found\n" TOY_CC_RESET);
exit(-1);
}
}
//routine structure
// static void writeRoutineParam(Toy_Routine* rt) {
// //
// }
static void writeRoutineCode(Toy_Routine** rt, Toy_Ast* ast) {
if (ast == NULL) {
return;
}
//determine how to write each instruction based on the Ast
switch(ast->type) {
case TOY_AST_BLOCK:
writeRoutineCode(rt, ast->block.child);
writeRoutineCode(rt, ast->block.next);
break;
case TOY_AST_VALUE:
writeInstructionValue(rt, ast->value);
break;
case TOY_AST_UNARY:
writeInstructionUnary(rt, ast->unary);
break;
case TOY_AST_BINARY:
writeInstructionBinary(rt, ast->binary);
break;
//other disallowed instructions
case TOY_AST_GROUP:
fprintf(stderr, TOY_CC_ERROR "Invalid AST type found: Group shouldn't be used\n" TOY_CC_RESET);
exit(-1);
break;
case TOY_AST_PASS:
//NOTE: this should be disallowed, but for now it's required for testing
// fprintf(stderr, TOY_CC_ERROR "Invalid AST type found: Unknown pass\n" TOY_CC_RESET);
// exit(-1);
break;
//meta instructions are disallowed
case TOY_AST_ERROR:
fprintf(stderr, TOY_CC_ERROR "Invalid AST type found: Unknown error\n" TOY_CC_RESET);
exit(-1);
break;
case TOY_AST_END:
fprintf(stderr, TOY_CC_ERROR "Invalid AST type found: Unknown end\n" TOY_CC_RESET);
exit(-1);
break;
}
}
// static void writeRoutineJumps(Toy_Routine* rt) {
// //
// }
// static void writeRoutineData(Toy_Routine* rt) {
// //
// }
static void* writeRoutine(Toy_Routine* rt, Toy_Ast* ast) {
//build the routine's parts
//param
//code
writeRoutineCode(&rt, ast);
EMIT_BYTE(&rt, TOY_OPCODE_RETURN); //temp terminator
//jumps
//data
//write the header and combine the parts
void* buffer = TOY_ALLOCATE(unsigned char, 16);
int capacity = 0, count = 0;
// int paramAddr = 0, codeAddr = 0, jumpsAddr = 0, dataAddr = 0, subsAddr = 0;
int codeAddr = 0;
emitInt(&buffer, &capacity, &count, 0); //total size (overwritten later)
emitInt(&buffer, &capacity, &count, rt->paramCount); //param count
emitInt(&buffer, &capacity, &count, rt->dataCount); //data count
emitInt(&buffer, &capacity, &count, rt->subsCount); //routine count
//generate blank spaces, cache their positions in the []Addr variables
if (rt->paramCount > 0) {
// paramAddr = count;
emitInt((void**)&buffer, &capacity, &count, 0); //params
}
if (rt->codeCount > 0) {
codeAddr = count;
emitInt((void**)&buffer, &capacity, &count, 0); //code
}
if (rt->jumpsCount > 0) {
// jumpsAddr = count;
emitInt((void**)&buffer, &capacity, &count, 0); //jumps
}
if (rt->dataCount > 0) {
// dataAddr = count;
emitInt((void**)&buffer, &capacity, &count, 0); //data
}
if (rt->subsCount > 0) {
// subsAddr = count;
emitInt((void**)&buffer, &capacity, &count, 0); //subs
}
//append various parts to the buffer TODO: add the rest
if (rt->codeCount > 0) {
expand(&buffer, &capacity, &count, rt->codeCount);
memcpy((buffer + count), rt->code, rt->codeCount);
((int*)buffer)[codeAddr] = count;
count += rt->codeCount;
}
//finally, record the total size, and return the result
((int*)buffer)[0] = count;
return buffer;
}
//exposed functions //exposed functions
Toy_Routine Toy_compileRoutine(Toy_Ast* ast) { void* Toy_compileRoutine(Toy_Ast* ast) {
//setup //setup
Toy_Routine rt; Toy_Routine rt;
@@ -36,23 +302,27 @@ Toy_Routine Toy_compileRoutine(Toy_Ast* ast) {
rt.codeCapacity = 0; rt.codeCapacity = 0;
rt.codeCount = 0; rt.codeCount = 0;
rt.jumps = NULL;
rt.jumpsCapacity = 0;
rt.jumpsCount = 0;
rt.data = NULL; rt.data = NULL;
rt.dataCapacity = 0; rt.dataCapacity = 0;
rt.dataCount = 0; rt.dataCount = 0;
rt.jump = NULL; rt.subs = NULL;
rt.jumpCapacity = 0; rt.subsCapacity = 0;
rt.jumpCount = 0; rt.subsCount = 0;
//build //build
//TODO void * buffer = writeRoutine(&rt, ast);
return rt; //cleanup the temp object
}
void freeRoutine(Toy_Routine rt) {
TOY_FREE_ARRAY(unsigned char, rt.param, rt.paramCapacity); TOY_FREE_ARRAY(unsigned char, rt.param, rt.paramCapacity);
TOY_FREE_ARRAY(unsigned char, rt.code, rt.codeCapacity); TOY_FREE_ARRAY(unsigned char, rt.code, rt.codeCapacity);
TOY_FREE_ARRAY(int, rt.jumps, rt.jumpsCapacity);
TOY_FREE_ARRAY(unsigned char, rt.data, rt.dataCapacity); TOY_FREE_ARRAY(unsigned char, rt.data, rt.dataCapacity);
TOY_FREE_ARRAY(int, rt.jump, rt.jumpCapacity); TOY_FREE_ARRAY(unsigned char, rt.subs, rt.subsCapacity);
return buffer;
} }

View File

@@ -3,7 +3,7 @@
#include "toy_common.h" #include "toy_common.h"
#include "toy_ast.h" #include "toy_ast.h"
//routine - holds the individual parts of a compiled routine //routine - internal structure that holds the individual parts of a compiled routine
typedef struct Toy_Routine { typedef struct Toy_Routine {
unsigned char* param; //c-string params in sequence unsigned char* param; //c-string params in sequence
int paramCapacity; int paramCapacity;
@@ -13,16 +13,17 @@ typedef struct Toy_Routine {
int codeCapacity; int codeCapacity;
int codeCount; int codeCount;
int* jumps; //each 'jump' is the starting address of an element within 'data'
int jumpsCapacity;
int jumpsCount;
unsigned char* data; //{type,val} tuples of data unsigned char* data; //{type,val} tuples of data
int dataCapacity; int dataCapacity;
int dataCount; int dataCount;
int* jump; //each 'jump' is the starting address of an element within 'data' unsigned char* subs; //subroutines, recursively
int jumpCapacity; int subsCapacity;
int jumpCount; int subsCount;
//TODO: duplicate the data and jumps for subroutines
} Toy_Routine; } Toy_Routine;
TOY_API Toy_Routine Toy_compileRoutine(Toy_Ast* ast); TOY_API void* Toy_compileRoutine(Toy_Ast* ast);
TOY_API void Toy_freeRoutine(Toy_Routine routine);

View File

@@ -38,8 +38,6 @@ int test_bytecode_header(Toy_Bucket* bucket) {
} }
int main() { int main() {
fprintf(stderr, TOY_CC_WARN "WARNING: Bytecode implementation incomplete\n" TOY_CC_RESET);
//run each test set, returning the total errors given //run each test set, returning the total errors given
int total = 0, res = 0; int total = 0, res = 0;

View File

@@ -0,0 +1,47 @@
#include "toy_routine.h"
#include "toy_console_colors.h"
#include <stdio.h>
#include <string.h>
//tests
int test_routine_header(Toy_Bucket* bucket) {
//simple test to ensure the header looks right
{
//setup
Toy_Ast* ast = NULL;
Toy_private_emitAstPass(&bucket, &ast);
//run
void* buffer = Toy_compileRoutine(ast);
int len = ((int*)buffer)[0];
//check
//TODO
//cleanup
TOY_FREE_ARRAY(unsigned char, buffer, len);
}
return 0;
}
int main() {
fprintf(stderr, TOY_CC_WARN "WARNING: Routine tests incomplete\n" TOY_CC_RESET);
//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_routine_header(bucket);
TOY_BUCKET_FREE(bucket);
if (res == 0) {
printf(TOY_CC_NOTICE "All good\n" TOY_CC_RESET);
}
total += res;
}
return total;
}