From 3da330f045ed7fcb66ee9d9447de320680263699 Mon Sep 17 00:00:00 2001 From: David Kerkeslager Date: Sun, 13 Aug 2017 15:18:11 -0400 Subject: [PATCH] Normalize symbol expressions --- generation.py | 27 ++++++++++------------- normalization.py | 16 +++++++++----- templates/function_definition.c | 21 ++++++++++++++++++ templates/program.c | 39 +++++---------------------------- transformation.py | 22 ++++++------------- 5 files changed, 56 insertions(+), 69 deletions(-) create mode 100644 templates/function_definition.c diff --git a/generation.py b/generation.py index 4bcf138..1694e1f 100644 --- a/generation.py +++ b/generation.py @@ -14,14 +14,6 @@ def generate_integer_literal(c_integer_literal): def generate_string_literal(c_string_literal): return 'stringLiteral(STRING_LITERAL_LIST[{}])'.format(c_string_literal.index) -CONSTANT_EXPRESSION_MAPPING = { - 'true': 'TRUE', - 'false': 'FALSE', -} - -def generate_constant_expression(c_constant_expression): - return CONSTANT_EXPRESSION_MAPPING[c_constant_expression.value] - def generate_symbol_expression(symbol_expression): return 'Environment_get(environment, SYMBOL_LIST[{}] /* symbol: {} */)'.format( symbol_expression.symbol_list_index, @@ -41,7 +33,6 @@ def generate_expression(expression): LITERAL_TYPE_MAPPING = { transformation.CIntegerLiteral: generate_integer_literal, transformation.CStringLiteral: generate_string_literal, - transformation.CConstantExpression: generate_constant_expression, transformation.CSymbolExpression: generate_symbol_expression, } @@ -78,10 +69,6 @@ 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)) @@ -160,14 +147,22 @@ def generate_statement(statement): transformation.CVariableReassignmentStatement: generate_variable_reassignment_statement, }[type(statement)](statement) +def generate_function_definition(definition): + template = ENV.get_template('function_definition.c') + return template.render( + name=definition.name, + argument_name_list=definition.argument_name_list, + statement_list=list(generate_statement(s) for s in definition.statement_list), + ) + return definition + def generate(program): template = ENV.get_template('program.c') return template.render( builtins=tuple(sorted(program.builtin_set)), - function_definition_list=program.function_definition_list, - generate_statement=generate_statement, + function_definition_list=list(generate_function_definition(fd) for fd in program.function_definition_list), infix_declarations=program.operator_declarations, - statements=program.statements, + statements=list(generate_statement(s) for s in program.statements), standard_libraries=list(sorted(program.standard_libraries)), string_literal_list=program.string_literal_list, symbol_list=program.symbol_list, diff --git a/normalization.py b/normalization.py index 618e5d9..4a16a3d 100644 --- a/normalization.py +++ b/normalization.py @@ -141,11 +141,14 @@ def normalize_string_literal_expression(counter, expression): ) def normalize_symbol_expression(counter, expression): - # TODO Store this in a C variable + variable = '${}'.format(counter) return ( - counter, - (), - NormalSymbolExpression(symbol=expression.symbol), + counter + 1, + (NormalVariableInitializationStatement( + variable=variable, + expression=NormalSymbolExpression(symbol=expression.symbol), + ),), + NormalVariableExpression(variable=variable), ) def normalize_function_call_expression(counter, expression): @@ -358,6 +361,10 @@ def normalize_expression(counter, expression): }[type(expression)](counter, expression) def normalize_expression_statement(counter, statement): + # TODO Normalized will be a NormalVariableExpression, which will go unused + # for expression statements in every case except when it's a return + # statement. This cases warnings on C compilation. We should only generate + # this variable when it will be used on return. counter, prestatements, normalized = normalize_expression(counter, statement.expression) return ( @@ -406,7 +413,6 @@ def normalize_statement_list(statement_list): yield normalized def normalize(program): - return NormalProgram( statement_list=normalize_statement_list(program.statement_list), ) diff --git a/templates/function_definition.c b/templates/function_definition.c new file mode 100644 index 0000000..3120fb9 --- /dev/null +++ b/templates/function_definition.c @@ -0,0 +1,21 @@ + +Object user${{name}}$implementation(EnvironmentPool* environmentPool, Environment* parent, size_t argc, Object* args) +{ + assert(argc == {{ argument_name_list|length }}); + + Environment* environment = EnvironmentPool_allocate(environmentPool); + Environment_initialize(environment, parent); + + {% for argument_name in argument_name_list %} + Environment_set(environment, "{{ argument_name }}", args[{{ loop.index0 }}]); + {% endfor %} + + {% for statement in statement_list[:-1] %} + {{ statement }} + {% endfor %} + + Object result = {{ statement_list[-1] }} + + Environment_setLive(environment, false); + return result; +} diff --git a/templates/program.c b/templates/program.c index 2a08f39..3410e1b 100644 --- a/templates/program.c +++ b/templates/program.c @@ -77,15 +77,8 @@ struct Object Instance instance; }; -const Object TRUE = { - BOOLEAN, - { true } -}; - -const Object FALSE = { - BOOLEAN, - { false } -}; +const Object builtin$true = { BOOLEAN, (Instance)(bool){ true } }; +const Object builtin$false = { BOOLEAN, (Instance)(bool){ false } }; struct EnvironmentNode { @@ -404,35 +397,15 @@ Object builtin$print$implementation(EnvironmentPool* environmentPool, Environmen } // TODO Return something better - return FALSE; + return builtin$false; } Object builtin$print = { CLOSURE, (Instance)(Closure){ NULL, builtin$print$implementation } }; {% endif %} - {% for function_definition in function_definition_list %} -Object user${{function_definition.name}}$implementation(EnvironmentPool* environmentPool, Environment* parent, size_t argc, Object* args) -{ - assert(argc == {{ function_definition.argument_name_list|length }}); - - Environment* environment = EnvironmentPool_allocate(environmentPool); - Environment_initialize(environment, parent); - - {% 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; -} - +{{ function_definition }} {% endfor %} + int main(int argc, char** argv) { EnvironmentPool* environmentPool = EnvironmentPool_construct(); @@ -445,7 +418,7 @@ int main(int argc, char** argv) {% endfor %} {% for statement in statements %} - {{ generate_statement(statement) }} + {{ statement }} {% endfor %} Environment_setLive(environment, false); diff --git a/transformation.py b/transformation.py index 34710bf..2661cef 100644 --- a/transformation.py +++ b/transformation.py @@ -18,13 +18,6 @@ CStringLiteral = collections.namedtuple( ], ) -CConstantExpression = collections.namedtuple( - 'CConstantExpression', - [ - 'value' - ], -) - CVariableExpression = collections.namedtuple( 'CVariableExpression', [ @@ -168,8 +161,8 @@ def transform_string_literal_expression(accumulators, expression): return CStringLiteral(index=index, value=value) def transform_symbol_expression(accumulators, expression): - if expression.symbol in ['true', 'false']: - return CConstantExpression(value=expression.symbol) + if expression.symbol in BUILTINS: + accumulators.builtin_set.add(expression.symbol) try: symbol_list_index = accumulators.symbol_list.index(expression.symbol) @@ -297,12 +290,6 @@ def transform_symbol_assignment_statement(accumulators, assignment_statement): ) def transform_function_call_expression(accumulators, function_call): - if isinstance(function_call.function, normalization.NormalSymbolExpression): - # TODO Move this check to transformation of symbol expressions so we can have builtins that aren't functions - if function_call.function.symbol in BUILTINS.keys(): - # TODO Check that the builtin is actually callable - accumulators.builtin_set.add(function_call.function.symbol) - # TODO Use the symbol from SYMBOL LIST return CFunctionCallExpression( name=transform_expression(accumulators, function_call.function), @@ -391,6 +378,11 @@ def transform(program): transform_statement(accumulators, statement) for statement in program.statement_list ] + # This prevents warnings about normalized variables being entire C statements + last_statement = statement_list[-1] + if isinstance(last_statement, normalization.NormalExpressionStatement) and isinstance(last_statement.expression, normalization.NormalVariableExpression): + del statement_list[-1] + standard_library_set = set() for builtin in accumulators.builtin_set: for standard_library in BUILTINS[builtin]: -- 2.20.1