From d8fdecee02795cb0372627208c4f0a52ae7814f9 Mon Sep 17 00:00:00 2001 From: David Kerkeslager Date: Wed, 9 Aug 2017 14:26:10 -0400 Subject: [PATCH] A featureful commit: * Added support for a few new kinds of expression statements * Cleaned up the generated C code a bit * Pass through calling environments to functions --- examples/17_short_circuiting.fur | 24 +++++++++++ examples/17_short_circuiting.fur.output.txt | 3 ++ generation.py | 42 +++++++++++++++---- normalization.py | 3 ++ templates/program.c | 46 ++++++++++++--------- transformation.py | 4 ++ 6 files changed, 95 insertions(+), 27 deletions(-) create mode 100644 examples/17_short_circuiting.fur create mode 100644 examples/17_short_circuiting.fur.output.txt diff --git a/examples/17_short_circuiting.fur b/examples/17_short_circuiting.fur new file mode 100644 index 0000000..f70e7b9 --- /dev/null +++ b/examples/17_short_circuiting.fur @@ -0,0 +1,24 @@ +def return_zero() do + print('This should not print\n') + 2 +end + +def return_one() do + print('This should only print once.\n') + 1 +end + +def return_true() do + print('This should print exactly twice.\n') + true +end + +def return_false() do + print('This should print exactly twice.\n') + false +end + +0 < return_one() < 2 +0 < 0 < return_zero() +return_true() or return_true() +return_false() and return_false() diff --git a/examples/17_short_circuiting.fur.output.txt b/examples/17_short_circuiting.fur.output.txt new file mode 100644 index 0000000..21ff499 --- /dev/null +++ b/examples/17_short_circuiting.fur.output.txt @@ -0,0 +1,3 @@ +This should only print once. +This should print exactly twice. +This should print exactly twice. diff --git a/generation.py b/generation.py index c058f91..b48342a 100644 --- a/generation.py +++ b/generation.py @@ -23,7 +23,7 @@ def generate_constant_expression(c_constant_expression): return CONSTANT_EXPRESSION_MAPPING[c_constant_expression.value] def generate_symbol_expression(c_symbol_expression): - return 'Environment_get(environment, SYMBOL_LIST[{}] /* symbol: {} */)'.format( + return 'Environment_get(&environment, SYMBOL_LIST[{}] /* symbol: {} */)'.format( c_symbol_expression.symbol_list_index, c_symbol_expression.symbol, ) @@ -65,7 +65,7 @@ def generate_negation_expression(c_negation_expression): ) def generate_function_call(function_call): - return 'Environment_get(environment, "{}").instance.closure({}, {})'.format( + return 'Environment_get(&environment, "{}").instance.closure(&environment, {}, {})'.format( function_call.name, function_call.argument_count, # TODO This is just a single item containing a reference to the items list--make that clearer @@ -73,11 +73,15 @@ def generate_function_call(function_call): ) def generate_expression_statement(statement): + # TODO Do this at an earlier pass + if isinstance(statement.expression, transformation.CVariableExpression): + return ''; + # TODO Do we need to garbage collect the results of arbitrary statements? return '{};'.format(generate_expression(statement.expression)) def generate_symbol_assignment_statement(c_assignment_statement): - return 'Environment_set(environment, SYMBOL_LIST[{}] /* symbol: {} */, {});'.format( + return 'Environment_set(&environment, SYMBOL_LIST[{}] /* symbol: {} */, {});'.format( c_assignment_statement.target_symbol_list_index, c_assignment_statement.target, generate_expression(c_assignment_statement.expression), @@ -107,14 +111,38 @@ def indent(s): def generate_if_else_statement(statement): # TODO Check that the argument is boolean - return 'if({}.instance.boolean)\n{{\n{}\n}}\nelse\n{{\n{}\n}}'.format( + condition_expression = '{}.instance.boolean'.format( generate_expression(statement.condition_expression), - indent('\n'.join(generate_statement(s) for s in statement.if_statements)), - indent('\n'.join(generate_statement(s) for s in statement.else_statements)), ) + if len(statement.if_statements) == 0: + condition_expression = '!({})'.format(condition_expression) + if_statements = statement.else_statements + else_statements = () + else: + if_statements = statement.if_statements + else_statements = statement.else_statements + + generated_if_clause = 'if({})'.format(condition_expression) + + if len(if_statements) == 0: + generated_if_statements = ';' + else: + generated_if_statements = indent('\n{{\n{}\n}}'.format( + indent('\n'.join(generate_statement(s) for s in if_statements)), + )) + + if len(else_statements) == 0: + generated_else_statements = '' + else: + generated_else_statements = indent('\nelse\n{{\n{}\n}}'.format( + indent('\n'.join(generate_statement(s) for s in else_statements)), + )) + + return generated_if_clause + generated_if_statements + generated_else_statements + def generate_function_declaration(statement): - return 'Environment_set(environment, "{}", user${});'.format(statement.name, statement.name) + return 'Environment_set(&environment, "{}", user${});'.format(statement.name, statement.name) def generate_statement(statement): return { diff --git a/normalization.py b/normalization.py index 6f27b55..3fa52ac 100644 --- a/normalization.py +++ b/normalization.py @@ -302,8 +302,11 @@ def normalize_expression(counter, expression): }[type(expression)](counter, expression) def normalize_expression_statement(counter, statement): + # TODO Verify all expression types are supported and just call normalize_expression counter, prestatements, normalized = { parsing.FurFunctionCallExpression: normalize_function_call_expression, + parsing.FurSymbolExpression: normalize_expression, + parsing.FurInfixExpression: normalize_expression, parsing.FurIntegerLiteralExpression: normalize_expression, }[type(statement.expression)](counter, statement.expression) diff --git a/templates/program.c b/templates/program.c index 73d9334..0cab0c8 100644 --- a/templates/program.c +++ b/templates/program.c @@ -14,6 +14,10 @@ union Instance; typedef union Instance Instance; struct Object; typedef struct Object Object; +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 %} @@ -38,7 +42,7 @@ enum Type union Instance { bool boolean; - Object (*closure)(size_t, Object*); + Object (*closure)(Environment*, size_t, Object*); int32_t integer; const char* string; }; @@ -59,8 +63,6 @@ const Object FALSE = { false }; -struct EnvironmentNode; -typedef struct EnvironmentNode EnvironmentNode; struct EnvironmentNode { const char* key; @@ -68,22 +70,19 @@ struct EnvironmentNode EnvironmentNode* next; }; -struct Environment; -typedef struct Environment Environment; struct Environment { + 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; } -void Environment_destruct(Environment* self) +void Environment_deinitialize(Environment* self) { EnvironmentNode* next; for(EnvironmentNode* node = self->root; node != NULL; node = next) @@ -115,6 +114,11 @@ Object Environment_get(Environment* self, const char* const symbol) } } + if(self->parent != NULL) + { + return Environment_get(self->parent, symbol); + } + // TODO Handle symbol errors assert(false); } @@ -274,7 +278,7 @@ Object operator$or(Object left, Object right) } {% if 'pow' in builtins %} -Object builtin$pow$implementation(size_t argc, Object* args) +Object builtin$pow$implementation(Environment* parent, size_t argc, Object* args) { assert(argc == 2); @@ -294,7 +298,7 @@ Object builtin$pow = { CLOSURE, (Instance)builtin$pow$implementation }; {% endif %} {% if 'print' in builtins %} -Object builtin$print$implementation(size_t argc, Object* args) +Object builtin$print$implementation(Environment* parent, size_t argc, Object* args) { for(size_t i = 0; i < argc; i++) { @@ -327,16 +331,17 @@ Object builtin$print = { CLOSURE, (Instance)builtin$print$implementation }; {% endif %} {% for function_definition in function_definition_list %} -Object user${{function_definition.name}}$implementation(size_t argc, Object* args) +Object user${{function_definition.name}}$implementation(Environment* parent, size_t argc, Object* args) { - Environment* environment = Environment_construct(); + Environment environment; + Environment_initialize(&environment, parent); - {% for statement in function_definition.statement_list %} + {% for statement in function_definition.statement_list[:-1] %} {{ generate_statement(statement) }} {% endfor %} Object result = {{ generate_statement(function_definition.statement_list[-1]) }} - Environment_destruct(environment); + Environment_deinitialize(&environment); return result; } @@ -345,18 +350,19 @@ Object user${{function_definition.name}} = { CLOSURE, (Instance)user${{function_ int main(int argc, char** argv) { - Environment* environment = Environment_construct(); + Environment environment; + Environment_initialize(&environment, NULL); // TODO Use the symbol from SYMBOL_LIST {% for builtin in builtins %} - Environment_set(environment, "{{ builtin }}", builtin${{ builtin }}); + Environment_set(&environment, "{{ builtin }}", builtin${{ builtin }}); {% endfor %} {% for statement in statements %} {{ generate_statement(statement) }} {% endfor %} - Environment_destruct(environment); + Environment_deinitialize(&environment); return 0; } diff --git a/transformation.py b/transformation.py index 2825257..5fb853c 100644 --- a/transformation.py +++ b/transformation.py @@ -294,10 +294,14 @@ def transform_function_call_expression(accumulators, function_call): ) def transform_expression_statement(accumulators, statement): + # TODO At some point we can verify that all expression types are supported and just call transform_expression expression = { parsing.FurFunctionCallExpression: transform_function_call_expression, + parsing.FurInfixExpression: transform_expression, parsing.FurIntegerLiteralExpression: transform_expression, + parsing.FurSymbolExpression: transform_expression, normalization.NormalFunctionCallExpression: transform_function_call_expression, + normalization.NormalVariableExpression: transform_expression, }[type(statement.expression)](accumulators, statement.expression) return CExpressionStatement( -- 2.20.1