From 1b0dce9ed1165ce6a177a7b582f5597d797417e6 Mon Sep 17 00:00:00 2001 From: Nathan Braswell Date: Thu, 2 Feb 2017 00:46:36 -0500 Subject: [PATCH] Work on function value lower --- current_stats.sh | 2 +- kraken.krak | 6 +++ stdlib/function_value_lower.krak | 80 ++++++++++++++++++++++++++++++++ stdlib/set.krak | 9 ++++ stress_generator.py | 21 +++++++++ 5 files changed, 117 insertions(+), 1 deletion(-) create mode 100644 stdlib/function_value_lower.krak create mode 100644 stress_generator.py diff --git a/current_stats.sh b/current_stats.sh index 5913990..c05e1cd 100755 --- a/current_stats.sh +++ b/current_stats.sh @@ -1,2 +1,2 @@ #!/bin/sh -cloc --read-lang-def=kraken_cloc_definition.txt . +cloc --read-lang-def=kraken_cloc_definition.txt kraken.krak stdlib/ diff --git a/kraken.krak b/kraken.krak index 0d868c6..7159205 100644 --- a/kraken.krak +++ b/kraken.krak @@ -13,6 +13,7 @@ import ast_transformation:* import adt_lower:* import obj_lower:* import defer_lower:* +import function_value_lower:* import ref_lower:* import ctce_lower:* import c_line_control:* @@ -153,6 +154,11 @@ fun main(argc: int, argv: **char):int { defer_lower(&importer.name_ast_map, &importer.ast_pass.ast_to_syntax) /*printlnerr("Counting Nodes")*/ /*node_counter(&importer.name_ast_map, &importer.ast_pass.ast_to_syntax)*/ + // Should come after lowering of ADTs and before lowering of Refs + printlnerr("Lowering Function Values (Lambdas, etc)") + function_value_lower(&importer.name_ast_map, &importer.ast_pass.ast_to_syntax) + /*printlnerr("Counting Nodes")*/ + /*node_counter(&importer.name_ast_map, &importer.ast_pass.ast_to_syntax)*/ printlnerr("Lowering Ref") ref_lower(&importer.name_ast_map, &importer.ast_pass.ast_to_syntax) /*printlnerr("Counting Nodes")*/ diff --git a/stdlib/function_value_lower.krak b/stdlib/function_value_lower.krak new file mode 100644 index 0000000..0610dd2 --- /dev/null +++ b/stdlib/function_value_lower.krak @@ -0,0 +1,80 @@ +import symbol:* +import tree:* +import vector:* +import map:* +import util:* +import string:* +import mem:* +import io:* +import ast_nodes:* +import ast_transformation:* +import hash_set:* + +import pass_common:* + +obj function_parent_block { + var function: *ast_node + var parent: *ast_node + var block: *ast_node +} +fun make_function_parent_block(function: *ast_node, parent: *ast_node, block: *ast_node): function_parent_block { + var result: function_parent_block + result.function = function + result.parent = parent + result.block = block + return result +} + +fun function_value_lower(name_ast_map: *map,*ast_node>>, ast_to_syntax: *map<*ast_node, *tree>) { + var visited = hash_set<*ast_node>() + var lambdas = set<*ast_node>() + var function_types_needed_wo_lambdas = set() + var function_value_creation_points = vector() + name_ast_map->for_each(fun(name: string, syntax_ast_pair: pair<*tree,*ast_node>) { + lambdas.add(syntax_ast_pair.second->translation_unit.lambdas) + }) + name_ast_map->for_each(fun(name: string, syntax_ast_pair: pair<*tree,*ast_node>) { + var helper_before = fun(node: *ast_node, parent_chain: *stack<*ast_node>) { + match(*node) { + ast_node::function(backing) { + var parent = parent_chain->top() + // need to use function value if + // it isn't a regular function definition (or lambda top reference) and + var need_done = (!is_translation_unit(parent) && !is_type_def(parent) && !is_template(parent) && backing.body_statement) && ( + // it is a lambda or it's not a lambda and it's not being called immediantly or + lambdas.contains(node) || (!is_function_call(parent) || + // it's parent is a function call, but it's not calling us, so we're used as a parameter and + // us as a parameter isn't the right side of a . or -> because our parent + // isn't a function or has a body + (parent->function_call.func != node && (!is_function(parent->function_call.func) || parent->function_call.func->function.body_statement + // or it is a . or -> but it's parent isn't a function call + // or it is, but our grandparent's funciton call isn't our access operation + // and thus we're being passed as a parameter. Not sure if this actually works right now + // as I'm not sure you can pass member functions anyway + || parent_chain->size() < 2 || !is_function_call(parent_chain->from_top(1)) || parent_chain->from_top(1)->function_call.func != parent)))) + if (need_done) { + function_value_creation_points.add(make_function_parent_block(node, parent_chain->top(), + parent_chain->item_from_top_satisfying(fun(i: *ast_node): bool return is_code_block(i);))) + } + + if (backing.type->return_type->is_function()) + function_types_needed_wo_lambdas.add(*backing.type->return_type) + for (var i = 0; i < backing.type->parameter_types.size; i++;) + if (backing.type->parameter_types[i]->is_function()) + function_types_needed_wo_lambdas.add(*backing.type->parameter_types[i]) + } + ast_node::identifier(backing) { + if (backing.type->is_function()) + function_types_needed_wo_lambdas.add(*backing.type) + } + } + } + run_on_tree(helper_before, empty_pass_second_half, syntax_ast_pair.second, &visited) + }) + var function_types_needed_for_lambdas = lambdas.map(fun(l: *ast_node): type { return *l->function.type; }) + println(string("there are ") + function_value_creation_points.size + " function value creation points in the program.") + println(string("there are ") + function_types_needed_wo_lambdas.size() + " function types needed wo lambdas in the program.") + println(string("there are ") + function_types_needed_for_lambdas.size() + " function types needed for lambdas in the program.") + println(string("there are ") + (function_types_needed_wo_lambdas + function_types_needed_for_lambdas).size() + " total (set union, not addition) in the program.") +} + diff --git a/stdlib/set.krak b/stdlib/set.krak index 96848e3..5cf35f4 100644 --- a/stdlib/set.krak +++ b/stdlib/set.krak @@ -82,6 +82,9 @@ obj set (Object, Serializable) { fun add(items: ref set) { items.for_each( fun(item: ref T) add(item); ) } + fun add(items: ref vector::vector) { + items.for_each( fun(item: ref T) add(item); ) + } fun remove(item: ref T) { var idx = data.find(item) if (idx == -1) { @@ -102,6 +105,12 @@ obj set (Object, Serializable) { fun reduce(func: fun(T,U): U, initial: U): U { return data.reduce(func, initial) } + fun map(func: fun(T):U):set { + var newSet.construct(size()): set + for (var i = 0; i < size(); i++;) + newSet.add(func(data[i])) + return newSet + } fun flatten_map(func: fun(T):set):set { var newSet.construct(size()): set for (var i = 0; i < size(); i++;) diff --git a/stress_generator.py b/stress_generator.py new file mode 100644 index 0000000..776c81f --- /dev/null +++ b/stress_generator.py @@ -0,0 +1,21 @@ + +func_base = "main" +var_base = "var" + +numlines = 20 +numfuncs = 5 + +def genFunc(): + stress_test = open("stress_test.krak",'w') + for i in range(numfuncs): + stress_test.write('fun '+func_base+(str(i) if i != 0 else "")+'() : int {\n') + for j in range(numlines): + stress_test.write("var " + var_base+str(j)+' : int = (5*4+3-2)+1; \n') + stress_test.write("return 0;\n") + stress_test.write('}') + stress_test.write("\n\n") + + stress_test.close() + + +genFunc()