X-Git-Url: https://code.kerkeslager.com/?a=blobdiff_plain;f=templates%2Fprogram.c;h=f8095bf838a3934733e628d67976060c69109054;hb=5e3bb8aa55a25e2ced307e06f6579c027749ff0e;hp=25bb41348abf3a3454cad00da4c08e6cf51aca44;hpb=151f60b119247efb1bcf05a664f4324b71fac782;p=fur diff --git a/templates/program.c b/templates/program.c index 25bb413..f8095bf 100644 --- a/templates/program.c +++ b/templates/program.c @@ -1,5 +1,6 @@ #include #include +#include #include #include #include @@ -34,6 +35,8 @@ struct Environment; typedef struct Environment Environment; struct EnvironmentPool; typedef struct EnvironmentPool EnvironmentPool; +struct Stack; +typedef struct Stack Stack; const char* const STRING_LITERAL_LIST[] = { {% for string_literal in string_literal_list %} @@ -55,6 +58,7 @@ enum Type LIST, STRING_CONCATENATION, STRING_LITERAL, + STRUCTURE, VOID }; @@ -63,7 +67,7 @@ typedef struct Closure Closure; struct Closure { Environment* closed; - Object (*call)(EnvironmentPool*, Environment*, size_t, Object*); + Object (*call)(EnvironmentPool*, Environment*, size_t, Stack*, const unsigned long, jmp_buf); }; struct List; @@ -78,6 +82,16 @@ struct List struct StringConcatenation; typedef struct StringConcatenation StringConcatenation; +struct Structure; +typedef struct Structure Structure; +struct Structure +{ + size_t reference_count; + size_t length; + const char** symbol_list; + Object* value_list; +}; + union Instance { bool boolean; @@ -86,6 +100,7 @@ union Instance List list; StringConcatenation* string_concatenation; const char* string_literal; + Structure* structure; }; struct Object @@ -137,6 +152,107 @@ Object List_get(Object* list, Object index) return list->instance.list.items[index.instance.integer]; } +struct Stack +{ + uint16_t length; + Object items[256]; +}; + +void Stack_initialize(Stack* self) +{ + self->length = 0; +} + +Stack* Stack_construct() +{ + Stack* result = malloc(sizeof(Stack)); + Stack_initialize(result); + return result; +} + +void Stack_destruct(Stack* self) +{ + free(self); +} + +bool Stack_any(Stack* self) +{ + return self->length > 0; +} + +void Stack_push(Stack* self, Object item) +{ + assert(self->length < 256); + self->items[self->length] = item; + self->length++; +} + +Object Stack_pop(Stack* self) +{ + assert(self->length > 0); + self->length--; + return self->items[self->length]; +} + +Object Object_rereference(Object self) +{ + switch(self.type) + { + case BOOLEAN: + case CLOSURE: + case INTEGER: + case STRING_LITERAL: + case VOID: + return self; + + case STRING_CONCATENATION: + self.instance.string_concatenation->referenceCount++; + return self; + + case STRUCTURE: + self.instance.structure->reference_count++; + return self; + + default: + assert(false); + } +} + +Object Structure_construct(size_t length, const char** symbol_list, Object* value_list) +{ + Structure* structure = malloc(sizeof(Structure)); + structure->reference_count = 1; + structure->length = length; + structure->symbol_list = malloc(sizeof(const char*) * length); + structure->value_list = malloc(sizeof(Object) * length); + + // TODO Don't allow assignment of mutable structures, as this screws up reference counting + for(size_t i = 0; i < length; i++) + { + structure->symbol_list[i] = symbol_list[i]; + structure->value_list[i] = Object_rereference(value_list[i]); + } + + Object result = { STRUCTURE, (Instance)structure }; + + return result; +} + +Object Structure_get(Object* self, const char* symbol) +{ + assert(self->type == STRUCTURE); + + for(size_t i = 0; i < self->instance.structure->length; i++) + { + if(self->instance.structure->symbol_list[i] == symbol) + { + return self->instance.structure->value_list[i]; + } + } + + assert(false); +} + struct EnvironmentNode { const char* key; @@ -197,11 +313,42 @@ void Object_deinitialize(Object* self) } break; + case STRUCTURE: + self->instance.structure->reference_count--; + + if(self->instance.structure->reference_count == 0) + { + for(size_t i = 0; i < self->instance.structure->length; i++) + { + Object_deinitialize(&(self->instance.structure->value_list[i])); + } + free(self->instance.structure->symbol_list); + free(self->instance.structure->value_list); + free(self->instance.structure); + } + break; + default: assert(false); } } +typedef uint32_t StackSnapshot; + +StackSnapshot Stack_takeSnapshot(Stack* self) +{ + return (StackSnapshot) self->length; +} + +void Stack_rewind(Stack* self, StackSnapshot snapshot) +{ + while(self->length > snapshot) + { + Object item = Stack_pop(self); + Object_deinitialize(&item); + } +} + void Environment_deinitialize(Environment* self) { EnvironmentNode* next; @@ -403,6 +550,13 @@ Environment* EnvironmentPool_allocate(EnvironmentPool* self) return EnvironmentPool_allocate(previous->overflow); } +Environment* Environment_construct(EnvironmentPool* environmentPool, Environment* parent) +{ + Environment* environment = EnvironmentPool_allocate(environmentPool); + Environment_initialize(environment, parent); + return environment; +} + Object integerLiteral(int32_t literal) { Object result; @@ -419,25 +573,110 @@ Object stringLiteral(const char* literal) return result; } -// TODO Make this conditionally added -Object operator$negate(Object input) -{ - assert(input.type == INTEGER); +{% if 'pow' in builtins %} +Object builtin$pow$implementation( + EnvironmentPool* environmentPool, + Environment* parent, + size_t argc, + Stack* stack, + const unsigned long line, + jmp_buf parentJump) +{ + // Must unload items in reverse order + Object exponent = Stack_pop(stack); + Object base = Stack_pop(stack); + + assert(base.type == INTEGER); + assert(exponent.type == INTEGER); Object result; result.type = INTEGER; - result.instance.integer = -input.instance.integer; + result.instance.integer = pow(base.instance.integer, exponent.instance.integer); + return result; +} + +Object builtin$pow = { CLOSURE, (Instance)(Closure){ NULL, builtin$pow$implementation } }; +{% endif %} + +Object builtin$negate$implementation( + EnvironmentPool* environmentPool, + Environment* parent, + size_t argc, + Stack* stack, + const unsigned long line, + jmp_buf parentJump) +{ + assert(argc == 1); + + Object argument = Stack_pop(stack); + + assert(argument.type == INTEGER); + + Object result = (Object){ + INTEGER, + (Instance)(int32_t) (-argument.instance.integer) + }; + return result; } +Object builtin$negate = { CLOSURE, (Instance)(Closure){ NULL, builtin$negate$implementation } }; + +{% for op in ['lt', 'gt', 'lte', 'gte', 'eq', 'neq'] %} +Object builtin${{ op }}$implementation( + EnvironmentPool* environmentPool, + Environment* parent, + size_t argc, + Stack* stack, + const unsigned long line, + jmp_buf parentJump) +{ + assert(argc == 2); + + Object right = Stack_pop(stack); + Object left = Stack_pop(stack); + + assert(left.type == INTEGER); + assert(right.type == INTEGER); + + {% if op == 'lt' %} + if(left.instance.integer < right.instance.integer) + {% elif op == 'gt' %} + if(left.instance.integer > right.instance.integer) + {% elif op == 'lte' %} + if(left.instance.integer <= right.instance.integer) + {% elif op == 'gte' %} + if(left.instance.integer >= right.instance.integer) + {% elif op == 'eq' %} + if(left.instance.integer == right.instance.integer) + {% elif op == 'neq' %} + if(left.instance.integer != right.instance.integer) + {% endif %} + { + return builtin$true; + } + else + { + return builtin$false; + } +} +Object builtin${{ op }} = { CLOSURE, (Instance)(Closure){ NULL, builtin${{ op }}$implementation } }; +{% endfor %} -// TODO Make this conditionally added -Object operator$concatenate(Object left, Object right) +Object builtin$concat$implementation( + EnvironmentPool* environmentPool, + Environment* parent, + size_t argc, + Stack* stack, + const unsigned long line, + jmp_buf parentJump) { + assert(argc == 2); + + Object right = Stack_pop(stack); + Object left = Stack_pop(stack); + switch(left.type) { case STRING_CONCATENATION: - left.instance.string_concatenation->referenceCount++; - break; - case STRING_LITERAL: break; @@ -447,9 +686,6 @@ Object operator$concatenate(Object left, Object right) switch(right.type) { case STRING_CONCATENATION: - right.instance.string_concatenation->referenceCount++; - break; - case STRING_LITERAL: break; @@ -459,52 +695,213 @@ Object operator$concatenate(Object left, Object right) StringConcatenation* concatenation = malloc(sizeof(StringConcatenation)); concatenation->referenceCount = 1; - concatenation->left = left; - concatenation->right = right; + concatenation->left = Object_rereference(left); + concatenation->right = Object_rereference(right); Object result = { STRING_CONCATENATION, (Instance)concatenation }; return result; } +Object builtin$concat = { CLOSURE, (Instance)(Closure){ NULL, builtin$concat$implementation } }; -{% for id in infix_declarations %} -Object operator${{ id.name }}(Object left, Object right) +Object builtin$add$implementation( + EnvironmentPool* environmentPool, + Environment* parent, + size_t argc, + Stack* stack, + const unsigned long line, + jmp_buf parentJump) { - assert(left.type == {{ id.in_type.upper() }}); - assert(right.type == {{ id.in_type.upper() }}); + assert(argc == 2); + + Object right = Stack_pop(stack); + Object left = Stack_pop(stack); + + assert(left.type == INTEGER); + assert(right.type == INTEGER); + + Object result = (Object){ + INTEGER, + (Instance)(int32_t) (left.instance.integer + right.instance.integer) + }; - Object result; - 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$add = { CLOSURE, (Instance)(Closure){ NULL, builtin$add$implementation } }; -{% if 'pow' in builtins %} -Object builtin$pow$implementation(EnvironmentPool* environmentPool, Environment* parent, size_t argc, Object* args) +Object builtin$subtract$implementation( + EnvironmentPool* environmentPool, + Environment* parent, + size_t argc, + Stack* stack, + const unsigned long line, + jmp_buf parentJump) { assert(argc == 2); - Object base = args[0]; - Object exponent = args[1]; + Object right = Stack_pop(stack); + Object left = Stack_pop(stack); - assert(base.type == INTEGER); - assert(exponent.type == INTEGER); + assert(left.type == INTEGER); + assert(right.type == INTEGER); + + Object result = (Object){ + INTEGER, + (Instance)(int32_t) (left.instance.integer - right.instance.integer) + }; - Object result; - result.type = INTEGER; - result.instance.integer = pow(base.instance.integer, exponent.instance.integer); return result; } +Object builtin$subtract = { CLOSURE, (Instance)(Closure){ NULL, builtin$subtract$implementation } }; -Object builtin$pow = { CLOSURE, (Instance)(Closure){ NULL, builtin$pow$implementation } }; -{% endif %} +Object builtin$multiply$implementation( + EnvironmentPool* environmentPool, + Environment* parent, + size_t argc, + Stack* stack, + const unsigned long line, + jmp_buf parentJump) +{ + assert(argc == 2); + + Object right = Stack_pop(stack); + Object left = Stack_pop(stack); + + assert(left.type == INTEGER); + assert(right.type == INTEGER); + + Object result = (Object){ + INTEGER, + (Instance)(int32_t) (left.instance.integer * right.instance.integer) + }; + + return result; +} +Object builtin$multiply = { CLOSURE, (Instance)(Closure){ NULL, builtin$multiply$implementation } }; + +Object builtin$integer_divide$implementation( + EnvironmentPool* environmentPool, + Environment* parent, + size_t argc, + Stack* stack, + const unsigned long line, + jmp_buf parentJump) +{ + assert(argc == 2); + + Object right = Stack_pop(stack); + Object left = Stack_pop(stack); + + assert(left.type == INTEGER); + assert(right.type == INTEGER); + + if(right.instance.integer == 0) + { + fprintf(stderr, "DivisionByZeroError on line %zu\n", line); + longjmp(parentJump, 1); + } + + Object result = (Object){ + INTEGER, + (Instance)(int32_t) (left.instance.integer / right.instance.integer) + }; + + return result; +} +Object builtin$integer_divide = { CLOSURE, (Instance)(Closure){ NULL, builtin$integer_divide$implementation } }; + +Object builtin$modular_divide$implementation( + EnvironmentPool* environmentPool, + Environment* parent, + size_t argc, + Stack* stack, + const unsigned long line, + jmp_buf parentJump) +{ + assert(argc == 2); + + Object right = Stack_pop(stack); + Object left = Stack_pop(stack); + + assert(left.type == INTEGER); + assert(right.type == INTEGER); + + if(right.instance.integer == 0) + { + fprintf(stderr, "DivisionByZeroError on line %zu\n", line); + longjmp(parentJump, 1); + } + + Object result = (Object){ + INTEGER, + (Instance)(int32_t) (left.instance.integer % right.instance.integer) + }; + + return result; +} +Object builtin$modular_divide = { CLOSURE, (Instance)(Closure){ NULL, builtin$modular_divide$implementation } }; + +Object builtin$field$implementation( + EnvironmentPool* environmentPool, + Environment* parent, + size_t argc, + Stack* stack, + const unsigned long line, + jmp_buf parentJump) +{ + assert(argc == 2); + + Object right = Stack_pop(stack); + Object left = Stack_pop(stack); + + assert(left.type == STRUCTURE); + assert(right.type == STRING_LITERAL); + + Object result = (Object){ + INTEGER, + (Instance)(int32_t) (left.instance.integer % right.instance.integer) + }; + + return result; +} +Object builtin$field = { CLOSURE, (Instance)(Closure){ NULL, builtin$field$implementation } }; + +Object builtin$get$implementation( + EnvironmentPool* environmentPool, + Environment* parent, + size_t argc, + Stack* stack, + const unsigned long line, + jmp_buf parentJump) +{ + assert(argc == 2); + + Object right = Stack_pop(stack); + Object left = Stack_pop(stack); + + return List_get(&left, right); +} +Object builtin$get = { CLOSURE, (Instance)(Closure){ NULL, builtin$get$implementation } }; {% if 'print' in builtins %} -Object builtin$print$implementation(EnvironmentPool* environmentPool, Environment* parent, size_t argc, Object* args) +Object builtin$print$implementation( + EnvironmentPool* environmentPool, + Environment* parent, + size_t argc, + Stack* stack, + const unsigned long line, + jmp_buf parentJump) { + Stack reverse_stack; + Stack_initialize(&reverse_stack); + for(size_t i = 0; i < argc; i++) { - Object output = args[i]; + Stack_push(&reverse_stack, Stack_pop(stack)); + } + + while(reverse_stack.length > 0) + { + Object output = Stack_pop(&reverse_stack); switch(output.type) { case BOOLEAN: @@ -521,8 +918,10 @@ Object builtin$print$implementation(EnvironmentPool* environmentPool, Environmen break; case STRING_CONCATENATION: - builtin$print$implementation(NULL, NULL, 1, &(output.instance.string_concatenation->left)); - builtin$print$implementation(NULL, NULL, 1, &(output.instance.string_concatenation->right)); + Stack_push(stack, output.instance.string_concatenation->left); + builtin$print$implementation(NULL, NULL, 1, stack, line, parentJump); + Stack_push(stack, output.instance.string_concatenation->right); + builtin$print$implementation(NULL, NULL, 1, stack, line, parentJump); break; case STRING_LITERAL: @@ -556,11 +955,48 @@ int main(int argc, char** argv) Environment* environment = EnvironmentPool_allocate(environmentPool); Environment_initialize(environment, NULL); + Stack stackMemory; + Stack* stack = &stackMemory; + Stack_initialize(stack); + + jmp_buf jump; + if(setjmp(jump) != 0) + { + fprintf(stderr, "\tin __main__\n"); + + while(Stack_any(stack)) + { + Object item = Stack_pop(stack); + Object_deinitialize(&item); + } + Environment_setLive(environment, false); + EnvironmentPool_destruct(environmentPool); + + // TODO We would like to return something nonzero here, but that messes up Valgrind so we couldn't catch memory leaks + return 0; + } + // TODO Use the symbol from SYMBOL_LIST {% for builtin in builtins %} Environment_set(environment, "{{ builtin }}", builtin${{ builtin }}); {% endfor %} + Environment_set(environment, "true", builtin$true); + Environment_set(environment, "false", builtin$false); + Environment_set(environment, "__add__", builtin$add); + Environment_set(environment, "__subtract__", builtin$subtract); + Environment_set(environment, "__multiply__", builtin$multiply); + Environment_set(environment, "__integer_divide__", builtin$integer_divide); + Environment_set(environment, "__modular_divide__", builtin$modular_divide); + Environment_set(environment, "__negate__", builtin$negate); + Environment_set(environment, "__concat__", builtin$concat); + Environment_set(environment, "__field__", builtin$field); + Environment_set(environment, "__get__", builtin$get); + + {% for op in ['lt', 'gt', 'lte', 'gte', 'eq', 'neq'] %} + Environment_set(environment, "__{{ op }}__", builtin${{ op }}); + {% endfor %} + {% for statement in statements %} {{ statement }} {% endfor %}