From 3a076cfd2c46c9f3b51815facd613445722a340b Mon Sep 17 00:00:00 2001 From: David Kerkeslager Date: Sat, 30 Dec 2017 22:38:04 -0500 Subject: [PATCH] Desugaring pass (#9) * Implemented the desugaring pass, except for exception support; also badly needs cleanup of dead code * Pass through metadata to end of desugaring phase (for error reporting) * Pass through more metadata, package it at tokenization phase * Added error handling to desugared code * Add line numbers to function call errors, clean up * Delete dead code --- desugaring.py | 272 ++++++++++++++++- examples/29_division_by_zero.fur.stderr.txt | 2 +- generation.py | 24 +- normalization.py | 229 +-------------- parsing.py | 42 ++- templates/function_definition.c | 3 +- templates/program.c | 308 ++++++++++++++++++-- tokenization.py | 20 +- transformation.py | 105 +------ 9 files changed, 615 insertions(+), 390 deletions(-) diff --git a/desugaring.py b/desugaring.py index ef51639..e671e04 100644 --- a/desugaring.py +++ b/desugaring.py @@ -1,5 +1,93 @@ import collections +import parsing + +DesugaredFunctionCallExpression = collections.namedtuple( + 'DesugaredFunctionCallExpression', + ( + 'metadata', + 'function', + 'argument_list', + ), +) + +DesugaredIfExpression = collections.namedtuple( + 'DesugaredIfExpression', + ( + 'condition_expression', + 'if_statement_list', + 'else_statement_list', + ), +) + +DesugaredIntegerLiteralExpression = collections.namedtuple( + 'DesugaredIntegerLiteralExpression', + ( + 'integer', + ), +) + +DesugaredListLiteralExpression = collections.namedtuple( + 'DesugaredListLiteralExpression', + ( + 'item_expression_list', + ), +) + +DesugaredStringLiteralExpression = collections.namedtuple( + 'DesugaredStringLiteralExpression', + ( + 'string', + ), +) + +DesugaredSymbolExpressionPair = collections.namedtuple( + 'DesugaredSymbolExpressionPair', + ( + 'symbol', + 'expression', + ), +) + +DesugaredStructureLiteralExpression = collections.namedtuple( + 'DesugaredStructureLiteralExpression', + ( + 'fields', + ), +) + +DesugaredSymbolExpression = collections.namedtuple( + 'DesugaredSymbolExpression', + ( + 'metadata', + 'symbol', + ), +) + +DesugaredAssignmentStatement = collections.namedtuple( + 'DesugaredAssignmentStatement', + ( + 'target', + 'expression', + ), +) + +DesugaredExpressionStatement = collections.namedtuple( + 'DesugaredExpressionStatement', + ( + 'expression', + ), +) + +DesugaredFunctionDefinitionStatement = collections.namedtuple( + 'DesugaredFunctionDefinitionStatement', + ( + 'name', + 'argument_name_list', + 'statement_list', + ), +) + DesugaredProgram = collections.namedtuple( 'DesugaredProgram', ( @@ -7,7 +95,189 @@ DesugaredProgram = collections.namedtuple( ), ) +def desugar_function_call_expression(expression): + return DesugaredFunctionCallExpression( + metadata=expression.metadata, + function=desugar_expression(expression.function), + argument_list=tuple(desugar_expression(e) for e in expression.arguments), + ) + +def desugar_if_expression(expression): + return DesugaredIfExpression( + condition_expression=desugar_expression(expression.condition_expression), + if_statement_list=tuple(desugar_statement(s) for s in expression.if_statement_list), + else_statement_list=tuple(desugar_statement(s) for s in expression.else_statement_list), + ) + +def desugar_infix_expression(expression): + if expression.operator == 'and': + return DesugaredIfExpression( + condition_expression=desugar_expression(expression.left), + if_statement_list=( + DesugaredExpressionStatement(expression=desugar_expression(expression.right)), + ), + else_statement_list=( + DesugaredExpressionStatement( + expression=DesugaredSymbolExpression( + metadata=expression.metadata, + symbol='false', + ), + ), + ), + ) + + if expression.operator == 'or': + return DesugaredIfExpression( + condition_expression=desugar_expression(expression.left), + if_statement_list=( + DesugaredExpressionStatement( + expression=DesugaredSymbolExpression( + metadata=expression.metadata, + symbol='true', + ), + ), + ), + else_statement_list=( + DesugaredExpressionStatement(expression=desugar_expression(expression.right)), + ), + ) + + if expression.operator == '.': + return DesugaredFunctionCallExpression( + metadata=expression.metadata, + function=DesugaredSymbolExpression( + metadata=expression.metadata, + symbol='__field__', + ), + argument_list=( + desugar_expression(expression.left), + DesugaredStringLiteralExpression(string=expression.right.symbol), + ), + ) + + function = { + '++': '__concat__', + '+': '__add__', + '-': '__subtract__', + '*': '__multiply__', + '//': '__integer_divide__', + '%': '__modular_divide__', + '<': '__lt__', + '>': '__gt__', + '<=': '__lte__', + '>=': '__gte__', + '==': '__eq__', + '!=': '__neq__', + }[expression.operator] + + return DesugaredFunctionCallExpression( + metadata=expression.metadata, + function=DesugaredSymbolExpression( + metadata=expression.metadata, + symbol=function, + ), + argument_list=( + desugar_expression(expression.left), + desugar_expression(expression.right), + ), + ) + +def desugar_integer_literal_expression(expression): + return DesugaredIntegerLiteralExpression( + integer=expression.integer, + ) + +def desugar_list_item_expression(expression): + return DesugaredFunctionCallExpression( + metadata=expression.metadata, + function=DesugaredSymbolExpression( + metadata=expression.metadata, + symbol='__get__', + ), + argument_list=( + desugar_expression(expression.list_expression), + desugar_expression(expression.index_expression), + ), + ) + +def desugar_list_literal_expression(expression): + return DesugaredListLiteralExpression( + item_expression_list=tuple(desugar_expression(i) for i in expression.item_expression_list), + ) + +def desugar_negation_expression(expression): + return DesugaredFunctionCallExpression( + metadata=expression.metadata, + function=DesugaredSymbolExpression( + metadata=expression.metadata, + symbol='__negate__', + ), + argument_list=( + desugar_expression(expression.value), + ), + ) + +def desugar_string_literal_expression(expression): + return DesugaredStringLiteralExpression( + string=expression.string, + ) + +def desugar_structure_literal_expression(expression): + return DesugaredStructureLiteralExpression( + fields=tuple( + DesugaredSymbolExpressionPair( + symbol=p.symbol, + expression=desugar_expression(p.expression), + ) for p in expression.fields + ), + ) + +def desugar_symbol_expression(expression): + return DesugaredSymbolExpression( + metadata=expression.metadata, + symbol=expression.symbol, + ) + +def desugar_expression(expression): + return { + parsing.FurFunctionCallExpression: desugar_function_call_expression, + parsing.FurIfExpression: desugar_if_expression, + parsing.FurInfixExpression: desugar_infix_expression, + parsing.FurIntegerLiteralExpression: desugar_integer_literal_expression, + parsing.FurListItemExpression: desugar_list_item_expression, + parsing.FurListLiteralExpression: desugar_list_literal_expression, + parsing.FurNegationExpression: desugar_negation_expression, + parsing.FurStringLiteralExpression: desugar_string_literal_expression, + parsing.FurStructureLiteralExpression: desugar_structure_literal_expression, + parsing.FurSymbolExpression: desugar_symbol_expression, + }[type(expression)](expression) + +def desugar_assignment_statement(statement): + return DesugaredAssignmentStatement( + target=statement.target, + expression=desugar_expression(statement.expression), + ) + +def desugar_expression_statement(statement): + return DesugaredExpressionStatement( + expression=desugar_expression(statement.expression), + ) + +def desugar_function_definition_statement(statement): + return DesugaredFunctionDefinitionStatement( + name=statement.name, + argument_name_list=statement.argument_name_list, + statement_list=tuple(desugar_statement(s) for s in statement.statement_list), + ) + +def desugar_statement(statement): + return { + parsing.FurAssignmentStatement: desugar_assignment_statement, + parsing.FurExpressionStatement: desugar_expression_statement, + parsing.FurFunctionDefinitionStatement: desugar_function_definition_statement, + }[type(statement)](statement) + def desugar(program): return DesugaredProgram( - statement_list=program.statement_list, + statement_list=[desugar_statement(s) for s in program.statement_list], ) diff --git a/examples/29_division_by_zero.fur.stderr.txt b/examples/29_division_by_zero.fur.stderr.txt index 9d45c1d..7b22109 100644 --- a/examples/29_division_by_zero.fur.stderr.txt +++ b/examples/29_division_by_zero.fur.stderr.txt @@ -1,3 +1,3 @@ DivisionByZeroError on line 2 - in get_divided_answer + in get_divided_answer on line 5 in __main__ diff --git a/generation.py b/generation.py index 64554d0..b2e191e 100644 --- a/generation.py +++ b/generation.py @@ -26,12 +26,6 @@ def generate_symbol_expression(symbol_expression): def generate_variable_expression(expression): return expression.variable -def generate_function_call_for_fur_infix_operator(expression): - return 'operator${}(stack, jump, {})'.format( - expression.name, - expression.metadata.line, - ) - def generate_structure_literal_expression(expression): return 'Structure_construct({}, {}, {})'.format( expression.field_count, @@ -39,13 +33,6 @@ def generate_structure_literal_expression(expression): expression.value_list_variable, ) -def generate_dot_expression(expression): - return 'Structure_get(&{}, SYMBOL_LIST[{}] /* symbol: "{}" */)'.format( - generate_variable_expression(expression.instance), - expression.symbol_list_index, - expression.symbol, - ) - def generate_list_construct_expression(expression): return 'List_construct({})'.format(expression.allocate) @@ -57,34 +44,27 @@ def generate_list_get_expression(expression): def generate_expression(expression): return { - transformation.CDotExpression: generate_dot_expression, transformation.CFunctionCallExpression: generate_function_call, - transformation.CFunctionCallForFurInfixOperator: generate_function_call_for_fur_infix_operator, transformation.CIntegerLiteral: generate_integer_literal, transformation.CListConstructExpression: generate_list_construct_expression, transformation.CListGetExpression: generate_list_get_expression, - transformation.CNegationExpression: generate_negation_expression, transformation.CStringLiteral: generate_string_literal, transformation.CStructureLiteralExpression: generate_structure_literal_expression, transformation.CSymbolExpression: generate_symbol_expression, transformation.CVariableExpression: generate_variable_expression, }[type(expression)](expression) -def generate_negation_expression(c_negation_expression): - return 'operator$negate({})'.format( - generate_expression(c_negation_expression.value) - ) - def generate_function_call(function_call): # This gets called twice, so we want to be sure it is efficient and without side effects assert isinstance(function_call.function_expression, transformation.CVariableExpression) # TODO Check the type of the things being called function_expression = generate_variable_expression(function_call.function_expression) - return '{}.instance.closure.call(environmentPool, {}.instance.closure.closed, {}, stack, jump)'.format( + return '{}.instance.closure.call(environmentPool, {}.instance.closure.closed, {}, stack, {}, jump)'.format( function_expression, function_expression, function_call.argument_count, + function_call.metadata.line, ) def generate_expression_statement(statement): diff --git a/normalization.py b/normalization.py index f2b7b13..40e3afd 100644 --- a/normalization.py +++ b/normalization.py @@ -1,6 +1,6 @@ import collections -import parsing +import desugaring import util NormalVariableExpression = collections.namedtuple( @@ -31,30 +31,6 @@ NormalSymbolExpression = collections.namedtuple( ], ) -NormalNegationExpression = collections.namedtuple( - 'NormalNegationExpression', - [ - 'internal_expression', - ], -) - -NormalDotExpression = collections.namedtuple( - 'NormalDotExpression', - [ - 'instance', - 'field', - ], -) - -NormalInfixExpression = collections.namedtuple( - 'NormalInfixExpression', - [ - 'metadata', - 'order', - 'operator', - ], -) - NormalPushStatement = collections.namedtuple( 'NormalPushStatement', ( @@ -65,6 +41,7 @@ NormalPushStatement = collections.namedtuple( NormalFunctionCallExpression = collections.namedtuple( 'NormalFunctionCallExpression', [ + 'metadata', 'function_expression', 'argument_count', ], @@ -142,9 +119,6 @@ NormalProgram = collections.namedtuple( ], ) -def fake_normalization(counter, thing): - return (counter, (), thing) - def normalize_integer_literal_expression(counter, expression): variable = '${}'.format(counter) return ( @@ -328,11 +302,9 @@ def normalize_symbol_expression(counter, expression): ) def normalize_function_call_expression(counter, expression): - assert isinstance(expression, parsing.FurFunctionCallExpression) - prestatements = [] - for argument in expression.arguments: + for argument in expression.argument_list: counter, argument_prestatements, normalized_argument = normalize_expression(counter, argument) for s in argument_prestatements: @@ -381,8 +353,9 @@ def normalize_function_call_expression(counter, expression): NormalVariableInitializationStatement( variable=result_variable, expression=NormalFunctionCallExpression( + metadata=expression.metadata, function_expression=function_expression, - argument_count=len(expression.arguments), + argument_count=len(expression.argument_list), ), ) ) @@ -393,156 +366,6 @@ def normalize_function_call_expression(counter, expression): NormalVariableExpression(variable=result_variable), ) -def normalize_basic_infix_operation(counter, expression): - counter, left_prestatements, left_expression = normalize_expression(counter, expression.left) - counter, right_prestatements, right_expression = normalize_expression(counter, expression.right) - - center_variable = '${}'.format(counter) - counter += 1 - - root_prestatements = ( - NormalPushStatement(expression=left_expression), - NormalPushStatement(expression=right_expression), - NormalVariableInitializationStatement( - variable=center_variable, - expression=NormalInfixExpression( - metadata=expression.metadata, - order=expression.order, - operator=expression.operator, - ), - ), - ) - - return ( - counter, - left_prestatements + right_prestatements + root_prestatements, - NormalVariableExpression(variable=center_variable), - ) - -def desugar_ternary_comparison(counter, expression): - counter, left_prestatements, left_expression = normalize_expression(counter, expression.left.left) - counter, middle_prestatements, middle_expression = normalize_expression(counter, expression.left.right) - - left_variable = '${}'.format(counter) - counter += 1 - middle_variable = '${}'.format(counter) - counter += 1 - - # TODO Is there a memory leak if the middle expression throws an exception because the first expression result hasn't been added to the stack? - juncture_prestatements = ( - NormalVariableInitializationStatement( - variable=left_variable, - expression=left_expression, - ), - NormalVariableInitializationStatement( - variable=middle_variable, - expression=middle_expression, - ) - ) - - counter, boolean_expression_prestatements, boolean_expression = normalize_boolean_expression( - counter, - parsing.FurInfixExpression( - metadata=expression.left.metadata, - order='and_level', - operator='and', - left=parsing.FurInfixExpression( - metadata=expression.left.metadata, - order='comparison_level', - operator=expression.left.operator, - left=NormalVariableExpression(variable=left_variable), - right=NormalVariableExpression(variable=middle_variable), - ), - right=parsing.FurInfixExpression( - metadata=expression.metadata, - order='comparison_level', - operator=expression.operator, - left=NormalVariableExpression(variable=middle_variable), - right=expression.right, - ), - ) - ) - - return ( - counter, - left_prestatements + middle_prestatements + juncture_prestatements + boolean_expression_prestatements, - boolean_expression, - ) - -def normalize_comparison_expression(counter, expression): - if isinstance(expression.left, parsing.FurInfixExpression) and expression.order == 'comparison_level': - return desugar_ternary_comparison(counter, expression) - - return normalize_basic_infix_operation(counter, expression) - -def normalize_boolean_expression(counter, expression): - counter, left_prestatements, left_expression = normalize_expression(counter, expression.left) - counter, right_prestatements, right_expression = normalize_expression(counter, expression.right) - - result_variable = '${}'.format(counter) - if_else_prestatment = NormalVariableInitializationStatement( - variable=result_variable, - expression=left_expression, - ) - counter += 1 - - condition_expression=NormalVariableExpression(variable=result_variable) - short_circuited_statements = right_prestatements + (NormalVariableReassignmentStatement(variable=result_variable, expression=right_expression),) - - if expression.operator == 'and': - if_else_statement = NormalIfElseStatement( - condition_expression=condition_expression, - if_statement_list=short_circuited_statements, - else_statement_list=(), - ) - - elif expression.operator == 'or': - if_else_statement = NormalIfElseStatement( - condition_expression=condition_expression, - if_statement_list=(), - else_statement_list=short_circuited_statements, - ) - - else: - raise Exception('Unable to handle operator "{}"'.format(expression.operator)) - - return ( - counter, - left_prestatements + (if_else_prestatment, if_else_statement), - NormalVariableExpression(variable=result_variable), - ) - -def normalize_dot_expression(counter, expression): - assert isinstance(expression.right, parsing.FurSymbolExpression) - - counter, prestatements, left_expression = normalize_expression(counter, expression.left) - - variable = '${}'.format(counter) - - dot_expression_prestatement = NormalVariableInitializationStatement( - variable=variable, - expression=NormalDotExpression( - instance=left_expression, - field=expression.right.symbol, - ), - ) - - return ( - counter + 1, - prestatements + (dot_expression_prestatement,), - NormalVariableExpression(variable=variable), - ) - -def normalize_infix_expression(counter, expression): - return { - 'multiplication_level': normalize_basic_infix_operation, - 'addition_level': normalize_basic_infix_operation, - 'comparison_level': normalize_comparison_expression, - 'dot_level': normalize_dot_expression, - 'and_level': normalize_boolean_expression, - 'or_level': normalize_boolean_expression, - }[expression.order](counter, expression) - def normalize_if_expression(counter, expression): counter, condition_prestatements, condition_expression = normalize_expression( counter, @@ -579,37 +402,15 @@ def normalize_if_expression(counter, expression): NormalVariableExpression(variable=result_variable), ) -def normalize_negation_expression(counter, expression): - counter, prestatements, internal_expression = normalize_expression(counter, expression.value) - - internal_variable = '${}'.format(counter) - counter += 1 - - return ( - counter, - prestatements + ( - NormalVariableInitializationStatement( - variable=internal_variable, - expression=internal_expression, - ), - ), - NormalNegationExpression(internal_expression=NormalVariableExpression(variable=internal_variable)), - ) - def normalize_expression(counter, expression): return { - NormalInfixExpression: fake_normalization, - NormalVariableExpression: fake_normalization, - parsing.FurFunctionCallExpression: normalize_function_call_expression, - parsing.FurIfExpression: normalize_if_expression, - parsing.FurInfixExpression: normalize_infix_expression, - parsing.FurIntegerLiteralExpression: normalize_integer_literal_expression, - parsing.FurListLiteralExpression: normalize_list_literal_expression, - parsing.FurListItemExpression: normalize_list_item_expression, - parsing.FurNegationExpression: normalize_negation_expression, - parsing.FurStringLiteralExpression: normalize_string_literal_expression, - parsing.FurStructureLiteralExpression: normalize_structure_literal_expression, - parsing.FurSymbolExpression: normalize_symbol_expression, + desugaring.DesugaredFunctionCallExpression: normalize_function_call_expression, + desugaring.DesugaredIfExpression: normalize_if_expression, + desugaring.DesugaredIntegerLiteralExpression: normalize_integer_literal_expression, + desugaring.DesugaredListLiteralExpression: normalize_list_literal_expression, + desugaring.DesugaredStringLiteralExpression: normalize_string_literal_expression, + desugaring.DesugaredStructureLiteralExpression: normalize_structure_literal_expression, + desugaring.DesugaredSymbolExpression: normalize_symbol_expression, }[type(expression)](counter, expression) def normalize_expression_statement(counter, statement): @@ -654,9 +455,9 @@ def normalize_assignment_statement(counter, statement): def normalize_statement(counter, statement): return { - parsing.FurAssignmentStatement: normalize_assignment_statement, - parsing.FurExpressionStatement: normalize_expression_statement, - parsing.FurFunctionDefinitionStatement: normalize_function_definition_statement, + desugaring.DesugaredAssignmentStatement: normalize_assignment_statement, + desugaring.DesugaredExpressionStatement: normalize_expression_statement, + desugaring.DesugaredFunctionDefinitionStatement: normalize_function_definition_statement, }[type(statement)](counter, statement) @util.force_generator(tuple) diff --git a/parsing.py b/parsing.py index 12b93f5..014d74b 100644 --- a/parsing.py +++ b/parsing.py @@ -36,14 +36,6 @@ def _zero_or_more_parser(formatter, parser): return result_parser -NodeMetadata = collections.namedtuple( - 'NodeMetadata', - [ - 'index', - 'line', - ], -) - FurIntegerLiteralExpression = collections.namedtuple( 'FurIntegerLiteralExpression', [ @@ -61,6 +53,7 @@ FurStringLiteralExpression = collections.namedtuple( FurSymbolExpression = collections.namedtuple( 'FurSymbolExpression', [ + 'metadata', 'symbol', ], ) @@ -68,6 +61,7 @@ FurSymbolExpression = collections.namedtuple( FurNegationExpression = collections.namedtuple( 'FurNegationExpression', [ + 'metadata', 'value', ], ) @@ -135,7 +129,14 @@ def _string_literal_expression_parser(index, tokens): def _symbol_expression_parser(index, tokens): if tokens[index].type == 'symbol': - return (True, index + 1, FurSymbolExpression(symbol=tokens[index].match)) + return ( + True, + index + 1, + FurSymbolExpression( + metadata=tokens[index].metadata, + symbol=tokens[index].match, + ), + ) return (False, index, None) @@ -249,12 +250,14 @@ def _negation_expression_parser(index, tokens): if tokens[index].match != '-': return failure + metadata = tokens[index].metadata + success, index, value = _dot_expression_parser(index + 1, tokens) if not success: return failure - return (True, index, FurNegationExpression(value=value)) + return (True, index, FurNegationExpression(metadata=metadata, value=value)) def _negation_level_expression_parser(index, tokens): return _or_parser( @@ -279,10 +282,7 @@ def _left_recursive_infix_operator_parser(operator_token_matcher, operand_parser if success: result = FurInfixExpression( - metadata=NodeMetadata( - index=tokens[index].index, - line=tokens[index].line, - ), + metadata=tokens[index].metadata, order=order, operator=tokens[index].match, left=result, @@ -368,6 +368,7 @@ FurListItemExpression = collections.namedtuple( 'FurListItemExpression', [ 'list_expression', + 'metadata', 'index_expression', ], ) @@ -375,6 +376,7 @@ FurListItemExpression = collections.namedtuple( FurFunctionCallExpression = collections.namedtuple( 'FurFunctionCallExpression', [ + 'metadata', 'function', 'arguments', ], @@ -424,6 +426,8 @@ def _list_item_expression_parser(index, tokens): if not success: return failure + metadata = tokens[index].metadata + success, index, index_expression = _bracket_wrapped_parser(_expression_parser)( index, tokens, @@ -437,9 +441,12 @@ def _list_item_expression_parser(index, tokens): # We can't give this a better name without a bunch of checks, however. list_expression = FurListItemExpression( list_expression=list_expression, + metadata=metadata, index_expression=index_expression, ) + metadata = tokens[index].metadata + success, index, index_expression = _bracket_wrapped_parser(_expression_parser)( index, tokens, @@ -460,6 +467,8 @@ def _function_call_expression_parser(index, tokens): if not success: return failure + metadata = tokens[index].metadata + success, index, arguments = _parenthese_wrapped_parser(_comma_separated_expression_list_parser)( index, tokens, @@ -472,10 +481,13 @@ def _function_call_expression_parser(index, tokens): # "function" is actually the full function call if the next parse attempt doesn't succeed # We can't give this a better name without a bunch of checks, however. function = FurFunctionCallExpression( + metadata=metadata, function=function, arguments=arguments, ) + metadata = tokens[index].metadata + success, index, arguments = _parenthese_wrapped_parser(_comma_separated_expression_list_parser)( index, tokens, @@ -549,7 +561,7 @@ def _assignment_statement_parser(index, tokens): if tokens[index].type == 'symbol': target = tokens[index].match - target_assignment_line = tokens[index].line + target_assignment_line = tokens[index].metadata.line index += 1 else: diff --git a/templates/function_definition.c b/templates/function_definition.c index 1fc85e4..034a2af 100644 --- a/templates/function_definition.c +++ b/templates/function_definition.c @@ -4,6 +4,7 @@ Object user${{name}}$implementation( Environment* environment, size_t argc, Stack* stack, + const unsigned long line, jmp_buf parentJump) { environment = Environment_construct(environmentPool, environment); @@ -13,7 +14,7 @@ Object user${{name}}$implementation( jmp_buf jump; if(setjmp(jump) != 0) { - fprintf(stderr, "\tin {{name}}\n"); + fprintf(stderr, "\tin {{name}} on line %zu\n", line); Stack_rewind(stack, stackSnapshot); Environment_setLive(environment, false); diff --git a/templates/program.c b/templates/program.c index 25f9acb..f8095bf 100644 --- a/templates/program.c +++ b/templates/program.c @@ -67,7 +67,7 @@ typedef struct Closure Closure; struct Closure { Environment* closed; - Object (*call)(EnvironmentPool*, Environment*, size_t, Stack*, jmp_buf); + Object (*call)(EnvironmentPool*, Environment*, size_t, Stack*, const unsigned long, jmp_buf); }; struct List; @@ -573,20 +573,105 @@ Object stringLiteral(const char* literal) return result; } -// TODO Make this conditionally added -Object operator$negate(Object input) +{% if 'pow' in builtins %} +Object builtin$pow$implementation( + EnvironmentPool* environmentPool, + Environment* parent, + size_t argc, + Stack* stack, + const unsigned long line, + jmp_buf parentJump) { - assert(input.type == INTEGER); + // Must unload items in reverse order + Object exponent = Stack_pop(stack); + Object base = Stack_pop(stack); + + assert(base.type == INTEGER); + assert(exponent.type == INTEGER); Object result; result.type = INTEGER; - result.instance.integer = -input.instance.integer; + result.instance.integer = pow(base.instance.integer, exponent.instance.integer); return result; } -// TODO Make this conditionally added -Object operator$concatenate(Stack* stack, jmp_buf parentJump, size_t line) +Object builtin$pow = { CLOSURE, (Instance)(Closure){ NULL, builtin$pow$implementation } }; +{% endif %} + +Object builtin$negate$implementation( + EnvironmentPool* environmentPool, + Environment* parent, + size_t argc, + Stack* stack, + const unsigned long line, + jmp_buf parentJump) +{ + assert(argc == 1); + + Object argument = Stack_pop(stack); + + assert(argument.type == INTEGER); + + Object result = (Object){ + INTEGER, + (Instance)(int32_t) (-argument.instance.integer) + }; + + return result; +} +Object builtin$negate = { CLOSURE, (Instance)(Closure){ NULL, builtin$negate$implementation } }; + +{% for op in ['lt', 'gt', 'lte', 'gte', 'eq', 'neq'] %} +Object builtin${{ op }}$implementation( + EnvironmentPool* environmentPool, + Environment* parent, + size_t argc, + Stack* stack, + const unsigned long line, + jmp_buf parentJump) +{ + assert(argc == 2); + + Object right = Stack_pop(stack); + Object left = Stack_pop(stack); + + assert(left.type == INTEGER); + assert(right.type == INTEGER); + + {% if op == 'lt' %} + if(left.instance.integer < right.instance.integer) + {% elif op == 'gt' %} + if(left.instance.integer > right.instance.integer) + {% elif op == 'lte' %} + if(left.instance.integer <= right.instance.integer) + {% elif op == 'gte' %} + if(left.instance.integer >= right.instance.integer) + {% elif op == 'eq' %} + if(left.instance.integer == right.instance.integer) + {% elif op == 'neq' %} + if(left.instance.integer != right.instance.integer) + {% endif %} + { + return builtin$true; + } + else + { + return builtin$false; + } +} +Object builtin${{ op }} = { CLOSURE, (Instance)(Closure){ NULL, builtin${{ op }}$implementation } }; +{% endfor %} + +Object builtin$concat$implementation( + EnvironmentPool* environmentPool, + Environment* parent, + size_t argc, + Stack* stack, + const unsigned long line, + jmp_buf parentJump) { + assert(argc == 2); + Object right = Stack_pop(stack); Object left = Stack_pop(stack); @@ -616,52 +701,195 @@ Object operator$concatenate(Stack* stack, jmp_buf parentJump, size_t line) Object result = { STRING_CONCATENATION, (Instance)concatenation }; return result; } +Object builtin$concat = { CLOSURE, (Instance)(Closure){ NULL, builtin$concat$implementation } }; -{% for id in infix_declarations %} -Object operator${{ id.name }}(Stack* stack, jmp_buf parentJump, size_t line) +Object builtin$add$implementation( + EnvironmentPool* environmentPool, + Environment* parent, + size_t argc, + Stack* stack, + const unsigned long line, + jmp_buf parentJump) { + assert(argc == 2); + + Object right = Stack_pop(stack); + Object left = Stack_pop(stack); + + assert(left.type == INTEGER); + assert(right.type == INTEGER); + + Object result = (Object){ + INTEGER, + (Instance)(int32_t) (left.instance.integer + right.instance.integer) + }; + + return result; +} +Object builtin$add = { CLOSURE, (Instance)(Closure){ NULL, builtin$add$implementation } }; + +Object builtin$subtract$implementation( + EnvironmentPool* environmentPool, + Environment* parent, + size_t argc, + Stack* stack, + const unsigned long line, + jmp_buf parentJump) +{ + assert(argc == 2); + + Object right = Stack_pop(stack); + Object left = Stack_pop(stack); + + assert(left.type == INTEGER); + assert(right.type == INTEGER); + + Object result = (Object){ + INTEGER, + (Instance)(int32_t) (left.instance.integer - right.instance.integer) + }; + + return result; +} +Object builtin$subtract = { CLOSURE, (Instance)(Closure){ NULL, builtin$subtract$implementation } }; + +Object builtin$multiply$implementation( + EnvironmentPool* environmentPool, + Environment* parent, + size_t argc, + Stack* stack, + const unsigned long line, + jmp_buf parentJump) +{ + assert(argc == 2); + Object right = Stack_pop(stack); Object left = Stack_pop(stack); - assert(left.type == {{ id.in_type.upper() }}); - assert(right.type == {{ id.in_type.upper() }}); + assert(left.type == INTEGER); + assert(right.type == INTEGER); + + Object result = (Object){ + INTEGER, + (Instance)(int32_t) (left.instance.integer * right.instance.integer) + }; + + return result; +} +Object builtin$multiply = { CLOSURE, (Instance)(Closure){ NULL, builtin$multiply$implementation } }; + +Object builtin$integer_divide$implementation( + EnvironmentPool* environmentPool, + Environment* parent, + size_t argc, + Stack* stack, + const unsigned long line, + jmp_buf parentJump) +{ + assert(argc == 2); + + Object right = Stack_pop(stack); + Object left = Stack_pop(stack); + + assert(left.type == INTEGER); + assert(right.type == INTEGER); - {% if id.name == 'integerDivide' or id.name == 'modularDivide' %} if(right.instance.integer == 0) { fprintf(stderr, "DivisionByZeroError on line %zu\n", line); longjmp(parentJump, 1); } - {% endif %} - Object result; - result.type = {{ id.out_type.upper() }}; - result.instance.{{ id.out_type.lower() }} = left.instance.{{ id.in_type.lower() }} {{ id.operator }} right.instance.{{ id.in_type.lower() }}; + Object result = (Object){ + INTEGER, + (Instance)(int32_t) (left.instance.integer / right.instance.integer) + }; + return result; } -{% endfor %} +Object builtin$integer_divide = { CLOSURE, (Instance)(Closure){ NULL, builtin$integer_divide$implementation } }; -{% if 'pow' in builtins %} -Object builtin$pow$implementation(EnvironmentPool* environmentPool, Environment* parent, size_t argc, Stack* stack, jmp_buf parentJump) +Object builtin$modular_divide$implementation( + EnvironmentPool* environmentPool, + Environment* parent, + size_t argc, + Stack* stack, + const unsigned long line, + jmp_buf parentJump) { - // Must unload items in reverse order - Object exponent = Stack_pop(stack); - Object base = Stack_pop(stack); + assert(argc == 2); - assert(base.type == INTEGER); - assert(exponent.type == INTEGER); + Object right = Stack_pop(stack); + Object left = Stack_pop(stack); + + assert(left.type == INTEGER); + assert(right.type == INTEGER); + + if(right.instance.integer == 0) + { + fprintf(stderr, "DivisionByZeroError on line %zu\n", line); + longjmp(parentJump, 1); + } + + Object result = (Object){ + INTEGER, + (Instance)(int32_t) (left.instance.integer % right.instance.integer) + }; - Object result; - result.type = INTEGER; - result.instance.integer = pow(base.instance.integer, exponent.instance.integer); return result; } +Object builtin$modular_divide = { CLOSURE, (Instance)(Closure){ NULL, builtin$modular_divide$implementation } }; -Object builtin$pow = { CLOSURE, (Instance)(Closure){ NULL, builtin$pow$implementation } }; -{% endif %} +Object builtin$field$implementation( + EnvironmentPool* environmentPool, + Environment* parent, + size_t argc, + Stack* stack, + const unsigned long line, + jmp_buf parentJump) +{ + assert(argc == 2); + + Object right = Stack_pop(stack); + Object left = Stack_pop(stack); + + assert(left.type == STRUCTURE); + assert(right.type == STRING_LITERAL); + + Object result = (Object){ + INTEGER, + (Instance)(int32_t) (left.instance.integer % right.instance.integer) + }; + + return result; +} +Object builtin$field = { CLOSURE, (Instance)(Closure){ NULL, builtin$field$implementation } }; + +Object builtin$get$implementation( + EnvironmentPool* environmentPool, + Environment* parent, + size_t argc, + Stack* stack, + const unsigned long line, + jmp_buf parentJump) +{ + assert(argc == 2); + + Object right = Stack_pop(stack); + Object left = Stack_pop(stack); + + return List_get(&left, right); +} +Object builtin$get = { CLOSURE, (Instance)(Closure){ NULL, builtin$get$implementation } }; {% if 'print' in builtins %} -Object builtin$print$implementation(EnvironmentPool* environmentPool, Environment* parent, size_t argc, Stack* stack, jmp_buf parentJump) +Object builtin$print$implementation( + EnvironmentPool* environmentPool, + Environment* parent, + size_t argc, + Stack* stack, + const unsigned long line, + jmp_buf parentJump) { Stack reverse_stack; Stack_initialize(&reverse_stack); @@ -691,9 +919,9 @@ Object builtin$print$implementation(EnvironmentPool* environmentPool, Environmen case STRING_CONCATENATION: Stack_push(stack, output.instance.string_concatenation->left); - builtin$print$implementation(NULL, NULL, 1, stack, parentJump); + builtin$print$implementation(NULL, NULL, 1, stack, line, parentJump); Stack_push(stack, output.instance.string_concatenation->right); - builtin$print$implementation(NULL, NULL, 1, stack, parentJump); + builtin$print$implementation(NULL, NULL, 1, stack, line, parentJump); break; case STRING_LITERAL: @@ -753,6 +981,22 @@ int main(int argc, char** argv) Environment_set(environment, "{{ builtin }}", builtin${{ builtin }}); {% endfor %} + Environment_set(environment, "true", builtin$true); + Environment_set(environment, "false", builtin$false); + Environment_set(environment, "__add__", builtin$add); + Environment_set(environment, "__subtract__", builtin$subtract); + Environment_set(environment, "__multiply__", builtin$multiply); + Environment_set(environment, "__integer_divide__", builtin$integer_divide); + Environment_set(environment, "__modular_divide__", builtin$modular_divide); + Environment_set(environment, "__negate__", builtin$negate); + Environment_set(environment, "__concat__", builtin$concat); + Environment_set(environment, "__field__", builtin$field); + Environment_set(environment, "__get__", builtin$get); + + {% for op in ['lt', 'gt', 'lte', 'gte', 'eq', 'neq'] %} + Environment_set(environment, "__{{ op }}__", builtin${{ op }}); + {% endfor %} + {% for statement in statements %} {{ statement }} {% endfor %} diff --git a/tokenization.py b/tokenization.py index bc8cf85..88576bd 100644 --- a/tokenization.py +++ b/tokenization.py @@ -5,12 +5,19 @@ import util Token = collections.namedtuple( 'Token', - [ + ( 'type', 'match', + 'metadata', + ), +) + +NodeMetadata = collections.namedtuple( + 'NodeMetadata', + ( 'index', 'line', - ], + ), ) def _make_token_matcher(definition): @@ -26,7 +33,14 @@ def _make_token_matcher(definition): return ( True, index + len(match.group()), - Token(type=name, match=match.group(), index=index, line=line), + Token( + type=name, + match=match.group(), + metadata=NodeMetadata( + index=index, + line=line, + ), + ), ) return token_matcher diff --git a/transformation.py b/transformation.py index 7d47ed4..eb6d9cb 100644 --- a/transformation.py +++ b/transformation.py @@ -42,30 +42,6 @@ CStructureLiteralExpression = collections.namedtuple( ], ) -CDotExpression = collections.namedtuple( - 'CDotExpression', - [ - 'instance', - 'symbol', - 'symbol_list_index', - ], -) - -CNegationExpression = collections.namedtuple( - 'CNegationExpression', - [ - 'value', - ], -) - -CFunctionCallForFurInfixOperator = collections.namedtuple( - 'CFunctionCallForFurInfixOperator', - [ - 'metadata', - 'name', - ], -) - CPushStatement = collections.namedtuple( 'CPushStatement', ( @@ -75,10 +51,11 @@ CPushStatement = collections.namedtuple( CFunctionCallExpression = collections.namedtuple( 'CFunctionCallExpression', - [ + ( + 'metadata', 'function_expression', 'argument_count', - ], + ), ) # TODO We are currently not changing variables, just preventing them from being accessed. @@ -209,61 +186,9 @@ def transform_symbol_expression(accumulators, expression): symbol_list_index=symbol_list_index, ) -CInfixDeclaration = collections.namedtuple( - 'CInfixDeclaration', - [ - 'name', - 'in_type', - 'out_type', - 'operator', - ], -) - -FUR_INFIX_OPERATOR_TO_C_FUNCTION = { - '++': 'concatenate', -} - -FUR_INFIX_OPERATOR_TO_C_INFIX_OPERATOR = { - '+': CInfixDeclaration(name='add', in_type='integer', out_type='integer', operator='+'), - '-': CInfixDeclaration(name='subtract', in_type='integer', out_type='integer', operator='-'), - '*': CInfixDeclaration(name='multiply', in_type='integer', out_type='integer', operator='*'), - '//': CInfixDeclaration(name='integerDivide', in_type='integer', out_type='integer', operator='/'), - '%': CInfixDeclaration(name='modularDivide', in_type='integer', out_type='integer', operator='%'), - 'and': CInfixDeclaration(name='and', in_type='boolean', out_type='boolean', operator='&&'), - 'or': CInfixDeclaration(name='or', in_type='boolean', out_type='boolean', operator='||'), - '==': CInfixDeclaration(name='equals', in_type='integer', out_type='boolean', operator='=='), - '!=': CInfixDeclaration(name='notEquals', in_type='integer', out_type='boolean', operator='!='), - '<=': CInfixDeclaration(name='lessThanOrEqual', in_type='integer', out_type='boolean', operator='<='), - '>=': CInfixDeclaration(name='greaterThanOrEqual', in_type='integer', out_type='boolean', operator='>='), - '<': CInfixDeclaration(name='lessThan', in_type='integer', out_type='boolean', operator='<'), - '>': CInfixDeclaration(name='greaterThan', in_type='integer', out_type='boolean', operator='>'), -} - -def transform_infix_operator_without_c_equivalent(accumulators, expression): - return CFunctionCallForFurInfixOperator( - metadata=expression.metadata, - name='concatenate', - ) - -def transform_infix_expression(accumulators, expression): - if expression.operator in FUR_INFIX_OPERATOR_TO_C_FUNCTION: - return transform_infix_operator_without_c_equivalent(accumulators, expression) - - accumulators.operator_set.add(FUR_INFIX_OPERATOR_TO_C_INFIX_OPERATOR[expression.operator]) - - return CFunctionCallForFurInfixOperator( - metadata=expression.metadata, - name=FUR_INFIX_OPERATOR_TO_C_INFIX_OPERATOR[expression.operator].name, - ) - def transform_integer_literal_expression(accumulators, expression): return CIntegerLiteral(value=expression.integer) -def transform_negation_expression(accumulators, expression): - return CNegationExpression( - value=transform_expression(accumulators, expression.internal_expression), - ) - CListConstructExpression = collections.namedtuple( 'CListConstructExpression', [ @@ -294,20 +219,6 @@ def transform_structure_literal_expression(accumulators, expression): value_list_variable=expression.value_list_variable, ) -def transform_dot_expression(accumulators, expression): - try: - symbol_list_index = accumulators.symbol_list.index(expression.field) - - except ValueError: - symbol_list_index = len(accumulators.symbol_list) - accumulators.symbol_list.append(expression.field) - - return CDotExpression( - instance=transform_variable_expression(accumulators, expression.instance), - symbol=expression.field, - symbol_list_index=symbol_list_index, - ) - def transform_list_construct_expression(accumulators, expression): return CListConstructExpression(allocate=expression.allocate) @@ -324,19 +235,11 @@ def transform_list_append_statement(accumulators, expression): ) def transform_expression(accumulators, expression): - # TODO Clean up handlers for parsing expressions return { - parsing.FurInfixExpression: transform_infix_expression, - parsing.FurIntegerLiteralExpression: transform_integer_literal_expression, - parsing.FurNegationExpression: transform_negation_expression, - parsing.FurStringLiteralExpression: transform_string_literal_expression, - normalization.NormalDotExpression: transform_dot_expression, normalization.NormalFunctionCallExpression: transform_function_call_expression, - normalization.NormalInfixExpression: transform_infix_expression, normalization.NormalIntegerLiteralExpression: transform_integer_literal_expression, normalization.NormalListConstructExpression: transform_list_construct_expression, normalization.NormalListGetExpression: transform_list_get_expression, - normalization.NormalNegationExpression: transform_negation_expression, normalization.NormalStructureLiteralExpression: transform_structure_literal_expression, normalization.NormalStringLiteralExpression: transform_string_literal_expression, normalization.NormalSymbolExpression: transform_symbol_expression, @@ -363,6 +266,7 @@ def transform_symbol_assignment_statement(accumulators, assignment_statement): def transform_function_call_expression(accumulators, function_call): # TODO Use the symbol from SYMBOL LIST return CFunctionCallExpression( + metadata=function_call.metadata, function_expression=transform_expression(accumulators, function_call.function_expression), argument_count=function_call.argument_count, ) @@ -434,7 +338,6 @@ def transform_push_statement(accumulators, statement): def transform_statement(accumulators, statement): return { - parsing.FurExpressionStatement: transform_expression_statement, normalization.NormalArrayVariableInitializationStatement: transform_array_variable_initialization_statement, normalization.NormalAssignmentStatement: transform_symbol_assignment_statement, normalization.NormalExpressionStatement: transform_expression_statement, -- 2.20.1