Normalize symbol expressions
authorDavid Kerkeslager <kerkeslager@gmail.com>
Sun, 13 Aug 2017 19:18:11 +0000 (15:18 -0400)
committerDavid Kerkeslager <kerkeslager@gmail.com>
Sun, 13 Aug 2017 19:18:11 +0000 (15:18 -0400)
generation.py
normalization.py
templates/function_definition.c [new file with mode: 0644]
templates/program.c
transformation.py

index 4bcf138..1694e1f 100644 (file)
@@ -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,
index 618e5d9..4a16a3d 100644 (file)
@@ -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 (file)
index 0000000..3120fb9
--- /dev/null
@@ -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;
+}
index 2a08f39..3410e1b 100644 (file)
@@ -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);
index 34710bf..2661cef 100644 (file)
@@ -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]: