mirror of
https://github.com/krgamestudios/Toy.git
synced 2026-04-15 14:54:07 +10:00
Strings are needed for the handling of identifiers in the key/value variable storage, so I've got them working first. I used the rope pattern, which seems to be quite an interesting approach. I'll add comparison checks later. Adjusted how buckets are handled in all tests, could've been an issue down the line. Added the build instructions to README.md.
150 lines
3.0 KiB
C
150 lines
3.0 KiB
C
#include "toy_vm.h"
|
|
#include "toy_console_colors.h"
|
|
|
|
#include "toy_lexer.h"
|
|
#include "toy_parser.h"
|
|
#include "toy_bytecode.h"
|
|
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
|
|
//utils
|
|
Toy_Bytecode makeBytecodeFromSource(Toy_Bucket** bucket, const char* source) {
|
|
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);
|
|
|
|
return bc;
|
|
}
|
|
|
|
//tests
|
|
int test_setup_and_teardown(Toy_Bucket** bucket) {
|
|
//basic init & quit
|
|
{
|
|
//generate bytecode for testing
|
|
const char* source = "(1 + 2) * (3 + 4);";
|
|
|
|
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_initVM(&vm);
|
|
Toy_bindVM(&vm, bc.ptr, bc.capacity);
|
|
|
|
//check the header size
|
|
int headerSize = 3 + strlen(TOY_VERSION_BUILD) + 1;
|
|
if (headerSize % 4 != 0) {
|
|
headerSize += 4 - (headerSize % 4); //ceil
|
|
}
|
|
|
|
//check the routine was loaded correctly
|
|
if (
|
|
vm.routine - vm.bc != headerSize ||
|
|
vm.routineSize != 72 ||
|
|
vm.paramCount != 0 ||
|
|
vm.jumpsCount != 0 ||
|
|
vm.dataCount != 0 ||
|
|
vm.subsCount != 0
|
|
)
|
|
{
|
|
fprintf(stderr, TOY_CC_ERROR "ERROR: failed to setup and teadown Toy_VM, source: %s\n" TOY_CC_RESET, source);
|
|
|
|
//cleanup and return
|
|
Toy_freeVM(&vm);
|
|
return -1;
|
|
}
|
|
|
|
//don't run it this time, simply teadown
|
|
Toy_freeVM(&vm);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
//tests
|
|
int test_simple_execution(Toy_Bucket** bucket) {
|
|
//basic init & quit
|
|
{
|
|
//generate bytecode for testing
|
|
const char* source = "(1 + 2) * (3 + 4);";
|
|
|
|
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_initVM(&vm);
|
|
Toy_bindVM(&vm, bc.ptr, bc.capacity);
|
|
|
|
//run
|
|
Toy_runVM(&vm);
|
|
|
|
//check the final state of the stack
|
|
if (vm.stack.count != 1 ||
|
|
TOY_VALUE_IS_INTEGER( Toy_peekStack(&vm.stack) ) != true ||
|
|
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);
|
|
|
|
//cleanup and return
|
|
Toy_freeVM(&vm);
|
|
return -1;
|
|
}
|
|
|
|
//teadown
|
|
Toy_freeVM(&vm);
|
|
}
|
|
|
|
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_setup_and_teardown(&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_simple_execution(&bucket);
|
|
TOY_BUCKET_FREE(bucket);
|
|
if (res == 0) {
|
|
printf(TOY_CC_NOTICE "All good\n" TOY_CC_RESET);
|
|
}
|
|
total += res;
|
|
}
|
|
|
|
return total;
|
|
}
|