X-Git-Url: https://code.kerkeslager.com/?a=blobdiff_plain;f=templates%2Fprogram.c;h=c20fd458a13a65ded16322dd3b094c54aa693210;hb=ec54804ff2c217e4f6be0220049142e300681093;hp=274aa33aaa795a02e4b8e0188526fa4b6774a26f;hpb=fd918259dd949c8fababcf49ced426ab3c39da38;p=fur diff --git a/templates/program.c b/templates/program.c index 274aa33..c20fd45 100644 --- a/templates/program.c +++ b/templates/program.c @@ -25,6 +25,15 @@ struct String char* characters; }; +#define MAX_SYMBOL_LENGTH {{ MAX_SYMBOL_LENGTH }} +struct Symbol; +typedef struct Symbol Symbol; +struct Symbol +{ + size_t length; + char name[MAX_SYMBOL_LENGTH]; +}; + enum Type { INTEGER, @@ -43,11 +52,78 @@ struct Object Instance instance; }; +struct EnvironmentNode; +typedef struct EnvironmentNode EnvironmentNode; +struct EnvironmentNode +{ + Symbol* key; + Object value; + EnvironmentNode* next; +}; + +struct Environment; +typedef struct Environment Environment; +struct Environment +{ + EnvironmentNode* root; +}; + +Environment* Environment_construct() +{ + // TODO Handle malloc returning NULL + Environment* result = malloc(sizeof(Environment)); + result->root = NULL; + return result; +} + +void Environment_destruct(Environment* self) +{ + EnvironmentNode* next; + for(EnvironmentNode* node = self->root; node != NULL; node = next) + { + // We don't need to destruct the keys, because those will be destructed at the end when the Runtime is destructed + // We don't need to destruct the permanent strings, because those will be destructed at the end when the Runtime is destructed + // The above two comments represent all heap-allocated objects currently, so we don't need to destruct Objects (yet) + next = node->next; + free(node); + } +} + +// This need not be thread safe because environments exist on one thread only +void Environment_set(Environment* self, Symbol* key, Object value) +{ + EnvironmentNode* node = malloc(sizeof(EnvironmentNode)); + node->key = key; + node->value = value; + node->next = self->root; + self->root = node; +} + +Object Environment_get(Environment* self, Symbol* symbol) +{ + for(EnvironmentNode* node = self->root; node != NULL; node = node->next) + { + // We can compare pointers because pointers are unique within Runtime->symbols + if(node->key == symbol) + { + return node->value; + } + } + + // TODO Handle symbol errors + assert(false); +} + + +// TODO Allocate all symbols and strings as static constants so we can remove the level of indirection struct Runtime { size_t permanentStringsLength; size_t permanentStringsAllocated; String** permanentStrings; + size_t symbolsLength; + size_t symbolsAllocated; + Symbol** symbols; }; Runtime* Runtime_construct() @@ -56,12 +132,26 @@ Runtime* Runtime_construct() result->permanentStringsLength = 0; result->permanentStringsAllocated = 0; result->permanentStrings = NULL; + result->symbolsLength = 0; + result->symbolsAllocated =0; + result->symbols = NULL; return result; } void Runtime_destruct(Runtime* self) { + for(size_t i = 0; i < self->permanentStringsLength; i++) + { + free(self->permanentStrings[i]); + } + + for(size_t i = 0; i < self->symbolsLength; i++) + { + free(self->symbols[i]); + } + free(self->permanentStrings); + free(self->symbols); free(self); } @@ -91,6 +181,49 @@ void Runtime_addPermanentString(Runtime* self, String* string) self->permanentStringsLength++; } +// TODO Optimize this by sorting the symbols +// TODO Make this function thread safe +Symbol* Runtime_symbol(Runtime* self, const char* name) +{ + assert(strlen(name) <= MAX_SYMBOL_LENGTH); + + for(size_t i = 0; i < self->symbolsLength; i++) + { + if(strcmp(self->symbols[i]->name, name) == 0) + { + return self->symbols[i]; + } + } + + if(self->symbolsLength == self->symbolsAllocated) + { + if(self->symbolsAllocated == 0) + { + self->symbolsAllocated = 8; + } + else + { + self->symbolsAllocated = self->symbolsAllocated * 2; + } + + self->symbols = realloc( + self->symbols, + sizeof(Symbol*) * self->symbolsAllocated + ); + + // TODO Handle realloc returning NULL + } + + Symbol* result = malloc(sizeof(Symbol)); + result->length = strlen(name); + strcpy(result->name, name); + + self->symbols[self->symbolsLength] = result; + self->symbolsLength++; + + return result; +} + Object integerLiteral(int32_t literal) { Object result; @@ -114,6 +247,16 @@ Object stringLiteral(Runtime* runtime, const char* literal) } // TODO Make this conditionally added +Object builtin$negate(Object input) +{ + assert(input.type == INTEGER); + + Object result; + result.type = INTEGER; + result.instance.integer = -input.instance.integer; + return result; +} + Object builtin$add(Object left, Object right) { assert(left.type == INTEGER); @@ -169,6 +312,19 @@ Object builtin$modularDivide(Object left, Object right) return result; } +{% if 'pow' in builtins %} +Object builtin$pow(Object base, Object exponent) +{ + assert(base.type == INTEGER); + assert(exponent.type == INTEGER); + + Object result; + result.type = INTEGER; + result.instance.integer = pow(base.instance.integer, exponent.instance.integer); + return result; +} +{% endif %} + {% if 'print' in builtins %} void builtin$print(Object output) { @@ -192,11 +348,13 @@ void builtin$print(Object output) int main(int argc, char** argv) { Runtime* runtime = Runtime_construct(); + Environment* environment = Environment_construct(); {% for statement in statements %} {{ statement }} {% endfor %} + Environment_destruct(environment); Runtime_destruct(runtime); return 0;