X-Git-Url: https://code.kerkeslager.com/?a=blobdiff_plain;f=templates%2Fprogram.c;h=2a08f397bbe4762480dd08a1941b051d6447265e;hb=d6af7d074bf65e782e42055623a197863b5f8000;hp=0f79b14cd1d5c82a2734fd8c05139c3ab36ee9cc;hpb=98d42eb47acf01ace76d57942404c09132d51f79;p=fur diff --git a/templates/program.c b/templates/program.c index 0f79b14..2a08f39 100644 --- a/templates/program.c +++ b/templates/program.c @@ -4,28 +4,44 @@ #include #include +/* Some terminology used in function names: + * - initialize: These functions take a pointer and potentially some other arguments, and use those + * to initialize the value pointed to by self. Initialize functions DO NOT allocate the function, + * so they can be used to initialize stack-allocated variables. + * - construct: This allocates a value for a pointer, initializes it, and returns it. This is for + * heap-allocated values. It may be as simple as allocating the memory, calling an initialize, and + * returning it. + * - deinitialize: These functions dereference or free any objects pointed to by the self pointer's + * value, but they don't actually free the self pointer. This is useful for stack-allocated objects + * which point to heap-allocated objects. + * - destruct: This dereferences or frees memory pointed to by the self argument, and all the + * pointers on the self argument. + */ + {% for standard_library in standard_libraries %} #include <{{standard_library}}> {% endfor %} -struct String; -typedef struct String String; enum Type; typedef enum Type Type; union Instance; typedef union Instance Instance; struct Object; typedef struct Object Object; -struct Runtime; -typedef struct Runtime Runtime; +struct EnvironmentNode; +typedef struct EnvironmentNode EnvironmentNode; +struct Environment; +typedef struct Environment Environment; +struct EnvironmentPool; +typedef struct EnvironmentPool EnvironmentPool; -struct String -{ - size_t length; - char* characters; +const char* const STRING_LITERAL_LIST[] = { +{% for string_literal in string_literal_list %} + "{{ string_literal }}", +{% endfor %} }; -const char * const SYMBOL_LIST[] = { +const char* const SYMBOL_LIST[] = { {% for symbol in symbol_list %} "{{ symbol }}", {% endfor %} @@ -33,14 +49,26 @@ const char * const SYMBOL_LIST[] = { enum Type { + BOOLEAN, + CLOSURE, INTEGER, STRING }; +struct Closure; +typedef struct Closure Closure; +struct Closure +{ + Environment* closed; + Object (*call)(EnvironmentPool*, Environment*, size_t, Object*); +}; + union Instance { + bool boolean; + Closure closure; int32_t integer; - String* string; + const char* string; }; struct Object @@ -49,8 +77,16 @@ struct Object Instance instance; }; -struct EnvironmentNode; -typedef struct EnvironmentNode EnvironmentNode; +const Object TRUE = { + BOOLEAN, + { true } +}; + +const Object FALSE = { + BOOLEAN, + { false } +}; + struct EnvironmentNode { const char* key; @@ -58,33 +94,68 @@ struct EnvironmentNode EnvironmentNode* next; }; -struct Environment; -typedef struct Environment Environment; struct Environment { + bool mark; + bool live; + + Environment* parent; EnvironmentNode* root; }; -Environment* Environment_construct() +void Environment_initialize(Environment* self, Environment* parent) { - // TODO Handle malloc returning NULL - Environment* result = malloc(sizeof(Environment)); - result->root = NULL; - return result; + self->parent = parent; + self->root = NULL; + + // We are currently only ever initializing environments at the beginning of running functions, so + // for now at least we can assume that we want it to be live immediately. + self->live = true; } -void Environment_destruct(Environment* self) +void Environment_deinitialize(Environment* self) { EnvironmentNode* next; for(EnvironmentNode* node = self->root; node != NULL; node = next) { - // We don't need to destruct the permanent strings, because those will be destructed at the end when the Runtime is destructed - // The above comment represents all heap-allocated objects currently, so we don't need to destruct Objects (yet) next = node->next; free(node); } } +void Environment_setLive(Environment* self, bool live) +{ + self->live = live; +} + +void Environment_mark(Environment* self) +{ + if(self == NULL) return; + if(self->mark) return; // Prevents infinite recursion in the case of cycles + + self->mark = true; + + Environment_mark(self->parent); + + for(EnvironmentNode* node = self->root; node != NULL; node = node->next) + { + switch(node->value.type) + { + case BOOLEAN: + case INTEGER: + case STRING: + break; + + case CLOSURE: + Environment_mark(node->value.instance.closure.closed); + break; + + default: + assert(false); + } + } +} + // This need not be thread safe because environments exist on one thread only void Environment_set(Environment* self, const char* const key, Object value) { @@ -99,69 +170,146 @@ Object Environment_get(Environment* self, const char* const symbol) { for(EnvironmentNode* node = self->root; node != NULL; node = node->next) { - // We can compare pointers because pointers are unique in the SYMBOLS_LIST + // We can compare pointers because pointers are unique in the SYMBOL_LIST if(node->key == symbol) { return node->value; } } + if(self->parent != NULL) + { + return Environment_get(self->parent, symbol); + } + // TODO Handle symbol errors assert(false); } - -struct Runtime +# define POOL_SIZE 64 +struct EnvironmentPool { - size_t permanentStringsLength; - size_t permanentStringsAllocated; - String** permanentStrings; + int8_t freeIndex; + bool allocatedFlags[POOL_SIZE]; + Environment environments[POOL_SIZE]; + EnvironmentPool* overflow; }; -Runtime* Runtime_construct() +EnvironmentPool* EnvironmentPool_construct(); +void EnvironmentPool_initialize(EnvironmentPool*); +void EnvironmentPool_deinitialize(EnvironmentPool*); +void EnvironmentPool_destruct(EnvironmentPool*); + +EnvironmentPool* EnvironmentPool_construct() { - Runtime* result = malloc(sizeof(Runtime)); - result->permanentStringsLength = 0; - result->permanentStringsAllocated = 0; - result->permanentStrings = NULL; + EnvironmentPool* result = malloc(sizeof(EnvironmentPool)); + EnvironmentPool_initialize(result); return result; } -void Runtime_destruct(Runtime* self) +void EnvironmentPool_initialize(EnvironmentPool* self) +{ + self->overflow = NULL; + self->freeIndex = 0; + + for(size_t i = 0; i < POOL_SIZE; i++) + { + self->allocatedFlags[i] = false; + self->environments[i].live = false; + } +} + +void EnvironmentPool_deinitialize(EnvironmentPool* self) { - for(size_t i = 0; i < self->permanentStringsLength; i++) + // We can assume if this is being called, none of the Environments are live + for(int8_t i = 0; i < POOL_SIZE; i++) { - free(self->permanentStrings[i]); + if(self->allocatedFlags[i]) Environment_deinitialize(&(self->environments[i])); } - free(self->permanentStrings); + EnvironmentPool_destruct(self->overflow); +} + +void EnvironmentPool_destruct(EnvironmentPool* self) +{ + if(self == NULL) return; + EnvironmentPool_deinitialize(self); free(self); } -void Runtime_addPermanentString(Runtime* self, String* string) +void EnvironmentPool_GC(EnvironmentPool* self) { - // TODO Make this function thread-safe - if(self->permanentStringsLength == self->permanentStringsAllocated) + // Unmark all the environments + for(EnvironmentPool* current = self; current != NULL; current = current->overflow) { - if(self->permanentStringsAllocated == 0) + for(int8_t i = 0; i < POOL_SIZE; i++) { - self->permanentStringsAllocated = 8; + current->environments[i].mark = false; } - else + } + + // Mark live enviroments and environments referenced by live environments + for(EnvironmentPool* current = self; current != NULL; current = current->overflow) + { + for(int8_t i = 0; i < POOL_SIZE; i++) { - self->permanentStringsAllocated = self->permanentStringsAllocated * 2; + if(current->environments[i].live) + { + Environment_mark(&(current->environments[i])); + } } + } - self->permanentStrings = realloc( - self->permanentStrings, - sizeof(String*) * self->permanentStringsAllocated - ); + // TODO We never free pools until the very end--we could free a pool if two pools are empty + for(EnvironmentPool* current = self; current != NULL; current = current->overflow) + { + for(int8_t i = POOL_SIZE - 1; i >= 0; i--) + { + if(!current->environments[i].mark && current->allocatedFlags[i]) + { + Environment_deinitialize(&(current->environments[i])); + current->allocatedFlags[i] = false; + current->freeIndex = i; + } + } + } +} - // TODO Handle realloc returning NULL +Environment* EnvironmentPool_allocate(EnvironmentPool* self) +{ + for(EnvironmentPool* current = self; current != NULL; current = current->overflow) + { + for(; current->freeIndex < POOL_SIZE; current->freeIndex++) + { + if(!current->allocatedFlags[current->freeIndex]) + { + current->allocatedFlags[current->freeIndex] = true; + return &(current->environments[current->freeIndex]); + } + } } - self->permanentStrings[self->permanentStringsLength] = string; - self->permanentStringsLength++; + EnvironmentPool_GC(self); + + EnvironmentPool* previous; + for(EnvironmentPool* current = self; current != NULL; current = current->overflow) + { + for(; current->freeIndex < POOL_SIZE; current->freeIndex++) + { + if(!current->allocatedFlags[current->freeIndex]) + { + current->allocatedFlags[current->freeIndex] = true; + return &(current->environments[current->freeIndex]); + } + else + { + previous = current; + } + } + } + + previous->overflow = EnvironmentPool_construct(); + return EnvironmentPool_allocate(previous->overflow); } Object integerLiteral(int32_t literal) @@ -172,22 +320,16 @@ Object integerLiteral(int32_t literal) return result; } -Object stringLiteral(Runtime* runtime, const char* literal) +Object stringLiteral(const char* literal) { - String* resultString = malloc(sizeof(String)); - resultString->length = strlen(literal); - resultString->characters = malloc(resultString->length); - memcpy(resultString->characters, literal, resultString->length); - Runtime_addPermanentString(runtime, resultString); - Object result; result.type = STRING; - result.instance.string = resultString; + result.instance.string = literal; return result; } // TODO Make this conditionally added -Object builtin$negate(Object input) +Object operator$negate(Object input) { assert(input.type == INTEGER); @@ -197,105 +339,116 @@ Object builtin$negate(Object input) return result; } -Object builtin$add(Object left, Object right) +{% for id in infix_declarations %} +Object operator${{ id.name }}(Object left, Object right) { - assert(left.type == INTEGER); - assert(right.type == INTEGER); + assert(left.type == {{ id.in_type.upper() }}); + assert(right.type == {{ id.in_type.upper() }}); Object result; - result.type = INTEGER; - result.instance.integer = left.instance.integer + right.instance.integer; + result.type = {{ id.out_type.upper() }}; + result.instance.{{ id.out_type.lower() }} = left.instance.{{ id.in_type.lower() }} {{ id.operator }} right.instance.{{ id.in_type.lower() }}; return result; } +{% endfor %} -Object builtin$subtract(Object left, Object right) +{% if 'pow' in builtins %} +Object builtin$pow$implementation(EnvironmentPool* environmentPool, Environment* parent, size_t argc, Object* args) { - assert(left.type == INTEGER); - assert(right.type == INTEGER); + assert(argc == 2); - Object result; - result.type = INTEGER; - result.instance.integer = left.instance.integer - right.instance.integer; - return result; -} + Object base = args[0]; + Object exponent = args[1]; -Object builtin$multiply(Object left, Object right) -{ - assert(left.type == INTEGER); - assert(right.type == INTEGER); + assert(base.type == INTEGER); + assert(exponent.type == INTEGER); Object result; result.type = INTEGER; - result.instance.integer = left.instance.integer * right.instance.integer; + result.instance.integer = pow(base.instance.integer, exponent.instance.integer); return result; } -Object builtin$integerDivide(Object left, Object right) -{ - assert(left.type == INTEGER); - assert(right.type == INTEGER); - - Object result; - result.type = INTEGER; - result.instance.integer = left.instance.integer / right.instance.integer; - return result; -} +Object builtin$pow = { CLOSURE, (Instance)(Closure){ NULL, builtin$pow$implementation } }; +{% endif %} -Object builtin$modularDivide(Object left, Object right) +{% if 'print' in builtins %} +Object builtin$print$implementation(EnvironmentPool* environmentPool, Environment* parent, size_t argc, Object* args) { - assert(left.type == INTEGER); - assert(right.type == INTEGER); + for(size_t i = 0; i < argc; i++) + { + Object output = args[i]; + switch(output.type) + { + case BOOLEAN: + fputs(output.instance.boolean ? "true" : "false", stdout); + break; + + case CLOSURE: + // TODO Print something better + printf(""); + break; + + case INTEGER: + printf("%" PRId32, output.instance.integer); + break; + + case STRING: + // Using fwrite instead of printf to handle size_t length + printf("%s", output.instance.string); + break; + + default: + assert(false); + } + } - Object result; - result.type = INTEGER; - result.instance.integer = left.instance.integer % right.instance.integer; - return result; + // TODO Return something better + return FALSE; } -{% 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; -} +Object builtin$print = { CLOSURE, (Instance)(Closure){ NULL, builtin$print$implementation } }; {% endif %} -{% if 'print' in builtins %} -void builtin$print(Object output) +{% for function_definition in function_definition_list %} +Object user${{function_definition.name}}$implementation(EnvironmentPool* environmentPool, Environment* parent, size_t argc, Object* args) { - switch(output.type) - { - case INTEGER: - printf("%" PRId32, output.instance.integer); - break; + assert(argc == {{ function_definition.argument_name_list|length }}); - case STRING: - // Using fwrite instead of printf to handle size_t length - fwrite(output.instance.string->characters, 1, output.instance.string->length, stdout); - break; + Environment* environment = EnvironmentPool_allocate(environmentPool); + Environment_initialize(environment, parent); - default: - assert(false); - } + {% for argument_name in function_definition.argument_name_list %} + Environment_set(environment, "{{ argument_name }}", args[{{ loop.index0 }}]); + {% endfor %} + + {% for statement in function_definition.statement_list[:-1] %} + {{ generate_statement(statement) }} + {% endfor %} + + Object result = {{ generate_statement(function_definition.statement_list[-1]) }} + + Environment_setLive(environment, false); + return result; } -{% endif %} +{% endfor %} int main(int argc, char** argv) { - Runtime* runtime = Runtime_construct(); - Environment* environment = Environment_construct(); + EnvironmentPool* environmentPool = EnvironmentPool_construct(); + Environment* environment = EnvironmentPool_allocate(environmentPool); + Environment_initialize(environment, NULL); - {% for statement in statements %} - {{ statement }} + // TODO Use the symbol from SYMBOL_LIST + {% for builtin in builtins %} + Environment_set(environment, "{{ builtin }}", builtin${{ builtin }}); {% endfor %} - Environment_destruct(environment); - Runtime_destruct(runtime); + {% for statement in statements %} + {{ generate_statement(statement) }} + {% endfor %} + Environment_setLive(environment, false); + EnvironmentPool_destruct(environmentPool); return 0; }