Added lambda expressions
authorDavid Kerkeslager <kerkeslager@gmail.com>
Fri, 5 Jan 2018 05:00:52 +0000 (00:00 -0500)
committerDavid Kerkeslager <kerkeslager@gmail.com>
Fri, 5 Jan 2018 05:00:52 +0000 (00:00 -0500)
conversion.py
desugaring.py
examples/30_lambda.fur [new file with mode: 0644]
examples/30_lambda.fur.stdout.txt [new file with mode: 0644]
generation.py
normalization.py
parsing.py
tokenization.py
transformation.py

index 965f86e..fd469fa 100644 (file)
@@ -18,6 +18,14 @@ CPSIntegerLiteralExpression = collections.namedtuple(
     ),
 )
 
+CPSLambdaExpression = collections.namedtuple(
+    'CPSLambdaExpression',
+    (
+        'argument_name_list',
+        'statement_list',
+    ),
+)
+
 CPSListConstructExpression = collections.namedtuple(
     'CPSListConstructExpression',
     (
@@ -152,6 +160,12 @@ def convert_function_call_expression(expression):
 def convert_integer_literal_expression(expression):
     return CPSIntegerLiteralExpression(integer=expression.integer)
 
+def convert_lambda_expression(expression):
+    return CPSLambdaExpression(
+        argument_name_list=expression.argument_name_list,
+        statement_list=tuple(convert_statement(s) for s in expression.statement_list),
+    )
+
 def convert_list_construct_expression(expression):
     return CPSListConstructExpression(allocate=expression.allocate)
 
@@ -175,6 +189,7 @@ def convert_expression(expression):
     return {
         normalization.NormalFunctionCallExpression: convert_function_call_expression,
         normalization.NormalIntegerLiteralExpression: convert_integer_literal_expression,
+        normalization.NormalLambdaExpression: convert_lambda_expression,
         normalization.NormalListConstructExpression: convert_list_construct_expression,
         normalization.NormalStringLiteralExpression: convert_string_literal_expression,
         normalization.NormalStructureLiteralExpression: convert_structure_literal_expression,
index e671e04..c951fd5 100644 (file)
@@ -27,6 +27,14 @@ DesugaredIntegerLiteralExpression = collections.namedtuple(
     ),
 )
 
+DesugaredLambdaExpression = collections.namedtuple(
+    'DesugaredLambdaExpression',
+    (
+        'argument_name_list',
+        'statement_list',
+    ),
+)
+
 DesugaredListLiteralExpression = collections.namedtuple(
     'DesugaredListLiteralExpression',
     (
@@ -187,6 +195,12 @@ def desugar_integer_literal_expression(expression):
         integer=expression.integer,
     )
 
+def desugar_lambda_expression(expression):
+    return DesugaredLambdaExpression(
+        argument_name_list=expression.argument_name_list,
+        statement_list=tuple(desugar_statement(s) for s in expression.statement_list),
+    )
+
 def desugar_list_item_expression(expression):
     return DesugaredFunctionCallExpression(
         metadata=expression.metadata,
@@ -244,6 +258,7 @@ def desugar_expression(expression):
         parsing.FurIfExpression: desugar_if_expression,
         parsing.FurInfixExpression: desugar_infix_expression,
         parsing.FurIntegerLiteralExpression: desugar_integer_literal_expression,
+        parsing.FurLambdaExpression: desugar_lambda_expression,
         parsing.FurListItemExpression: desugar_list_item_expression,
         parsing.FurListLiteralExpression: desugar_list_literal_expression,
         parsing.FurNegationExpression: desugar_negation_expression,
diff --git a/examples/30_lambda.fur b/examples/30_lambda.fur
new file mode 100644 (file)
index 0000000..f5ecb8a
--- /dev/null
@@ -0,0 +1,8 @@
+def incrementer(n) do
+  lambda(m) do
+    m + n
+  end
+end
+
+print(incrementer(1)(42), '\n')
+print(incrementer(2)(42), '\n')
diff --git a/examples/30_lambda.fur.stdout.txt b/examples/30_lambda.fur.stdout.txt
new file mode 100644 (file)
index 0000000..b4db3ed
--- /dev/null
@@ -0,0 +1,2 @@
+43
+44
index 348cb18..6c1cf0b 100644 (file)
@@ -33,6 +33,11 @@ def generate_structure_literal_expression(expression):
         expression.value_list_variable,
     )
 
+def generate_lambda_expression(expression):
+    return '(Object){{ CLOSURE, (Instance)(Closure){{ environment, user${}$implementation }} }}'.format(
+        expression.name,
+    )
+
 def generate_list_construct_expression(expression):
     return 'List_construct({})'.format(expression.allocate)
 
@@ -40,6 +45,7 @@ def generate_expression(expression):
     return {
         transformation.CFunctionCallExpression: generate_function_call,
         transformation.CIntegerLiteral: generate_integer_literal,
+        transformation.CLambdaExpression: generate_lambda_expression,
         transformation.CListConstructExpression: generate_list_construct_expression,
         transformation.CStringLiteral: generate_string_literal,
         transformation.CStructureLiteralExpression: generate_structure_literal_expression,
@@ -134,7 +140,10 @@ def generate_if_else_statement(statement):
     return generated_if_clause + generated_if_statement_list + generated_else_statement_list
 
 def generate_function_declaration(statement):
-    return 'Environment_set(environment, "{}", (Object){{ CLOSURE, (Instance)(Closure){{ environment, user${}$implementation }} }});'.format(statement.name, statement.name)
+    return 'Environment_set(environment, "{}", (Object){{ CLOSURE, (Instance)(Closure){{ environment, user${}$implementation }} }});'.format(
+        statement.name,
+        statement.name,
+    )
 
 def generate_list_append_statement(statement):
     return 'List_append(&{}, {});'.format(
index 9fdabd9..9725b5b 100644 (file)
@@ -17,6 +17,14 @@ NormalIntegerLiteralExpression = collections.namedtuple(
     ],
 )
 
+NormalLambdaExpression = collections.namedtuple(
+    'NormalLambdaExpression',
+    (
+        'argument_name_list',
+        'statement_list',
+    ),
+)
+
 NormalStringLiteralExpression = collections.namedtuple(
     'NormalStringLiteralExpression',
     [
@@ -132,6 +140,29 @@ def normalize_integer_literal_expression(counter, expression):
         NormalVariableExpression(variable=variable),
     )
 
+def normalize_lambda_expression(counter, expression):
+    variable = '${}'.format(counter)
+
+    _, statement_list = normalize_statement_list(
+        0,
+        expression.statement_list,
+        assign_result_to='result',
+    )
+
+    return (
+        counter + 1,
+        (
+            NormalVariableInitializationStatement(
+                variable=variable,
+                expression=NormalLambdaExpression(
+                    argument_name_list=expression.argument_name_list,
+                    statement_list=statement_list,
+                ),
+            ),
+        ),
+        NormalVariableExpression(variable=variable),
+    )
+
 NormalListConstructExpression = collections.namedtuple(
     'NormalListConstructExpression',
     [
@@ -380,6 +411,7 @@ def normalize_expression(counter, expression):
         desugaring.DesugaredFunctionCallExpression: normalize_function_call_expression,
         desugaring.DesugaredIfExpression: normalize_if_expression,
         desugaring.DesugaredIntegerLiteralExpression: normalize_integer_literal_expression,
+        desugaring.DesugaredLambdaExpression: normalize_lambda_expression,
         desugaring.DesugaredListLiteralExpression: normalize_list_literal_expression,
         desugaring.DesugaredStringLiteralExpression: normalize_string_literal_expression,
         desugaring.DesugaredStructureLiteralExpression: normalize_structure_literal_expression,
index 014d74b..20ac376 100644 (file)
@@ -43,6 +43,14 @@ FurIntegerLiteralExpression = collections.namedtuple(
     ],
 )
 
+FurLambdaExpression = collections.namedtuple(
+    'FurLambdaExpression',
+    (
+        'argument_name_list',
+        'statement_list',
+    ),
+)
+
 FurStringLiteralExpression = collections.namedtuple(
     'FurStringLiteralExpression',
     [
@@ -213,6 +221,56 @@ def _structure_literal_parser(index, tokens):
         ),
     )
 
+def _lambda_expression_parser(index, tokens):
+    failure = (False, index, None)
+
+    if tokens[index].type == 'keyword' and tokens[index].match == 'lambda':
+        index += 1
+    else:
+        return failure
+
+    if tokens[index].type == 'open_parenthese':
+        index += 1
+    else:
+        raise Exception('Expected "(", found "{}" on line {}'.format(
+            tokens[index].match,
+            tokens[index].metadata.line,
+        ))
+
+    success, index, argument_name_list = _comma_separated_list_parser(_symbol_expression_parser)(
+        index,
+        tokens,
+    )
+
+    if tokens[index].type == 'close_parenthese':
+        index += 1
+    else:
+        raise Exception('Expected ")", found "{}" on line {}'.format(
+            tokens[index].match,
+            tokens[index].line,
+        ))
+
+    if tokens[index].match == 'do':
+        index += 1
+    else:
+        return failure
+
+    success, index, statement_list = _zero_or_more_parser(tuple, _statement_parser)(index, tokens)
+
+    _, index, _ = consume_newlines(index, tokens)
+
+    if tokens[index].type == 'keyword' and tokens[index].match == 'end':
+        index += 1
+    else:
+        return failure
+
+    return True, index, FurLambdaExpression(
+        argument_name_list=tuple(an.symbol for an in argument_name_list),
+        statement_list=statement_list,
+    )
+
+
+
 def _list_literal_expression_parser(index, tokens):
     failure = (False, index, None)
 
@@ -233,6 +291,7 @@ def _literal_level_expression_parser(index, tokens):
         _integer_literal_expression_parser,
         _string_literal_expression_parser,
         _list_literal_expression_parser,
+        _lambda_expression_parser,
         _symbol_expression_parser,
         _structure_literal_parser,
     )(index, tokens)
@@ -642,7 +701,7 @@ def _function_definition_statement_parser(index, tokens):
 
     return True, index, FurFunctionDefinitionStatement(
         name=name,
-    argument_name_list=tuple(an.symbol for an in argument_name_list),
+        argument_name_list=tuple(an.symbol for an in argument_name_list),
         statement_list=statement_list,
     )
 
index 88576bd..819a0de 100644 (file)
@@ -46,7 +46,7 @@ def _make_token_matcher(definition):
     return token_matcher
 
 _TOKEN_MATCHERS = [
-    ('keyword',                         r'(def|do|else|end|if)(?![a-z_])'),
+    ('keyword',                         r'(def|do|else|end|if|lambda)(?![a-z_])'),
     ('open_bracket',                    r'\['),
     ('close_bracket',                   r'\]'),
     ('open_parenthese',                 r'\('),
index e5a1bd5..e8ee51c 100644 (file)
@@ -190,17 +190,24 @@ def transform_integer_literal_expression(accumulators, expression):
 
 CListConstructExpression = collections.namedtuple(
     'CListConstructExpression',
-    [
+    (
         'allocate',
-    ],
+    ),
+)
+
+CLambdaExpression = collections.namedtuple(
+    'CLambdaExpression',
+    (
+        'name',
+    ),
 )
 
 CListAppendStatement = collections.namedtuple(
     'CListAppendStatement',
-    [
+    (
         'list_expression',
         'item_expression',
-    ],
+    ),
 )
 
 def transform_structure_literal_expression(accumulators, expression):
@@ -210,6 +217,24 @@ def transform_structure_literal_expression(accumulators, expression):
         value_list_variable=expression.value_list_variable,
     )
 
+def transform_lambda_expression(accumulators, expression):
+    # TODO This function feels hacky
+    if len(accumulators.lambda_number_list) == 0:
+        accumulators.lambda_number_list.append(0)
+    else:
+        accumulators.lambda_number_list.append(accumulators.lambda_number_list[-1] + 1)
+
+    name = '__lambda_{}'.format(accumulators.lambda_number_list[-1])
+
+    accumulators.function_definition_list.append(CFunctionDefinition(
+        name=name,
+        argument_name_list=expression.argument_name_list,
+        statement_list=tuple(transform_statement(accumulators, s) for s in expression.statement_list),
+    ))
+
+    return CLambdaExpression(name=name)
+
+
 def transform_list_construct_expression(accumulators, expression):
     return CListConstructExpression(allocate=expression.allocate)
 
@@ -223,6 +248,7 @@ def transform_expression(accumulators, expression):
     return {
         conversion.CPSFunctionCallExpression: transform_function_call_expression,
         conversion.CPSIntegerLiteralExpression: transform_integer_literal_expression,
+        conversion.CPSLambdaExpression: transform_lambda_expression,
         conversion.CPSListConstructExpression: transform_list_construct_expression,
         conversion.CPSStructureLiteralExpression: transform_structure_literal_expression,
         conversion.CPSStringLiteralExpression: transform_string_literal_expression,
@@ -340,6 +366,7 @@ Accumulators = collections.namedtuple(
     [
         'builtin_set',
         'function_definition_list',
+        'lambda_number_list',
         'operator_set',
         'symbol_list',
         'string_literal_list',
@@ -350,6 +377,7 @@ def transform(program):
     accumulators = Accumulators(
         builtin_set=set(),
         function_definition_list=[],
+        lambda_number_list=[],
         operator_set=set(),
         symbol_list=[],
         string_literal_list=[],