From aa339c441f43849a8cae256aa130278ca7618b7e Mon Sep 17 00:00:00 2001 From: David Kerkeslager Date: Fri, 5 Jan 2018 00:00:52 -0500 Subject: [PATCH] Added lambda expressions --- conversion.py | 15 ++++++++ desugaring.py | 15 ++++++++ examples/30_lambda.fur | 8 ++++ examples/30_lambda.fur.stdout.txt | 2 + generation.py | 11 +++++- normalization.py | 32 ++++++++++++++++ parsing.py | 61 ++++++++++++++++++++++++++++++- tokenization.py | 2 +- transformation.py | 36 ++++++++++++++++-- 9 files changed, 175 insertions(+), 7 deletions(-) create mode 100644 examples/30_lambda.fur create mode 100644 examples/30_lambda.fur.stdout.txt diff --git a/conversion.py b/conversion.py index 965f86e..fd469fa 100644 --- a/conversion.py +++ b/conversion.py @@ -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, diff --git a/desugaring.py b/desugaring.py index e671e04..c951fd5 100644 --- a/desugaring.py +++ b/desugaring.py @@ -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 index 0000000..f5ecb8a --- /dev/null +++ b/examples/30_lambda.fur @@ -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 index 0000000..b4db3ed --- /dev/null +++ b/examples/30_lambda.fur.stdout.txt @@ -0,0 +1,2 @@ +43 +44 diff --git a/generation.py b/generation.py index 348cb18..6c1cf0b 100644 --- a/generation.py +++ b/generation.py @@ -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( diff --git a/normalization.py b/normalization.py index 9fdabd9..9725b5b 100644 --- a/normalization.py +++ b/normalization.py @@ -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, diff --git a/parsing.py b/parsing.py index 014d74b..20ac376 100644 --- a/parsing.py +++ b/parsing.py @@ -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, ) diff --git a/tokenization.py b/tokenization.py index 88576bd..819a0de 100644 --- a/tokenization.py +++ b/tokenization.py @@ -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'\('), diff --git a/transformation.py b/transformation.py index e5a1bd5..e8ee51c 100644 --- a/transformation.py +++ b/transformation.py @@ -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=[], -- 2.20.1