From ab984279c92601b321db123984c753aa862daad8 Mon Sep 17 00:00:00 2001 From: David Kerkeslager Date: Tue, 8 Aug 2017 18:57:17 -0400 Subject: [PATCH] Added variable-length args to function calls --- examples/15_varargs.fur | 2 ++ examples/15_varargs.fur.output.txt | 2 ++ generation.py | 17 ++++++++++--- normalization.py | 24 +++++++++++++++--- templates/program.c | 39 ++++++++++++++++++------------ transformation.py | 25 ++++++++++++++----- 6 files changed, 81 insertions(+), 28 deletions(-) create mode 100644 examples/15_varargs.fur create mode 100644 examples/15_varargs.fur.output.txt diff --git a/examples/15_varargs.fur b/examples/15_varargs.fur new file mode 100644 index 0000000..964ecfb --- /dev/null +++ b/examples/15_varargs.fur @@ -0,0 +1,2 @@ +print('Hello, world\n') +print(42, '\n') diff --git a/examples/15_varargs.fur.output.txt b/examples/15_varargs.fur.output.txt new file mode 100644 index 0000000..ac2ea2c --- /dev/null +++ b/examples/15_varargs.fur.output.txt @@ -0,0 +1,2 @@ +Hello, world +42 diff --git a/generation.py b/generation.py index 149a5e2..1e1243a 100644 --- a/generation.py +++ b/generation.py @@ -64,10 +64,12 @@ def generate_negation_expression(c_negation_expression): generate_expression(c_negation_expression.value) ) -def generate_function_call(c_function_call): - return '{}({})'.format( - c_function_call.name, - ', '.join(generate_expression(argument) for argument in c_function_call.arguments), +def generate_function_call(function_call): + return '{}({}, {})'.format( + function_call.name, + function_call.argument_count, + # TODO This is just a single item containing a reference to the items list--make that clearer + generate_expression(function_call.argument_items), ) def generate_expression_statement(statement): @@ -81,6 +83,12 @@ def generate_symbol_assignment_statement(c_assignment_statement): generate_expression(c_assignment_statement.expression), ) +def generate_array_variable_initialization_statement(statement): + return 'Object {}[] = {{ {} }};'.format( + statement.variable, + ', '.join(generate_expression(i) for i in statement.items), + ) + def generate_variable_initialization_statement(statement): return 'Object {} = {};'.format( statement.variable, @@ -110,6 +118,7 @@ def generate_statement(statement): transformation.CExpressionStatement: generate_expression_statement, transformation.CIfElseStatement: generate_if_else_statement, transformation.CSymbolAssignmentStatement: generate_symbol_assignment_statement, + transformation.CArrayVariableInitializationStatement: generate_array_variable_initialization_statement, transformation.CVariableInitializationStatement: generate_variable_initialization_statement, transformation.CVariableReassignmentStatement: generate_variable_reassignment_statement, }[type(statement)](statement) diff --git a/normalization.py b/normalization.py index 1da6569..a41eb8d 100644 --- a/normalization.py +++ b/normalization.py @@ -30,7 +30,16 @@ NormalFunctionCallExpression = collections.namedtuple( 'NormalFunctionCallExpression', [ 'function', - 'arguments', + 'argument_count', + 'argument_items', + ], +) + +NormalArrayVariableInitializationStatement = collections.namedtuple( + 'NormalArrayVariableInitializationStatement', + [ + 'variable', + 'items', ], ) @@ -98,12 +107,21 @@ def normalize_function_call_expression(counter, expression): )) counter += 1 + arguments_variable = '${}'.format(counter) + counter += 1 + + prestatements.append(NormalArrayVariableInitializationStatement( + variable=arguments_variable, + items=tuple(arguments), + )) + return ( counter, tuple(prestatements), NormalFunctionCallExpression( - expression.function, # TODO Normalize the function - arguments=tuple(arguments), + function=expression.function, # TODO Normalize the function + argument_count=len(arguments), + argument_items=NormalVariableExpression(variable=arguments_variable), ), ) diff --git a/templates/program.c b/templates/program.c index 8116e25..0c6f8f9 100644 --- a/templates/program.c +++ b/templates/program.c @@ -272,8 +272,13 @@ Object builtin$or(Object left, Object right) } {% if 'pow' in builtins %} -Object builtin$pow(Object base, Object exponent) +Object builtin$pow(size_t argc, Object args[]) { + assert(argc == 2); + + Object base = args[0]; + Object exponent = args[1]; + assert(base.type == INTEGER); assert(exponent.type == INTEGER); @@ -285,25 +290,29 @@ Object builtin$pow(Object base, Object exponent) {% endif %} {% if 'print' in builtins %} -void builtin$print(Object output) +void builtin$print(size_t argc, Object args[]) { - switch(output.type) + for(size_t i = 0; i < argc; i++) { - case BOOLEAN: - fputs(output.instance.boolean ? "true" : "false", stdout); - break; + Object output = args[i]; + switch(output.type) + { + case BOOLEAN: + fputs(output.instance.boolean ? "true" : "false", stdout); + break; - case INTEGER: - printf("%" PRId32, output.instance.integer); - break; + case INTEGER: + printf("%" PRId32, output.instance.integer); + break; - case STRING: - // Using fwrite instead of printf to handle size_t length - printf("%s", output.instance.string); - break; + case STRING: + // Using fwrite instead of printf to handle size_t length + printf("%s", output.instance.string); + break; - default: - assert(false); + default: + assert(false); + } } } {% endif %} diff --git a/transformation.py b/transformation.py index 4c1ef3b..ecfab9a 100644 --- a/transformation.py +++ b/transformation.py @@ -60,7 +60,8 @@ CFunctionCallExpression = collections.namedtuple( 'CFunctionCallExpression', [ 'name', - 'arguments', + 'argument_count', + 'argument_items', ], ) @@ -73,6 +74,14 @@ CSymbolAssignmentStatement = collections.namedtuple( ], ) +CArrayVariableInitializationStatement = collections.namedtuple( + 'CArrayVariableInitializationStatement', + [ + 'variable', + 'items', + ], +) + CVariableInitializationStatement = collections.namedtuple( 'CVariableInitializationStatement', [ @@ -257,17 +266,14 @@ def transform_negation_expression(accumulators, expression): ) def transform_function_call_expression(accumulators, function_call): - # TODO Function should be a full expression if function_call.function.value in BUILTINS.keys(): # TODO Check that the builtin is actually callable accumulators.builtin_set.add(function_call.function.value) return CFunctionCallExpression( name='builtin$' + function_call.function.value, - arguments=tuple( - transform_expression(accumulators, arg) - for arg in function_call.arguments - ), + argument_count=function_call.argument_count, + argument_items=transform_expression(accumulators, function_call.argument_items), ) raise Exception() @@ -289,6 +295,12 @@ def transform_if_else_statement(accumulators, statement): else_statements=tuple(transform_statement(accumulators, s) for s in statement.else_statements), ) +def transform_array_variable_initialization_statement(accumulators, statement): + return CArrayVariableInitializationStatement( + variable=statement.variable, + items=tuple(transform_expression(accumulators, i) for i in statement.items), + ) + def transform_variable_initialization_statement(accumulators, statement): return CVariableInitializationStatement( variable=statement.variable, @@ -307,6 +319,7 @@ def transform_statement(accumulators, statement): parsing.FurExpressionStatement: transform_expression_statement, normalization.NormalExpressionStatement: transform_expression_statement, normalization.NormalIfElseStatement: transform_if_else_statement, + normalization.NormalArrayVariableInitializationStatement: transform_array_variable_initialization_statement, normalization.NormalVariableInitializationStatement: transform_variable_initialization_statement, normalization.NormalVariableReassignmentStatement: transform_variable_reassignment_statement, }[type(statement)](accumulators, statement) -- 2.20.1