X-Git-Url: https://code.kerkeslager.com/?a=blobdiff_plain;f=templates%2Fprogram.c;h=c589e048520bb3044beb8307fdf3ad00788c6a2b;hb=80efbcfcd42da6061d0e31add5cc1e6fb17b2f93;hp=063587d7adcd33a2091cdcca78a98e42d1338913;hpb=f60d1b48bbf73c51d214c5ae5c22ea3cdee087c1;p=fur diff --git a/templates/program.c b/templates/program.c index 063587d..c589e04 100644 --- a/templates/program.c +++ b/templates/program.c @@ -8,33 +8,43 @@ #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; + +const char* const STRING_LITERAL_LIST[] = { +{% for string_literal in string_literal_list %} + "{{ string_literal }}", +{% endfor %} +}; -struct String -{ - size_t length; - char* characters; +const char* const SYMBOL_LIST[] = { +{% for symbol in symbol_list %} + "{{ symbol }}", +{% endfor %} }; enum Type { + BOOLEAN, + CLOSURE, INTEGER, STRING }; union Instance { + bool boolean; + Object (*closure)(Environment*, size_t, Object*); int32_t integer; - String* string; + const char* string; }; struct Object @@ -43,52 +53,84 @@ struct Object Instance instance; }; -struct Runtime +const Object TRUE = { + BOOLEAN, + { true } +}; + +const Object FALSE = { + BOOLEAN, + { false } +}; + +struct EnvironmentNode { - size_t permanentStringsLength; - size_t permanentStringsAllocated; - String** permanentStrings; + const char* key; + Object value; + EnvironmentNode* next; }; -Runtime* Runtime_construct() +struct Environment { - Runtime* result = malloc(sizeof(Runtime)); - result->permanentStringsLength = 0; - result->permanentStringsAllocated = 0; - result->permanentStrings = NULL; - return result; -} + size_t referenceCount; + Environment* parent; + EnvironmentNode* root; +}; -void Runtime_destruct(Runtime* self) +Environment* Environment_construct(Environment* parent) { - free(self->permanentStrings); - free(self); + Environment* result = malloc(sizeof(Environment)); + result->referenceCount = 1; + result->parent = parent; + result->root = NULL; + return result; } -void Runtime_addPermanentString(Runtime* self, String* string) +void Environment_destruct(Environment* self) { - // TODO Make this function thread-safe - if(self->permanentStringsLength == self->permanentStringsAllocated) + self->referenceCount--; + + if(self->referenceCount == 0) { - if(self->permanentStringsAllocated == 0) + EnvironmentNode* next; + for(EnvironmentNode* node = self->root; node != NULL; node = next) { - self->permanentStringsAllocated = 8; + // No objects are allocated on the heap (yet!) so we don't need to free anything else + next = node->next; + free(node); } - else + free(self); + } +} + +// This need not be thread safe because environments exist on one thread only +void Environment_set(Environment* self, const char* const 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, const char* const symbol) +{ + for(EnvironmentNode* node = self->root; node != NULL; node = node->next) + { + // We can compare pointers because pointers are unique in the SYMBOL_LIST + if(node->key == symbol) { - self->permanentStringsAllocated = self->permanentStringsAllocated * 2; + return node->value; } + } - self->permanentStrings = realloc( - self->permanentStrings, - sizeof(String*) * self->permanentStringsAllocated - ); - - // TODO Handle realloc returning NULL + if(self->parent != NULL) + { + return Environment_get(self->parent, symbol); } - self->permanentStrings[self->permanentStringsLength] = string; - self->permanentStringsLength++; + // TODO Handle symbol errors + assert(false); } Object integerLiteral(int32_t literal) @@ -99,79 +141,100 @@ 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$add(Object left, Object right) +Object operator$negate(Object input) { - assert(left.type == INTEGER); - assert(right.type == INTEGER); + assert(input.type == INTEGER); Object result; result.type = INTEGER; - result.instance.integer = left.instance.integer + right.instance.integer; + result.instance.integer = -input.instance.integer; return result; } -Object builtin$subtract(Object left, Object right) +{% for od in operator_declarations %} +Object operator${{ od.name }}(Object left, Object right) +{ + assert(left.type == {{ od.input_type.upper() }}); + assert(right.type == {{ od.input_type.upper() }}); + + Object result; + result.type = {{ od.result_type.upper() }}; + result.instance.{{ od.result_type.lower() }} = left.instance.{{ od.input_type.lower() }} {{ od.c_operator }} right.instance.{{ od.input_type.lower() }}; + return result; +} +{% endfor %} + +Object operator$equals(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; + Object result = { BOOLEAN, { left.instance.integer == right.instance.integer } }; return result; } -Object builtin$multiply(Object left, Object right) +Object operator$notEquals(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; + Object result = { BOOLEAN, { left.instance.integer != right.instance.integer } }; return result; } -Object builtin$integerDivide(Object left, Object right) +Object operator$greaterThan(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; + Object result = { BOOLEAN, { left.instance.integer > right.instance.integer } }; return result; } -Object builtin$modularDivide(Object left, Object right) +Object operator$lessThan(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; + Object result = { BOOLEAN, { left.instance.integer < right.instance.integer } }; + return result; +} + +Object operator$greaterThanOrEqual(Object left, Object right) +{ + assert(left.type == INTEGER); + assert(right.type == INTEGER); + + Object result = { BOOLEAN, { left.instance.integer >= right.instance.integer } }; + return result; +} + +Object operator$lessThanOrEqual(Object left, Object right) +{ + assert(left.type == INTEGER); + assert(right.type == INTEGER); + + Object result = { BOOLEAN, { left.instance.integer <= right.instance.integer } }; return result; } {% if 'pow' in builtins %} -Object builtin$pow(Object base, Object exponent) +Object builtin$pow$implementation(Environment* parent, size_t argc, Object* args) { + assert(argc == 2); + + Object base = args[0]; + Object exponent = args[1]; + assert(base.type == INTEGER); assert(exponent.type == INTEGER); @@ -180,37 +243,74 @@ Object builtin$pow(Object base, Object exponent) result.instance.integer = pow(base.instance.integer, exponent.instance.integer); return result; } + +Object builtin$pow = { CLOSURE, (Instance)builtin$pow$implementation }; {% endif %} {% if 'print' in builtins %} -void builtin$print(Object output) +Object builtin$print$implementation(Environment* parent, size_t argc, Object* args) { - switch(output.type) + for(size_t i = 0; i < argc; i++) { - case INTEGER: - printf("%" PRId32, output.instance.integer); - break; + Object output = args[i]; + switch(output.type) + { + case BOOLEAN: + fputs(output.instance.boolean ? "true" : "false", stdout); + break; - case STRING: - // Using fwrite instead of printf to handle size_t length - fwrite(output.instance.string->characters, 1, output.instance.string->length, stdout); - break; + case INTEGER: + printf("%" PRId32, output.instance.integer); + break; - default: - assert(false); + case STRING: + // Using fwrite instead of printf to handle size_t length + printf("%s", output.instance.string); + break; + + default: + assert(false); + } } + + // TODO Return something better + return FALSE; } + +Object builtin$print = { CLOSURE, (Instance)builtin$print$implementation }; {% endif %} +{% for function_definition in function_definition_list %} +Object user${{function_definition.name}}$implementation(Environment* parent, size_t argc, Object* args) +{ + Environment* environment = Environment_construct(parent); + + {% for statement in function_definition.statement_list[:-1] %} + {{ generate_statement(statement) }} + {% endfor %} + + Object result = {{ generate_statement(function_definition.statement_list[-1]) }} + Environment_destruct(environment); + return result; +} + +Object user${{function_definition.name}} = { CLOSURE, (Instance)user${{function_definition.name}}$implementation }; +{% endfor %} + int main(int argc, char** argv) { - Runtime* runtime = Runtime_construct(); + Environment* environment = Environment_construct(NULL); + + // TODO Use the symbol from SYMBOL_LIST + {% for builtin in builtins %} + Environment_set(environment, "{{ builtin }}", builtin${{ builtin }}); + {% endfor %} {% for statement in statements %} - {{ statement }} + {{ generate_statement(statement) }} {% endfor %} - Runtime_destruct(runtime); + Environment_destruct(environment); return 0; }