mirror of
https://github.com/krgamestudios/Toy.git
synced 2026-04-15 14:54:07 +10:00
WIP, Functions are declared, still not called
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
|
||||
|
||||
fn name(foobar: bool const) {
|
||||
//return 42;
|
||||
print foobar;
|
||||
}
|
||||
10
source/toy_function.c
Normal file
10
source/toy_function.c
Normal file
@@ -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;
|
||||
}
|
||||
28
source/toy_function.h
Normal file
28
source/toy_function.h
Normal file
@@ -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);
|
||||
@@ -14,7 +14,7 @@ Toy_Module Toy_parseModule(unsigned char* ptr) {
|
||||
|
||||
Toy_Module module;
|
||||
|
||||
module.scopePtr = NULL;
|
||||
module.parentScope = NULL;
|
||||
|
||||
module.code = ptr;
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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,17 +93,19 @@ 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);
|
||||
|
||||
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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return newScope;
|
||||
}
|
||||
@@ -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) {
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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})
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user