X-Git-Url: https://code.kerkeslager.com/?p=fur;a=blobdiff_plain;f=crossplatform_ir_generation.py;h=f9c7fa9d4c0c16211fca73974804b415ccdd162a;hp=92b2adb5c06edb751afa1b392447a50d9c2e066a;hb=4f86ad3f093ca0c51e77a28b208e7751629d4948;hpb=03d34fcbb6814e64480f0165e56a91e5ba7b7ee0 diff --git a/crossplatform_ir_generation.py b/crossplatform_ir_generation.py index 92b2adb..f9c7fa9 100644 --- a/crossplatform_ir_generation.py +++ b/crossplatform_ir_generation.py @@ -36,70 +36,217 @@ def generate_string_literal(string): def generate_symbol_literal(symbol): return 'sym({})'.format(symbol) -def generate_function_call_expression(expression): - return generate_expression(expression.function_expression) + ( +def generate_instruction_name_from_builtin(builtin): + try: + return { + # Environment operations + '__get__': 'get', + + # Integer operations + '__add__': 'add', + '__integer_divide__': 'idiv', + '__modular_divide__': 'mod', + '__multiply__': 'mul', + '__negate__': 'neg', + '__subtract__': 'sub', + + # Boolean operations + '__eq__': 'eq', + '__neq__': 'neq', + '__lt__': 'lt', + '__lte__': 'lte', + '__gt__': 'gt', + '__gte__': 'gte', + + # String operations + '__concat__': 'concat', + }[builtin] + + except KeyError: + import ipdb; ipdb.set_trace() + +def generate_function_call_expression(counters, expression): + if isinstance(expression.function_expression, conversion.CPSBuiltinExpression): + return ( + (), + ( + CIRInstruction( + instruction=generate_instruction_name_from_builtin( + expression.function_expression.symbol, + ), + argument=expression.argument_count, + ), + ) + ) + + referenced_entry_list, instruction_list = generate_expression( + counters, + expression.function_expression, + ) + + instruction_list += ( CIRInstruction( instruction='call', argument=expression.argument_count, ), ) -def generate_integer_literal_expression(expression): - return (CIRInstruction( - instruction='push_value', + return referenced_entry_list, instruction_list + +def generate_integer_literal_expression(counters, expression): + referenced_entry_list = () + instruction_list = (CIRInstruction( + instruction='push_integer', argument=generate_integer_literal(expression.integer), ),) -def generate_string_literal_expression(expression): - return (CIRInstruction( - instruction='push_value', + return referenced_entry_list, instruction_list + +def escape_name(name): + return name.replace('$','$$').replace('_','$') + +def generate_lambda_expression(counters, expression): + if expression.name is None: + name = '__lambda__' + else: + name = escape_name(expression.name) + + name_counter = counters.get(name, 0) + counters[expression.name] = name_counter + 1 + label = '{}${}'.format(name, name_counter) + + referenced_entry_list_list = [] + instruction_list_list = [] + + for statement in expression.statement_list: + referenced_entry_list, instruction_list = generate_statement(counters, statement) + referenced_entry_list_list.append(referenced_entry_list) + instruction_list_list.append(instruction_list) + + # Pop from the stack in reversed order, because arguments were pushed onto + # the stack in order + argument_bindings = tuple( + CIRInstruction(instruction='pop', argument='sym({})'.format(arg)) + for arg in reversed(expression.argument_name_list) + ) + + lambda_body = flatten(instruction_list_list) + assert lambda_body[-1].instruction == 'drop' + lambda_body = argument_bindings + lambda_body[:-1] + (CIRInstruction(instruction='return', argument=None),) + + referenced_entry_list_list.append( + (CIRLabel(label=label),) + lambda_body, + ) + + instruction_list = ( + CIRInstruction(instruction='close', argument=label), + ) + + return flatten(referenced_entry_list_list), instruction_list + +def generate_list_construct_expression(counters, expression): + referenced_entry_list = () + instruction_list = (CIRInstruction( + instruction='list', + argument=2, + ),) + return referenced_entry_list, instruction_list + +def generate_string_literal_expression(counters, expression): + referenced_entry_list = () + instruction_list = (CIRInstruction( + instruction='push_string', argument=generate_string_literal(expression.string), ),) -def generate_symbol_expression(expression): - return (CIRInstruction( + return referenced_entry_list, instruction_list + +def generate_structure_literal_expression(counters, expression): + referenced_entry_list = () + instruction_list = (CIRInstruction( + instruction='structure', + argument=expression.field_count, + ),) + + return referenced_entry_list, instruction_list + +def generate_symbol_expression(counters, expression): + referenced_entry_list = () + instruction_list = (CIRInstruction( instruction='push', argument=generate_symbol_literal(expression.symbol), ),) -def generate_variable_expression(expression): - return (CIRInstruction( + return referenced_entry_list, instruction_list + +def generate_symbol_literal_expression(counters, expression): + referenced_entry_list = () + instruction_list = (CIRInstruction( + instruction='push_symbol', + argument=generate_symbol_literal(expression.symbol), + ),) + + return referenced_entry_list, instruction_list + +def generate_variable_expression(counters, expression): + referenced_entry_list = () + instruction_list = (CIRInstruction( instruction='push', argument=generate_symbol_literal(expression.variable), ),) -def generate_expression(expression): + return referenced_entry_list, instruction_list + +def generate_expression(counters, expression): return { conversion.CPSFunctionCallExpression: generate_function_call_expression, + conversion.CPSIfElseExpression: generate_if_else_expression, conversion.CPSIntegerLiteralExpression: generate_integer_literal_expression, + conversion.CPSLambdaExpression: generate_lambda_expression, + conversion.CPSListConstructExpression: generate_list_construct_expression, conversion.CPSStringLiteralExpression: generate_string_literal_expression, + conversion.CPSStructureLiteralExpression: generate_structure_literal_expression, conversion.CPSSymbolExpression: generate_symbol_expression, + conversion.CPSSymbolLiteralExpression: generate_symbol_literal_expression, conversion.CPSVariableExpression: generate_variable_expression, - }[type(expression)](expression) + }[type(expression)](counters, expression) def generate_expression_statement(counters, statement): - return ( - (), - generate_expression(statement.expression) + ( - CIRInstruction( - instruction='drop', - argument=None, - ), + referenced_entry_list, instruction_list = generate_expression( + counters, + statement.expression, + ) + + instruction_list += ( + CIRInstruction( + instruction='drop', + argument=None, ), ) -def generate_if_else_statement(counters, statement): + return referenced_entry_list, instruction_list + +def generate_if_else_expression(counters, statement): if_counter = counters['if'] counters['if'] += 1 referenced_entry_list_list = [] + condition_referenced_entry_list, condition_instruction_list = generate_expression( + counters, + statement.condition_expression, + ) + if_instruction_list_list = [] for if_statement in statement.if_statement_list: referenced_entry_list, instruction_list = generate_statement(counters, if_statement) referenced_entry_list_list.append(referenced_entry_list) if_instruction_list_list.append(instruction_list) + if_instruction_list = flatten(if_instruction_list_list) + assert if_instruction_list[-1].instruction == 'drop' + if_instruction_list = if_instruction_list[:-1] + else_instruction_list_list = [] for else_statement in statement.else_statement_list: @@ -107,76 +254,78 @@ def generate_if_else_statement(counters, statement): referenced_entry_list_list.append(referenced_entry_list) else_instruction_list_list.append(instruction_list) + else_instruction_list = flatten(else_instruction_list_list) + assert else_instruction_list[-1].instruction == 'drop' + else_instruction_list = else_instruction_list[:-1] + if_label = '__if${}__'.format(if_counter) else_label = '__else${}__'.format(if_counter) endif_label = '__endif${}__'.format(if_counter) - return ( - referenced_entry_list_list, - generate_expression(statement.condition_expression) + ( - CIRInstruction( - instruction='jump_if_false', - argument=else_label, - ), - CIRLabel(label=if_label), - ) + flatten(if_instruction_list_list) + ( - CIRInstruction( - instruction='jump', - argument=endif_label, - ), - CIRLabel(label=else_label), - ) + flatten(else_instruction_list_list) + ( - CIRLabel(label=endif_label), + instruction_list = condition_instruction_list + ( + CIRInstruction( + instruction='jump_if_false', + argument=else_label, + ), + CIRInstruction( + instruction='jump', + argument=if_label, ), + CIRLabel(label=if_label), + ) + if_instruction_list + ( + CIRInstruction( + instruction='jump', + argument=endif_label, + ), + CIRLabel(label=else_label), + ) + else_instruction_list + ( + CIRLabel(label=endif_label), ) -def generate_assignment_statement(counters, statement): return ( - (), - generate_expression(statement.expression) + ( - CIRInstruction( - instruction='pop', - argument=generate_symbol_literal(statement.target), - ), + condition_referenced_entry_list + flatten(referenced_entry_list_list), + instruction_list, + ) + +def generate_assignment_statement(counters, statement): + referenced_entry_list, instruction_list = generate_expression( + counters, + statement.expression, + ) + + instruction_list += ( + CIRInstruction( + instruction='pop', + argument=generate_symbol_literal(statement.target), ), ) + return referenced_entry_list, instruction_list + def generate_push_statement(counters, statement): - return ( - (), - generate_expression(statement.expression), - ) + return generate_expression(counters, statement.expression) def generate_variable_initialization_statement(counters, statement): - return ( - (), - generate_expression(statement.expression) + ( - CIRInstruction( - instruction='pop', - argument=generate_symbol_literal(statement.variable), - ), - ), + referenced_entry_list, instruction_list = generate_expression( + counters, + statement.expression, ) -def generate_variable_reassignment_statement(counter, statement): - return ( - (), - generate_expression(statement.expression) + ( - CIRInstruction( - instruction='pop', - argument=generate_symbol_literal(statement.variable), - ), + instruction_list += ( + CIRInstruction( + instruction='pop', + argument=generate_symbol_literal(statement.variable), ), ) + return referenced_entry_list, instruction_list + def generate_statement(counters, statement): return { conversion.CPSAssignmentStatement: generate_assignment_statement, conversion.CPSExpressionStatement: generate_expression_statement, - conversion.CPSIfElseStatement: generate_if_else_statement, conversion.CPSPushStatement: generate_push_statement, conversion.CPSVariableInitializationStatement: generate_variable_initialization_statement, - conversion.CPSVariableReassignmentStatement: generate_variable_reassignment_statement, }[type(statement)](counters, statement) def generate(converted): @@ -192,25 +341,32 @@ def generate(converted): instruction_list_list.append(instruction_list) return CIRProgram( - entry_list=( + entry_list=flatten(referenced_entry_list_list) + ( CIRLabel(label='__main__'), - ) + tuple( - referenced_entry - for referenced_entry_list in referenced_entry_list_list - for referenced_entry in referenced_entry_list - ) + tuple( - instruction - for instruction_list in instruction_list_list - for instruction in instruction_list - ), + ) + flatten(instruction_list_list) + ( + CIRInstruction(instruction='end', argument=None), + ) ) +NO_ARGUMENT_INSTRUCTIONS = set([ + 'drop', + 'return', +]) + +def format_argument(arg): + if arg is None: + return 'nil' + return arg + def output(program): lines = [] for entry in program.entry_list: if isinstance(entry, CIRInstruction): - lines.append(' {} {}'.format(entry.instruction, entry.argument)) + if entry.instruction in NO_ARGUMENT_INSTRUCTIONS and entry.argument is None: + lines.append(' {}'.format(entry.instruction)) + else: + lines.append(' {} {}'.format(entry.instruction, format_argument(entry.argument))) if isinstance(entry, CIRLabel): lines.append('\n{}:'.format(entry.label))