Add support for parenthesized functions
authorDavid Kerkeslager <kerkeslager@gmail.com>
Sat, 12 Aug 2017 18:01:11 +0000 (14:01 -0400)
committerDavid Kerkeslager <kerkeslager@gmail.com>
Sat, 12 Aug 2017 18:01:11 +0000 (14:01 -0400)
examples/23_parenthesized_functions.fur [new file with mode: 0644]
examples/23_parenthesized_functions.fur.output.txt [new file with mode: 0644]
generation.py
normalization.py
parsing.py
transformation.py

diff --git a/examples/23_parenthesized_functions.fur b/examples/23_parenthesized_functions.fur
new file mode 100644 (file)
index 0000000..9cf111e
--- /dev/null
@@ -0,0 +1,10 @@
+def make_incrementer(increment_amount) do
+  def result(i) do
+    increment_amount + i
+  end
+
+  result
+end
+
+print((make_incrementer(1))(41), '\n')
+print((make_incrementer(2))(40), '\n')
diff --git a/examples/23_parenthesized_functions.fur.output.txt b/examples/23_parenthesized_functions.fur.output.txt
new file mode 100644 (file)
index 0000000..daaac9e
--- /dev/null
@@ -0,0 +1,2 @@
+42
+42
index a1e85f1..4bcf138 100644 (file)
@@ -66,10 +66,10 @@ def generate_negation_expression(c_negation_expression):
 
 def generate_function_call(function_call):
     # TODO This gets called twice, which is really inefficient--normalization would also allow other clauses besides a variable reference
-    get_closure_clause = 'Environment_get(environment, "{}").instance.closure'.format(
-        function_call.name,
-    )
-    return '{}.call(environmentPool, {}.closed, {}, {})'.format(
+    # TODO This should no longer be called "name", as it can be an expression of a few types
+    # TODO Check the type of the things being called
+    get_closure_clause = generate_expression(function_call.name)
+    return '{}.instance.closure.call(environmentPool, {}.instance.closure.closed, {}, {})'.format(
         get_closure_clause,
         get_closure_clause,
         function_call.argument_count,
index 9505b33..a5863a1 100644 (file)
@@ -134,11 +134,19 @@ def normalize_function_call_expression(counter, expression):
         items=tuple(arguments),
     ))
 
+    counter, function_prestatements, function_expression = normalize_expression(
+        counter,
+        expression.function,
+    )
+
+    for ps in function_prestatements:
+        prestatements.append(ps)
+
     return (
         counter,
         tuple(prestatements),
         NormalFunctionCallExpression(
-            function=expression.function, # TODO Normalize the function
+            function=function_expression,
             argument_count=len(arguments),
             argument_items=NormalVariableExpression(variable=arguments_variable),
         ),
index 42f0ec8..7240b52 100644 (file)
@@ -274,10 +274,16 @@ FurProgram = collections.namedtuple(
 )
 
 def _function_call_expression_parser(index, tokens):
-    # TODO Use a FurSymbolExpression for the name
+    # TODO Allow function calls as the source of the function. This requires a
+    # left-recursive parser, however.
     failure = (False, index, None)
 
-    success, index, function = _symbol_expression_parser(index, tokens)
+    # We have to be careful what expressions we add here. Otherwise expressions
+    # like "a + b()" become ambiguous to the parser.
+    success, index, function = _or_parser(
+        _symbol_expression_parser,
+        _parenthesized_expression_parser,
+    )(index, tokens)
 
     if not success:
         return failure
index 0eed799..83fc36b 100644 (file)
@@ -292,13 +292,15 @@ def transform_symbol_assignment_statement(accumulators, assignment_statement):
     )
 
 def transform_function_call_expression(accumulators, function_call):
-    if function_call.function.value in BUILTINS.keys():
-        # TODO Check that the builtin is actually callable
-        accumulators.builtin_set.add(function_call.function.value)
+    if isinstance(function_call.function, parsing.FurSymbolExpression):
+        # TODO Move this check to transformation of symbol expressions so we can have builtins that aren't functions
+        if function_call.function.value in BUILTINS.keys():
+            # TODO Check that the builtin is actually callable
+            accumulators.builtin_set.add(function_call.function.value)
 
     # TODO Use the symbol from SYMBOL LIST
     return CFunctionCallExpression(
-        name=function_call.function.value,
+        name=transform_expression(accumulators, function_call.function),
         argument_count=function_call.argument_count,
         argument_items=transform_expression(accumulators, function_call.argument_items),
     )