A featureful commit:
authorDavid Kerkeslager <kerkeslager@gmail.com>
Wed, 9 Aug 2017 18:26:10 +0000 (14:26 -0400)
committerDavid Kerkeslager <kerkeslager@gmail.com>
Wed, 9 Aug 2017 18:32:19 +0000 (14:32 -0400)
* 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 [new file with mode: 0644]
examples/17_short_circuiting.fur.output.txt [new file with mode: 0644]
generation.py
normalization.py
templates/program.c
transformation.py

diff --git a/examples/17_short_circuiting.fur b/examples/17_short_circuiting.fur
new file mode 100644 (file)
index 0000000..f70e7b9
--- /dev/null
@@ -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 (file)
index 0000000..21ff499
--- /dev/null
@@ -0,0 +1,3 @@
+This should only print once.
+This should print exactly twice.
+This should print exactly twice.
index c058f91..b48342a 100644 (file)
@@ -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 {
index 6f27b55..3fa52ac 100644 (file)
@@ -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)
 
index 73d9334..0cab0c8 100644 (file)
@@ -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;
 }
index 2825257..5fb853c 100644 (file)
@@ -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(