X-Git-Url: https://code.kerkeslager.com/?a=blobdiff_plain;f=normalization.py;h=f2b7b138a6a8dbe9db3ce5cad5e8c5b280b454cb;hb=61733d6070859e6a639ae4b34faec9aacca52a29;hp=c96e455ec3e8b939435e76552f83c739f2bad2f6;hpb=a96e96f3f783930707122f691cd6a08a90416a74;p=fur diff --git a/normalization.py b/normalization.py index c96e455..f2b7b13 100644 --- a/normalization.py +++ b/normalization.py @@ -38,22 +38,35 @@ NormalNegationExpression = collections.namedtuple( ], ) +NormalDotExpression = collections.namedtuple( + 'NormalDotExpression', + [ + 'instance', + 'field', + ], +) + NormalInfixExpression = collections.namedtuple( 'NormalInfixExpression', [ + 'metadata', 'order', 'operator', - 'left', - 'right', ], ) +NormalPushStatement = collections.namedtuple( + 'NormalPushStatement', + ( + 'expression', + ), +) + NormalFunctionCallExpression = collections.namedtuple( 'NormalFunctionCallExpression', [ 'function_expression', 'argument_count', - 'argument_items', ], ) @@ -65,6 +78,14 @@ NormalArrayVariableInitializationStatement = collections.namedtuple( ], ) +NormalSymbolArrayVariableInitializationStatement = collections.namedtuple( + 'NormalSymbolArrayVariableInitializationStatement', + [ + 'variable', + 'symbol_list', + ], +) + NormalVariableInitializationStatement = collections.namedtuple( 'NormalVariableInitializationStatement', [ @@ -137,6 +158,83 @@ def normalize_integer_literal_expression(counter, expression): NormalVariableExpression(variable=variable), ) +NormalListConstructExpression = collections.namedtuple( + 'NormalListConstructExpression', + [ + 'allocate', + ], +) + +NormalListAppendStatement = collections.namedtuple( + 'NormalListAppendStatement', + [ + 'list_expression', + 'item_expression', + ], +) + +NormalListGetExpression = collections.namedtuple( + 'NormalListGetExpression', + [ + 'list_expression', + 'index_expression', + ], +) + +def normalize_list_literal_expression(counter, expression): + list_variable = '${}'.format(counter) + counter += 1 + + prestatements = [ + NormalVariableInitializationStatement( + variable=list_variable, + expression=NormalListConstructExpression(allocate=len(expression.item_expression_list)), + ), + ] + + list_expression = NormalVariableExpression(variable=list_variable) + + for item_expression in expression.item_expression_list: + counter, item_expression_prestatements, normalized = normalize_expression( + counter, + item_expression, + ) + + for p in item_expression_prestatements: + prestatements.append(p) + + prestatements.append( + NormalListAppendStatement( + list_expression=list_expression, + item_expression=normalized, + ) + ) + + return ( + counter, + tuple(prestatements), + list_expression, + ) + +def normalize_list_item_expression(counter, expression): + counter, list_prestatements, list_expression = normalize_expression(counter, expression.list_expression) + counter, index_prestatements, index_expression = normalize_expression(counter, expression.index_expression) + + result_variable = '${}'.format(counter) + result_prestatement = NormalVariableInitializationStatement( + variable=result_variable, + expression=NormalListGetExpression( + list_expression=list_expression, + index_expression=index_expression, + ), + ) + + return ( + counter + 1, + list_prestatements + index_prestatements + (result_prestatement,), + NormalVariableExpression(variable=result_variable), + ) + def normalize_string_literal_expression(counter, expression): variable = '${}'.format(counter) return ( @@ -150,6 +248,72 @@ def normalize_string_literal_expression(counter, expression): NormalVariableExpression(variable=variable), ) +NormalStructureLiteralExpression = collections.namedtuple( + 'NormalStructureLiteralExpression', + [ + 'field_count', + 'symbol_list_variable', + 'value_list_variable', + ], +) + +def normalize_structure_literal_expression(counter, expression): + prestatements = [] + field_symbol_array = [] + field_value_array = [] + + for symbol_expression_pair in expression.fields: + counter, field_prestatements, field_expression = normalize_expression( + counter, + symbol_expression_pair.expression, + ) + + for p in field_prestatements: + prestatements.append(p) + + field_symbol_array.append(symbol_expression_pair.symbol) + field_value_array.append(field_expression) + + symbol_array_variable = '${}'.format(counter) + counter += 1 + + prestatements.append( + NormalSymbolArrayVariableInitializationStatement( + variable=symbol_array_variable, + symbol_list=tuple(field_symbol_array), + ) + ) + + value_array_variable = '${}'.format(counter) + counter += 1 + + prestatements.append( + NormalArrayVariableInitializationStatement( + variable=value_array_variable, + items=tuple(field_value_array), + ) + ) + + variable = '${}'.format(counter) + + prestatements.append( + NormalVariableInitializationStatement( + variable=variable, + expression=NormalStructureLiteralExpression( + field_count=len(expression.fields), + symbol_list_variable=symbol_array_variable, + value_list_variable=value_array_variable, + ), + ) + ) + + return ( + counter + 1, + tuple(prestatements), + NormalVariableExpression(variable=variable), + ) + + def normalize_symbol_expression(counter, expression): variable = '${}'.format(counter) return ( @@ -167,7 +331,6 @@ def normalize_function_call_expression(counter, expression): assert isinstance(expression, parsing.FurFunctionCallExpression) prestatements = [] - arguments = [] for argument in expression.arguments: counter, argument_prestatements, normalized_argument = normalize_expression(counter, argument) @@ -182,19 +345,15 @@ def normalize_function_call_expression(counter, expression): expression=normalized_argument, ) ) - arguments.append(NormalVariableExpression( - variable=variable, - )) + prestatements.append( + NormalPushStatement( + expression=NormalVariableExpression( + variable=variable, + ), + ), + ) counter += 1 - arguments_variable = '${}'.format(counter) - counter += 1 - - prestatements.append(NormalArrayVariableInitializationStatement( - variable=arguments_variable, - items=tuple(arguments), - )) - counter, function_prestatements, function_expression = normalize_expression( counter, expression.function, @@ -216,43 +375,40 @@ def normalize_function_call_expression(counter, expression): function_expression = NormalVariableExpression(variable=function_variable) counter += 1 + result_variable = '${}'.format(counter) + + prestatements.append( + NormalVariableInitializationStatement( + variable=result_variable, + expression=NormalFunctionCallExpression( + function_expression=function_expression, + argument_count=len(expression.arguments), + ), + ) + ) + return ( - counter, + counter + 1, tuple(prestatements), - NormalFunctionCallExpression( - function_expression=function_expression, - argument_count=len(arguments), - argument_items=NormalVariableExpression(variable=arguments_variable), - ), + 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) - left_variable = '${}'.format(counter) - counter += 1 - right_variable = '${}'.format(counter) - counter += 1 center_variable = '${}'.format(counter) counter += 1 root_prestatements = ( - NormalVariableInitializationStatement( - variable=left_variable, - expression=left_expression, - ), - NormalVariableInitializationStatement( - variable=right_variable, - expression=right_expression, - ), + NormalPushStatement(expression=left_expression), + NormalPushStatement(expression=right_expression), NormalVariableInitializationStatement( variable=center_variable, expression=NormalInfixExpression( + metadata=expression.metadata, order=expression.order, operator=expression.operator, - left=NormalVariableExpression(variable=left_variable), - right=NormalVariableExpression(variable=right_variable), ), ), ) @@ -263,67 +419,61 @@ def normalize_basic_infix_operation(counter, expression): NormalVariableExpression(variable=center_variable), ) -def normalize_comparison_expression(counter, expression): - stack = [] - - while isinstance(expression.left, parsing.FurInfixExpression) and expression.order == 'comparison_level': - stack.append((expression.operator, expression.order, expression.right)) - expression = expression.left - - counter, left_prestatements, left_expression = normalize_expression(counter, expression.left) - counter, right_prestatements, right_expression = normalize_expression(counter, expression.right) +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 - right_variable = '${}'.format(counter) + middle_variable = '${}'.format(counter) counter += 1 - root_prestatements = ( + # 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=right_variable, - expression=right_expression, - ), + variable=middle_variable, + expression=middle_expression, + ) ) - counter, result_prestatements, result_expression = ( + counter, boolean_expression_prestatements, boolean_expression = normalize_boolean_expression( counter, - left_prestatements + right_prestatements + root_prestatements, - NormalInfixExpression( - order=expression.order, - operator=expression.operator, - left=NormalVariableExpression(variable=left_variable), - right=NormalVariableExpression(variable=right_variable), - ), - ) - - while len(stack) > 0: - right_operator, right_order, right_expression = stack.pop() - and_right_expression = parsing.FurInfixExpression( - operator=right_operator, - order=right_order, - left=NormalVariableExpression(variable=right_variable), - right=right_expression, - ) - - and_expression = parsing.FurInfixExpression( - operator='and', + parsing.FurInfixExpression( + metadata=expression.left.metadata, order='and_level', - left=result_expression, - right=and_right_expression, + 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, + ), ) + ) - counter, and_prestatements, result_expression = normalize_boolean_expression( - counter, - and_expression, - ) + return ( + counter, + left_prestatements + middle_prestatements + juncture_prestatements + boolean_expression_prestatements, + boolean_expression, + ) - result_prestatements = result_prestatements + and_prestatements +def normalize_comparison_expression(counter, expression): + if isinstance(expression.left, parsing.FurInfixExpression) and expression.order == 'comparison_level': + return desugar_ternary_comparison(counter, expression) - return (counter, result_prestatements, result_expression) + return normalize_basic_infix_operation(counter, expression) def normalize_boolean_expression(counter, expression): counter, left_prestatements, left_expression = normalize_expression(counter, expression.left) @@ -362,12 +512,33 @@ def normalize_boolean_expression(counter, expression): 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) @@ -408,9 +579,6 @@ 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) @@ -436,8 +604,11 @@ def normalize_expression(counter, 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, }[type(expression)](counter, expression) @@ -502,12 +673,12 @@ def normalize_statement_list(counter, statement_list, **kwargs): result_statement_list.append(s) result_statement_list.append(normalized) + # TODO The way we fix the last statement is really confusing last_statement = result_statement_list[-1] if isinstance(last_statement, NormalExpressionStatement) and isinstance(last_statement.expression, NormalVariableExpression): - result_expression = result_statement_list.pop().expression - if assign_result_to is not None: + result_expression = result_statement_list.pop().expression result_statement_list.append( NormalVariableReassignmentStatement( variable=assign_result_to,