diff --git a/scripts/funky.toy b/scripts/funky.toy index c54f44c..9b3768e 100644 --- a/scripts/funky.toy +++ b/scripts/funky.toy @@ -1,5 +1,5 @@ fn name(foobar: bool const) { - //return 42; + print foobar; } \ No newline at end of file diff --git a/source/toy_function.c b/source/toy_function.c new file mode 100644 index 0000000..9004757 --- /dev/null +++ b/source/toy_function.c @@ -0,0 +1,10 @@ +#include "toy_function.h" + +Toy_Function* Toy_createModuleFunction(Toy_Bucket** bucketHandle, Toy_Module module) { + Toy_Function* fn = (Toy_Function*)Toy_partitionBucket(bucketHandle, sizeof(Toy_Function)); + + fn->type = TOY_FUNCTION_MODULE; + fn->module.module = module; + + return fn; +} \ No newline at end of file diff --git a/source/toy_function.h b/source/toy_function.h new file mode 100644 index 0000000..76ff756 --- /dev/null +++ b/source/toy_function.h @@ -0,0 +1,28 @@ +#pragma once + +#include "toy_common.h" + +#include "toy_module.h" + +typedef enum Toy_FunctionType { + TOY_FUNCTION_MODULE, + TOY_FUNCTION_NATIVE, +} Toy_FunctionType; + +typedef union Toy_FunctionModule { + Toy_FunctionType type; + Toy_Module module; +} Toy_FunctionModule; + +typedef union Toy_FunctionNative { + Toy_FunctionType type; + void* native; //TODO: replace with the native function pointer +} Toy_FunctionNative; + +typedef union Toy_Function_t { + Toy_FunctionType type; + Toy_FunctionModule module; + Toy_FunctionNative native; +} Toy_Function; + +TOY_API Toy_Function* Toy_createModuleFunction(Toy_Bucket** bucketHandle, Toy_Module module); diff --git a/source/toy_module.c b/source/toy_module.c index 950d147..7189933 100644 --- a/source/toy_module.c +++ b/source/toy_module.c @@ -14,7 +14,7 @@ Toy_Module Toy_parseModule(unsigned char* ptr) { Toy_Module module; - module.scopePtr = NULL; + module.parentScope = NULL; module.code = ptr; diff --git a/source/toy_module.h b/source/toy_module.h index 3899644..82033a0 100644 --- a/source/toy_module.h +++ b/source/toy_module.h @@ -6,7 +6,7 @@ //runtime module info typedef struct Toy_Module { //closure support - points to parent scope - Toy_Scope* scopePtr; + Toy_Scope* parentScope; unsigned char* code; diff --git a/source/toy_scope.c b/source/toy_scope.c index 77aa8f8..8046b32 100644 --- a/source/toy_scope.c +++ b/source/toy_scope.c @@ -30,6 +30,11 @@ static Toy_TableEntry* lookupScope(Toy_Scope* scope, Toy_String* key, unsigned i return NULL; } + //continue after a dummy + if (scope->table == NULL) { + return recursive ? lookupScope(scope->next, key, hash, recursive) : NULL; + } + //copy and modify the code from Toy_lookupTable, so it can behave slightly differently unsigned int probe = hash % scope->table->capacity; @@ -62,6 +67,18 @@ Toy_Scope* Toy_pushScope(Toy_Bucket** bucketHandle, Toy_Scope* scope) { return newScope; } +Toy_Scope* Toy_private_pushDummyScope(Toy_Bucket** bucketHandle, Toy_Scope* scope) { + Toy_Scope* newScope = (Toy_Scope*)Toy_partitionBucket(bucketHandle, sizeof(Toy_Scope)); + + newScope->next = scope; + newScope->table = NULL; + newScope->refCount = 0; + + incrementRefCount(newScope); + + return newScope; +} + Toy_Scope* Toy_popScope(Toy_Scope* scope) { if (scope == NULL) { return NULL; @@ -76,15 +93,17 @@ Toy_Scope* Toy_deepCopyScope(Toy_Bucket** bucketHandle, Toy_Scope* scope) { Toy_Scope* newScope = (Toy_Scope*)Toy_partitionBucket(bucketHandle, sizeof(Toy_Scope)); newScope->next = scope->next; - newScope->table = Toy_private_adjustTableCapacity(NULL, scope->table->capacity); + newScope->table = scope->table != NULL ? Toy_private_adjustTableCapacity(NULL, scope->table->capacity) : NULL; newScope->refCount = 0; incrementRefCount(newScope); - //forcibly copy the contents - for (unsigned int i = 0; i < scope->table->capacity; i++) { - if (!TOY_VALUE_IS_NULL(scope->table->data[i].key)) { - Toy_insertTable(&newScope->table, Toy_copyValue(scope->table->data[i].key), Toy_copyValue(scope->table->data[i].value)); + if (newScope->table != NULL) { + //forcibly copy the contents + for (unsigned int i = 0; i < scope->table->capacity; i++) { + if (!TOY_VALUE_IS_NULL(scope->table->data[i].key)) { + Toy_insertTable(&newScope->table, Toy_copyValue(scope->table->data[i].key), Toy_copyValue(scope->table->data[i].value)); + } } } @@ -97,6 +116,11 @@ void Toy_declareScope(Toy_Scope* scope, Toy_String* key, Toy_Value value) { exit(-1); } + if (scope->table == NULL) { + fprintf(stderr, TOY_CC_ERROR "ERROR: Can't declare in a dummy scope\n" TOY_CC_RESET); + exit(-1); + } + Toy_TableEntry* entryPtr = lookupScope(scope, key, Toy_hashString(key), false); if (entryPtr != NULL) { diff --git a/source/toy_scope.h b/source/toy_scope.h index 93e2f4a..ff88f7f 100644 --- a/source/toy_scope.h +++ b/source/toy_scope.h @@ -17,6 +17,7 @@ typedef struct Toy_Scope { //handle deep scopes - the scope is stored in the bucket, not the table TOY_API Toy_Scope* Toy_pushScope(Toy_Bucket** bucketHandle, Toy_Scope* scope); TOY_API Toy_Scope* Toy_popScope(Toy_Scope* scope); +TOY_API Toy_Scope* Toy_private_pushDummyScope(Toy_Bucket** bucketHandle, Toy_Scope* scope); //doesn't delcare a table for storage TOY_API Toy_Scope* Toy_deepCopyScope(Toy_Bucket** bucketHandle, Toy_Scope* scope); diff --git a/source/toy_value.c b/source/toy_value.c index f884106..57acdbc 100644 --- a/source/toy_value.c +++ b/source/toy_value.c @@ -80,7 +80,7 @@ unsigned int Toy_hashValue(Toy_Value value) { case TOY_VALUE_ANY: case TOY_VALUE_REFERENCE: case TOY_VALUE_UNKNOWN: - fprintf(stderr, TOY_CC_ERROR "ERROR: Can't hash an unknown value type, exiting\n" TOY_CC_RESET); + fprintf(stderr, TOY_CC_ERROR "ERROR: Can't hash an unknown value type (%d), exiting\n" TOY_CC_RESET, (int)value.type); exit(-1); } @@ -134,6 +134,8 @@ Toy_Value Toy_copyValue(Toy_Value value) { return TOY_VALUE_FROM_TABLE(result); } case TOY_VALUE_FUNCTION: + return value; + case TOY_VALUE_OPAQUE: case TOY_VALUE_ANY: case TOY_VALUE_REFERENCE: @@ -172,6 +174,9 @@ void Toy_freeValue(Toy_Value value) { return; case TOY_VALUE_FUNCTION: + //not sure this needs to be freed + return; + case TOY_VALUE_OPAQUE: case TOY_VALUE_ANY: case TOY_VALUE_UNKNOWN: @@ -304,6 +309,8 @@ bool Toy_checkValuesAreEqual(Toy_Value left, Toy_Value right) { } case TOY_VALUE_FUNCTION: + return false; //URGENT: check this + case TOY_VALUE_OPAQUE: case TOY_VALUE_ANY: case TOY_VALUE_REFERENCE: @@ -343,6 +350,9 @@ bool Toy_checkValuesAreComparable(Toy_Value left, Toy_Value right) { return false; case TOY_VALUE_FUNCTION: + //nothing is comparable with a function + return false; + case TOY_VALUE_OPAQUE: case TOY_VALUE_ANY: case TOY_VALUE_REFERENCE: @@ -398,6 +408,8 @@ int Toy_compareValues(Toy_Value left, Toy_Value right) { break; case TOY_VALUE_FUNCTION: + break; + case TOY_VALUE_OPAQUE: case TOY_VALUE_ANY: case TOY_VALUE_REFERENCE: @@ -608,7 +620,8 @@ Toy_String* Toy_stringifyValue(Toy_Bucket** bucketHandle, Toy_Value value) { return string; } - case TOY_VALUE_FUNCTION: + case TOY_VALUE_FUNCTION: //URGENT: check this + case TOY_VALUE_OPAQUE: case TOY_VALUE_ANY: case TOY_VALUE_REFERENCE: diff --git a/source/toy_value.h b/source/toy_value.h index 272eeb3..8615f96 100644 --- a/source/toy_value.h +++ b/source/toy_value.h @@ -8,6 +8,7 @@ struct Toy_Bucket; union Toy_String_t; struct Toy_Array; struct Toy_Table; +union Toy_Function_t; typedef enum Toy_ValueType { TOY_VALUE_NULL, @@ -35,6 +36,7 @@ typedef struct Toy_Value { //32 | 64 BITNESS union Toy_String_t* string; //4 | 8 struct Toy_Array* array; //4 | 8 struct Toy_Table* table; //4 | 8 + union Toy_Function_t* function;//4 | 8 //TODO: more types go here } as; //4 | 8 @@ -60,6 +62,7 @@ typedef struct Toy_Value { //32 | 64 BITNESS #define TOY_VALUE_AS_STRING(value) (Toy_unwrapValue(value).as.string) #define TOY_VALUE_AS_ARRAY(value) (Toy_unwrapValue(value).as.array) #define TOY_VALUE_AS_TABLE(value) (Toy_unwrapValue(value).as.table) +#define TOY_VALUE_AS_FUNCTION(value) (Toy_unwrapValue(value).as.function) //TODO: more #define TOY_VALUE_FROM_NULL() ((Toy_Value){{ .integer = 0 }, TOY_VALUE_NULL}) @@ -69,6 +72,7 @@ typedef struct Toy_Value { //32 | 64 BITNESS #define TOY_VALUE_FROM_STRING(value) ((Toy_Value){{ .string = value }, TOY_VALUE_STRING}) #define TOY_VALUE_FROM_ARRAY(value) ((Toy_Value){{ .array = value }, TOY_VALUE_ARRAY}) #define TOY_VALUE_FROM_TABLE(value) ((Toy_Value){{ .table = value }, TOY_VALUE_TABLE}) +#define TOY_VALUE_FROM_FUNCTION(value) ((Toy_Value){{ .function = value }, TOY_VALUE_FUNCTION}) //TODO: more #define TOY_REFERENCE_FROM_POINTER(ptr) ((Toy_Value){{ .reference = ptr }, TOY_VALUE_REFERENCE}) diff --git a/source/toy_vm.c b/source/toy_vm.c index c372563..a1a2828 100644 --- a/source/toy_vm.c +++ b/source/toy_vm.c @@ -73,12 +73,12 @@ static void processRead(Toy_VM* vm) { //build a string from the data section if (stringType == TOY_STRING_LEAF) { - value = TOY_VALUE_FROM_STRING(Toy_createString(&vm->stringBucket, cstring)); + value = TOY_VALUE_FROM_STRING(Toy_createString(&vm->literalBucket, cstring)); } else if (stringType == TOY_STRING_NAME) { Toy_ValueType valueType = TOY_VALUE_UNKNOWN; - value = TOY_VALUE_FROM_STRING(Toy_createNameStringLength(&vm->stringBucket, cstring, len, valueType, false)); + value = TOY_VALUE_FROM_STRING(Toy_createNameStringLength(&vm->literalBucket, cstring, len, valueType, false)); } else { Toy_error("Invalid string type found in opcode read"); @@ -155,8 +155,20 @@ static void processRead(Toy_VM* vm) { } case TOY_VALUE_FUNCTION: { - // - // break; + // unsigned int paramCount = (unsigned int)READ_BYTE(vm); //unused + + fixAlignment(vm); + + unsigned int addr = (unsigned int)READ_INT(vm); + + Toy_Module module = Toy_parseModule(vm->code + vm->subsAddr + addr); + module.parentScope = Toy_private_pushDummyScope(&vm->scopeBucket, vm->scope); + + //create and push the function value + Toy_Function* function = Toy_createModuleFunction(&vm->literalBucket, module); + value = TOY_VALUE_FROM_FUNCTION(function); + + break; } case TOY_VALUE_OPAQUE: { @@ -198,7 +210,7 @@ static void processDeclare(Toy_VM* vm) { char* cstring = (char*)(vm->code + vm->dataAddr + jump); //build the name string - Toy_String* name = Toy_createNameStringLength(&vm->stringBucket, cstring, len, type, constant); + Toy_String* name = Toy_createNameStringLength(&vm->literalBucket, cstring, len, type, constant); //get the value Toy_Value value = Toy_popStack(&vm->stack); @@ -607,7 +619,7 @@ static void processAssert(Toy_VM* vm) { //determine the args if (count == 1) { - message = TOY_VALUE_FROM_STRING(Toy_createString(&vm->stringBucket, "assertion failed")); //TODO: needs a better default message + message = TOY_VALUE_FROM_STRING(Toy_createString(&vm->literalBucket, "assertion failed")); //TODO: needs a better default message value = Toy_popStack(&vm->stack); } else if (count == 2) { @@ -622,7 +634,7 @@ static void processAssert(Toy_VM* vm) { //do the check if (TOY_VALUE_IS_NULL(value) || Toy_checkValueIsTruthy(value) != true) { //on a failure, print the message - Toy_String* string = Toy_stringifyValue(&vm->stringBucket, message); + Toy_String* string = Toy_stringifyValue(&vm->literalBucket, message); char* buffer = Toy_getStringRawBuffer(string); Toy_assertFailure(buffer); @@ -640,7 +652,7 @@ static void processAssert(Toy_VM* vm) { static void processPrint(Toy_VM* vm) { //print the value on top of the stack, popping it Toy_Value value = Toy_popStack(&vm->stack); - Toy_String* string = Toy_stringifyValue(&vm->stringBucket, value); + Toy_String* string = Toy_stringifyValue(&vm->literalBucket, value); char* buffer = Toy_getStringRawBuffer(string); //TODO: check string type to skip this call Toy_print(buffer); @@ -663,7 +675,7 @@ static void processConcat(Toy_VM* vm) { } //all good - Toy_String* result = Toy_concatStrings(&vm->stringBucket, TOY_VALUE_AS_STRING(left), TOY_VALUE_AS_STRING(right)); + Toy_String* result = Toy_concatStrings(&vm->literalBucket, TOY_VALUE_AS_STRING(left), TOY_VALUE_AS_STRING(right)); Toy_pushStack(&vm->stack, TOY_VALUE_FROM_STRING(result)); } @@ -731,11 +743,11 @@ static void processIndex(Toy_VM* vm) { //extract cstring, based on type if (str->info.type == TOY_STRING_LEAF) { const char* cstr = str->leaf.data; - result = Toy_createStringLength(&vm->stringBucket, cstr + i, l); + result = Toy_createStringLength(&vm->literalBucket, cstr + i, l); } else if (str->info.type == TOY_STRING_NODE) { char* cstr = Toy_getStringRawBuffer(str); - result = Toy_createStringLength(&vm->stringBucket, cstr + i, l); + result = Toy_createStringLength(&vm->literalBucket, cstr + i, l); free(cstr); } else { @@ -978,7 +990,7 @@ void Toy_initVM(Toy_VM* vm) { //create persistent memory vm->scope = NULL; vm->stack = Toy_allocateStack(); - vm->stringBucket = Toy_allocateBucket(TOY_BUCKET_IDEAL); + vm->literalBucket = Toy_allocateBucket(TOY_BUCKET_IDEAL); vm->scopeBucket = Toy_allocateBucket(TOY_BUCKET_IDEAL); Toy_resetVM(vm, true); @@ -988,7 +1000,7 @@ void Toy_inheritVM(Toy_VM* vm, Toy_VM* parent) { //inherent persistent memory vm->scope = NULL; vm->stack = Toy_allocateStack(); - vm->stringBucket = parent->stringBucket; + vm->literalBucket = parent->literalBucket; vm->scopeBucket = parent->scopeBucket; //TODO: parent bucket pointers are updated after function calls @@ -1011,7 +1023,7 @@ void Toy_bindVM(Toy_VM* vm, Toy_Module* module, bool preserveScope) { vm->subsAddr = module->subsAddr; if (preserveScope == false) { - vm->scope = Toy_pushScope(&vm->scopeBucket, module->scopePtr); + vm->scope = Toy_pushScope(&vm->scopeBucket, module->parentScope); } } @@ -1037,6 +1049,6 @@ void Toy_freeVM(Toy_VM* vm) { //clear the persistent memory Toy_freeStack(vm->stack); - Toy_freeBucket(&vm->stringBucket); + Toy_freeBucket(&vm->literalBucket); Toy_freeBucket(&vm->scopeBucket); } diff --git a/source/toy_vm.h b/source/toy_vm.h index c2418a3..2e1d6fe 100644 --- a/source/toy_vm.h +++ b/source/toy_vm.h @@ -11,6 +11,7 @@ #include "toy_stack.h" #include "toy_array.h" #include "toy_table.h" +#include "toy_function.h" typedef struct Toy_VM { //raw instructions to be executed @@ -38,7 +39,7 @@ typedef struct Toy_VM { Toy_Stack* stack; //easy access to memory - Toy_Bucket* stringBucket; //stores the string literals + Toy_Bucket* literalBucket; //stores the value literals (strings, functions, etc.) Toy_Bucket* scopeBucket; //stores the scope instances TODO: is this separation needed? } Toy_VM;