mirror of
https://github.com/krgamestudios/Toy.git
synced 2026-04-15 14:54:07 +10:00
Functions are having issues with being copied around, especially between buckets, leading to the scopes getting looped. The program gets stuck in 'incrementRefCount()'. It's past my time limit, so I'll keep working on it tomorrow with a fresh mind. All function stuff is still untested. See #163
214 lines
6.3 KiB
C
214 lines
6.3 KiB
C
#include "toy_scope.h"
|
|
#include "toy_console_colors.h"
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#include "toy_print.h"
|
|
|
|
//utils
|
|
static void incrementRefCount(Toy_Scope* scope) {
|
|
for (Toy_Scope* iter = scope; iter; iter = iter->next) {
|
|
//check for issues
|
|
if (iter->next != NULL && iter->next->refCount == 0) {
|
|
fprintf(stderr, TOY_CC_ERROR "ERROR: Toy_Scope's ancestor has a refcount of 0'\n" TOY_CC_RESET);
|
|
exit(-1);
|
|
}
|
|
|
|
iter->refCount++;
|
|
}
|
|
}
|
|
|
|
static void decrementRefCount(Toy_Scope* scope) {
|
|
for (Toy_Scope* iter = scope; iter; iter = iter->next) {
|
|
iter->refCount--;
|
|
if (iter->refCount == 0 && iter->table != NULL) {
|
|
Toy_freeTable(iter->table);
|
|
iter->table = NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
static Toy_TableEntry* lookupScope(Toy_Scope* scope, Toy_String* key, unsigned int hash, bool recursive) {
|
|
//terminate
|
|
if (scope == NULL) {
|
|
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;
|
|
|
|
while (true) {
|
|
//found the entry
|
|
if (TOY_VALUE_IS_STRING(scope->table->data[probe].key) && Toy_compareStrings(TOY_VALUE_AS_STRING(scope->table->data[probe].key), key) == 0) {
|
|
return &(scope->table->data[probe]);
|
|
}
|
|
|
|
//if its an empty slot (didn't find it here)
|
|
if (TOY_VALUE_IS_NULL(scope->table->data[probe].key)) {
|
|
return recursive ? lookupScope(scope->next, key, hash, recursive) : NULL;
|
|
}
|
|
|
|
//adjust and continue
|
|
probe = (probe + 1) % scope->table->capacity;
|
|
}
|
|
}
|
|
|
|
//exposed functions
|
|
Toy_Scope* Toy_pushScope(Toy_Bucket** bucketHandle, Toy_Scope* scope) {
|
|
Toy_Scope* newScope = (Toy_Scope*)Toy_partitionBucket(bucketHandle, sizeof(Toy_Scope));
|
|
|
|
newScope->next = scope;
|
|
newScope->table = Toy_allocateTable();
|
|
newScope->refCount = 0;
|
|
|
|
incrementRefCount(newScope);
|
|
|
|
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;
|
|
}
|
|
|
|
decrementRefCount(scope);
|
|
return scope->next;
|
|
}
|
|
|
|
Toy_Scope* Toy_deepCopyScope(Toy_Bucket** bucketHandle, Toy_Scope* scope) {
|
|
//copy/pasted from pushScope, so I can allocate the table manually
|
|
Toy_Scope* newScope = (Toy_Scope*)Toy_partitionBucket(bucketHandle, sizeof(Toy_Scope));
|
|
|
|
newScope->next = scope->next;
|
|
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;
|
|
}
|
|
|
|
void Toy_declareScope(Toy_Scope* scope, Toy_String* key, Toy_Value value) {
|
|
if (key->info.type != TOY_STRING_NAME) {
|
|
fprintf(stderr, TOY_CC_ERROR "ERROR: Toy_Scope only allows name strings as keys\n" TOY_CC_RESET);
|
|
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) {
|
|
char buffer[key->info.length + 256];
|
|
sprintf(buffer, "Can't redefine a variable: %s", key->name.data);
|
|
Toy_error(buffer);
|
|
return;
|
|
}
|
|
|
|
//type check
|
|
Toy_ValueType kt = Toy_getNameStringVarType(key);
|
|
if (kt != TOY_VALUE_ANY && value.type != TOY_VALUE_NULL && kt != value.type && value.type != TOY_VALUE_REFERENCE) {
|
|
char buffer[key->info.length + 256];
|
|
sprintf(buffer, "Incorrect value type in declaration of '%s' (expected %s, got %s)", key->name.data, Toy_private_getValueTypeAsCString(kt), Toy_private_getValueTypeAsCString(value.type));
|
|
Toy_error(buffer);
|
|
return;
|
|
}
|
|
|
|
Toy_insertTable(&scope->table, TOY_VALUE_FROM_STRING(Toy_copyString(key)), value);
|
|
}
|
|
|
|
void Toy_assignScope(Toy_Scope* scope, Toy_String* key, Toy_Value value) {
|
|
if (key->info.type != TOY_STRING_NAME) {
|
|
fprintf(stderr, TOY_CC_ERROR "ERROR: Toy_Scope only allows name strings as keys\n" TOY_CC_RESET);
|
|
exit(-1);
|
|
}
|
|
|
|
Toy_TableEntry* entryPtr = lookupScope(scope, key, Toy_hashString(key), true);
|
|
|
|
if (entryPtr == NULL) {
|
|
char buffer[key->info.length + 256];
|
|
sprintf(buffer, "Undefined variable: %s\n", key->name.data);
|
|
Toy_error(buffer);
|
|
return;
|
|
}
|
|
|
|
//type check
|
|
Toy_ValueType kt = Toy_getNameStringVarType( TOY_VALUE_AS_STRING(entryPtr->key) );
|
|
if (kt != TOY_VALUE_ANY && value.type != TOY_VALUE_NULL && kt != value.type && value.type != TOY_VALUE_REFERENCE) {
|
|
char buffer[key->info.length + 256];
|
|
sprintf(buffer, "Incorrect value type in assignment of '%s' (expected %s, got %s)", key->name.data, Toy_private_getValueTypeAsCString(kt), Toy_private_getValueTypeAsCString(value.type));
|
|
Toy_error(buffer);
|
|
return;
|
|
}
|
|
|
|
//constness check
|
|
if (Toy_getNameStringVarConstant( TOY_VALUE_AS_STRING(entryPtr->key) )) {
|
|
char buffer[key->info.length + 256];
|
|
sprintf(buffer, "Can't reassign to constant variable %s", key->name.data);
|
|
Toy_error(buffer);
|
|
return;
|
|
}
|
|
|
|
entryPtr->value = value;
|
|
}
|
|
|
|
Toy_Value* Toy_accessScopeAsPointer(Toy_Scope* scope, Toy_String* key) {
|
|
if (key->info.type != TOY_STRING_NAME) {
|
|
fprintf(stderr, TOY_CC_ERROR "ERROR: Toy_Scope only allows name strings as keys\n" TOY_CC_RESET);
|
|
exit(-1);
|
|
}
|
|
|
|
Toy_TableEntry* entryPtr = lookupScope(scope, key, Toy_hashString(key), true);
|
|
|
|
if (entryPtr == NULL) {
|
|
char buffer[key->info.length + 256];
|
|
sprintf(buffer, "Undefined variable: %s\n", key->name.data);
|
|
Toy_error(buffer);
|
|
return NULL;
|
|
}
|
|
|
|
return &(entryPtr->value);
|
|
}
|
|
|
|
bool Toy_isDeclaredScope(Toy_Scope* scope, Toy_String* key) {
|
|
if (key->info.type != TOY_STRING_NAME) {
|
|
fprintf(stderr, TOY_CC_ERROR "ERROR: Toy_Scope only allows name strings as keys\n" TOY_CC_RESET);
|
|
exit(-1);
|
|
}
|
|
|
|
Toy_TableEntry* entryPtr = lookupScope(scope, key, Toy_hashString(key), true);
|
|
|
|
return entryPtr != NULL;
|
|
}
|