mirror of
https://github.com/krgamestudios/Toy.git
synced 2026-04-15 14:54:07 +10:00
Implemented and tested variable declaration
Assignment, etc. is still to come, as are types.
This commit is contained in:
@@ -2,6 +2,7 @@
|
||||
#include "toy_console_colors.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
int test_sizeof_ast_64bit() {
|
||||
#define TEST_SIZEOF(type, size) \
|
||||
@@ -16,6 +17,7 @@ int test_sizeof_ast_64bit() {
|
||||
//run for each type
|
||||
TEST_SIZEOF(Toy_AstType, 4);
|
||||
TEST_SIZEOF(Toy_AstBlock, 32);
|
||||
TEST_SIZEOF(Toy_AstVarDeclare, 24);
|
||||
TEST_SIZEOF(Toy_AstValue, 24);
|
||||
TEST_SIZEOF(Toy_AstUnary, 16);
|
||||
TEST_SIZEOF(Toy_AstBinary, 24);
|
||||
@@ -44,6 +46,7 @@ int test_sizeof_ast_32bit() {
|
||||
//run for each type
|
||||
TEST_SIZEOF(Toy_AstType, 4);
|
||||
TEST_SIZEOF(Toy_AstBlock, 16);
|
||||
TEST_SIZEOF(Toy_AstVarDeclare, 12);
|
||||
TEST_SIZEOF(Toy_AstValue, 12);
|
||||
TEST_SIZEOF(Toy_AstUnary, 12);
|
||||
TEST_SIZEOF(Toy_AstBinary, 16);
|
||||
@@ -218,6 +221,34 @@ int test_type_emission(Toy_Bucket** bucketHandle) {
|
||||
}
|
||||
}
|
||||
|
||||
//emit var declare
|
||||
{
|
||||
//build the AST
|
||||
Toy_Ast* ast = NULL;
|
||||
Toy_String* name = Toy_createNameStringLength(bucketHandle, "foobar", 6, TOY_VALUE_NULL);
|
||||
|
||||
Toy_private_emitAstVariableDeclaration(bucketHandle, &ast, name, NULL);
|
||||
|
||||
//check if it worked
|
||||
if (
|
||||
ast == NULL ||
|
||||
ast->type != TOY_AST_VAR_DECLARE ||
|
||||
|
||||
ast->varDeclare.name == NULL ||
|
||||
ast->varDeclare.name->type != TOY_STRING_NAME ||
|
||||
strcmp(ast->varDeclare.name->as.name.data, "foobar") != 0 ||
|
||||
|
||||
ast->varDeclare.expr != NULL)
|
||||
{
|
||||
fprintf(stderr, TOY_CC_ERROR "ERROR: failed to emit a var declare as 'Toy_Ast', state unknown\n" TOY_CC_RESET);
|
||||
Toy_freeString(name);
|
||||
return -1;
|
||||
}
|
||||
|
||||
//cleanup
|
||||
Toy_freeString(name);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -574,6 +574,16 @@ int main() {
|
||||
total += res;
|
||||
}
|
||||
|
||||
// { //TODO: test_parser.c: test_var_declare()
|
||||
// Toy_Bucket* bucket = Toy_allocateBucket(TOY_BUCKET_IDEAL);
|
||||
// res = test_var_declare(&bucket);
|
||||
// Toy_freeBucket(&bucket);
|
||||
// if (res == 0) {
|
||||
// printf(TOY_CC_NOTICE "All good\n" TOY_CC_RESET);
|
||||
// }
|
||||
// total += res;
|
||||
// }
|
||||
|
||||
{
|
||||
Toy_Bucket* bucket = Toy_allocateBucket(TOY_BUCKET_IDEAL);
|
||||
res = test_values(&bucket);
|
||||
|
||||
@@ -777,6 +777,114 @@ int test_routine_keywords(Toy_Bucket** bucketHandle) {
|
||||
free(buffer);
|
||||
}
|
||||
|
||||
//var declare
|
||||
{
|
||||
//setup
|
||||
const char* source = "var foobar = 42;";
|
||||
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* header = (int*)buffer;
|
||||
|
||||
if (header[0] != 64 || //total size
|
||||
header[1] != 0 || //param size
|
||||
header[2] != 4 || //jumps size
|
||||
header[3] != 8 || //data size
|
||||
header[4] != 0 || //subs size
|
||||
|
||||
// header[??] != ?? || //params address
|
||||
header[5] != 32 || //code address
|
||||
header[6] != 52 || //jumps address
|
||||
header[7] != 56 || //data address
|
||||
// header[??] != ?? || //subs address
|
||||
|
||||
false)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
void* code = buffer + 32; //8 values in the header, each 4 bytes
|
||||
|
||||
//check code
|
||||
if (
|
||||
//code start
|
||||
*((unsigned char*)(code + 0)) != TOY_OPCODE_READ ||
|
||||
*((unsigned char*)(code + 1)) != TOY_VALUE_INTEGER ||
|
||||
*((unsigned char*)(code + 2)) != 0 ||
|
||||
*((unsigned char*)(code + 3)) != 0 ||
|
||||
|
||||
*(int*)(code + 4) != 42 ||
|
||||
|
||||
*((unsigned char*)(code + 8)) != TOY_OPCODE_DECLARE ||
|
||||
*((unsigned char*)(code + 9)) != TOY_VALUE_NULL || //NOTE: will change in future
|
||||
*((unsigned char*)(code + 10)) != 6 || //strlen
|
||||
*((unsigned char*)(code + 11)) != 0 ||
|
||||
|
||||
*(unsigned int*)(code + 12) != 0 || //the jump index
|
||||
|
||||
*((unsigned char*)(code + 16)) != TOY_OPCODE_RETURN ||
|
||||
*((unsigned char*)(code + 17)) != 0 ||
|
||||
*((unsigned char*)(code + 18)) != 0 ||
|
||||
*((unsigned char*)(code + 19)) != 0 ||
|
||||
|
||||
false)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
void* jumps = code + 20;
|
||||
|
||||
//check jumps
|
||||
if (
|
||||
//code start
|
||||
*(unsigned int*)(jumps + 0) != 0 || //the address relative to the start of the data section
|
||||
|
||||
false)
|
||||
{
|
||||
fprintf(stderr, TOY_CC_ERROR "ERROR: failed to produce the expected routine jumps, source: %s\n" TOY_CC_RESET, source);
|
||||
|
||||
//cleanup and return
|
||||
free(buffer);
|
||||
return -1;
|
||||
}
|
||||
|
||||
void* data = jumps + 4;
|
||||
|
||||
//check data
|
||||
if (
|
||||
//data start (the end of the data is padded to the nearest multiple of 4)
|
||||
strcmp( ((char*)data) + ((unsigned int*)jumps)[0], "foobar" ) != 0 ||
|
||||
|
||||
false)
|
||||
{
|
||||
fprintf(stderr, TOY_CC_ERROR "ERROR: failed to produce the expected routine data, source: %s\n" TOY_CC_RESET, source);
|
||||
|
||||
//cleanup and return
|
||||
free(buffer);
|
||||
return -1;
|
||||
}
|
||||
|
||||
//cleanup
|
||||
free(buffer);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -304,8 +304,8 @@ int test_scope_elements() {
|
||||
Toy_Bucket* bucket = Toy_allocateBucket(TOY_BUCKET_IDEAL);
|
||||
Toy_Scope* scope = Toy_pushScope(&bucket, NULL);
|
||||
|
||||
Toy_String* hello1 = Toy_createNameString(&bucket, "hello", TOY_VALUE_NULL);
|
||||
Toy_String* hello2 = Toy_createNameString(&bucket, "hello", TOY_VALUE_NULL);
|
||||
Toy_String* hello1 = Toy_createNameStringLength(&bucket, "hello", 5, TOY_VALUE_NULL);
|
||||
Toy_String* hello2 = Toy_createNameStringLength(&bucket, "hello", 5, TOY_VALUE_NULL);
|
||||
|
||||
//check nothing is here
|
||||
if (Toy_isDeclaredScope(scope, hello2)) {
|
||||
@@ -389,7 +389,7 @@ int test_scope_elements() {
|
||||
Toy_Bucket* bucket = Toy_allocateBucket(TOY_BUCKET_IDEAL);
|
||||
Toy_Scope* scope = Toy_pushScope(&bucket, NULL);
|
||||
|
||||
Toy_String* hello = Toy_createNameString(&bucket, "hello", TOY_VALUE_NULL);
|
||||
Toy_String* hello = Toy_createNameStringLength(&bucket, "hello", 5, TOY_VALUE_NULL);
|
||||
|
||||
//declare and push
|
||||
Toy_declareScope(scope, hello, TOY_VALUE_FROM_INTEGER(42));
|
||||
|
||||
@@ -106,7 +106,7 @@ int test_string_allocation() {
|
||||
Toy_Bucket* bucket = Toy_allocateBucket(1024);
|
||||
|
||||
const char* cstring = "Hello world";
|
||||
Toy_String* str = Toy_createNameString(&bucket, cstring, TOY_VALUE_NULL);
|
||||
Toy_String* str = Toy_createNameStringLength(&bucket, cstring, strlen(cstring), TOY_VALUE_NULL);
|
||||
|
||||
//shallow and deep
|
||||
Toy_String* shallow = Toy_copyString(str);
|
||||
@@ -652,9 +652,9 @@ int test_string_equality() {
|
||||
{
|
||||
//setup
|
||||
Toy_Bucket* bucket = Toy_allocateBucket(1024);
|
||||
Toy_String* helloWorldOne = Toy_createNameString(&bucket, "Hello world", TOY_VALUE_NULL);
|
||||
Toy_String* helloWorldTwo = Toy_createNameString(&bucket, "Hello world", TOY_VALUE_NULL);
|
||||
Toy_String* helloEveryone = Toy_createNameString(&bucket, "Hello everyone", TOY_VALUE_NULL); //TODO: compare types?
|
||||
Toy_String* helloWorldOne = Toy_createNameStringLength(&bucket, "Hello world", strlen("Hello world"), TOY_VALUE_NULL);
|
||||
Toy_String* helloWorldTwo = Toy_createNameStringLength(&bucket, "Hello world", strlen("Hello world"), TOY_VALUE_NULL);
|
||||
Toy_String* helloEveryone = Toy_createNameStringLength(&bucket, "Hello everyone", strlen("Hello everyone"), TOY_VALUE_NULL); //TODO: compare types?
|
||||
|
||||
int result = 0; //for print the errors
|
||||
|
||||
|
||||
@@ -305,6 +305,57 @@ int test_keywords(Toy_Bucket** bucketHandle) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int test_scope(Toy_Bucket** bucketHandle) {
|
||||
//test execution
|
||||
{
|
||||
//generate bytecode for testing
|
||||
const char* source = "var foobar = 42;";
|
||||
|
||||
Toy_Lexer lexer;
|
||||
Toy_bindLexer(&lexer, source);
|
||||
|
||||
Toy_Parser parser;
|
||||
Toy_bindParser(&parser, &lexer);
|
||||
|
||||
Toy_Ast* ast = Toy_scanParser(bucketHandle, &parser);
|
||||
|
||||
Toy_Bytecode bc = Toy_compileBytecode(ast);
|
||||
|
||||
//run the setup
|
||||
Toy_VM vm;
|
||||
Toy_initVM(&vm);
|
||||
Toy_bindVM(&vm, bc.ptr);
|
||||
|
||||
//run
|
||||
Toy_runVM(&vm);
|
||||
|
||||
//check the final state of the stack
|
||||
Toy_String* key = Toy_createNameStringLength(bucketHandle, "foobar", 6, TOY_VALUE_NULL);
|
||||
|
||||
if (vm.stack == NULL ||
|
||||
vm.stack->count != 0 ||
|
||||
|
||||
vm.scope == NULL ||
|
||||
Toy_isDeclaredScope(vm.scope, key) == false ||
|
||||
TOY_VALUE_IS_INTEGER(Toy_accessScope(vm.scope, key)) != true ||
|
||||
TOY_VALUE_AS_INTEGER(Toy_accessScope(vm.scope, key)) != 42
|
||||
|
||||
)
|
||||
{
|
||||
fprintf(stderr, TOY_CC_ERROR "ERROR: Unexpected result in 'Toy_VM' when testing scope, source: %s\n" TOY_CC_RESET, source);
|
||||
|
||||
//cleanup and return
|
||||
Toy_freeVM(&vm);
|
||||
return -1;
|
||||
}
|
||||
|
||||
//teadown
|
||||
Toy_freeVM(&vm);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int test_vm_reuse(Toy_Bucket** bucketHandle) {
|
||||
//run code in the same vm multiple times
|
||||
{
|
||||
@@ -424,6 +475,16 @@ int main() {
|
||||
total += res;
|
||||
}
|
||||
|
||||
{
|
||||
Toy_Bucket* bucket = Toy_allocateBucket(TOY_BUCKET_IDEAL);
|
||||
res = test_scope(&bucket);
|
||||
Toy_freeBucket(&bucket);
|
||||
if (res == 0) {
|
||||
printf(TOY_CC_NOTICE "All good\n" TOY_CC_RESET);
|
||||
}
|
||||
total += res;
|
||||
}
|
||||
|
||||
{
|
||||
Toy_Bucket* bucket = Toy_allocateBucket(TOY_BUCKET_IDEAL);
|
||||
res = test_vm_reuse(&bucket);
|
||||
|
||||
Reference in New Issue
Block a user