From 74c7456042282dd86f9be673cbd1e00496b28710 Mon Sep 17 00:00:00 2001 From: David Kerkeslager Date: Sat, 12 Aug 2017 14:01:11 -0400 Subject: [PATCH] Add support for parenthesized functions --- examples/23_parenthesized_functions.fur | 10 ++++++++++ examples/23_parenthesized_functions.fur.output.txt | 2 ++ generation.py | 8 ++++---- normalization.py | 10 +++++++++- parsing.py | 10 ++++++++-- transformation.py | 10 ++++++---- 6 files changed, 39 insertions(+), 11 deletions(-) create mode 100644 examples/23_parenthesized_functions.fur create mode 100644 examples/23_parenthesized_functions.fur.output.txt diff --git a/examples/23_parenthesized_functions.fur b/examples/23_parenthesized_functions.fur new file mode 100644 index 0000000..9cf111e --- /dev/null +++ b/examples/23_parenthesized_functions.fur @@ -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 index 0000000..daaac9e --- /dev/null +++ b/examples/23_parenthesized_functions.fur.output.txt @@ -0,0 +1,2 @@ +42 +42 diff --git a/generation.py b/generation.py index a1e85f1..4bcf138 100644 --- a/generation.py +++ b/generation.py @@ -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, diff --git a/normalization.py b/normalization.py index 9505b33..a5863a1 100644 --- a/normalization.py +++ b/normalization.py @@ -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), ), diff --git a/parsing.py b/parsing.py index 42f0ec8..7240b52 100644 --- a/parsing.py +++ b/parsing.py @@ -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 diff --git a/transformation.py b/transformation.py index 0eed799..83fc36b 100644 --- a/transformation.py +++ b/transformation.py @@ -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), ) -- 2.20.1