From 337bc424eeecf5df16b712ee5620ffffff668ca0 Mon Sep 17 00:00:00 2001 From: Nathan Braswell Date: Wed, 6 Jan 2016 02:46:42 -0500 Subject: [PATCH] Added in basic transformation and generation for functions --- src/ASTTransformation.cpp | 14 ++++++--- src/CGenerator.cpp | 4 ++- stdlib/ast_nodes.krak | 41 +++++++++++++++++--------- stdlib/ast_transformation.krak | 53 ++++++++++++++++++++++++++++++++-- stdlib/c_generator.krak | 46 ++++++++++++++++++++++++++--- stdlib/type.krak | 51 +++++++++++++++++++++++++++----- tests/to_parse.krak | 5 +++- 7 files changed, 180 insertions(+), 34 deletions(-) diff --git a/src/ASTTransformation.cpp b/src/ASTTransformation.cpp index a1c0a30..885ba0c 100644 --- a/src/ASTTransformation.cpp +++ b/src/ASTTransformation.cpp @@ -287,9 +287,8 @@ NodeTree* ASTTransformation::secondPassFunction(NodeTree* from, //If this is a function template std::vector*> children = from->getChildren(); NodeTree* functionDef = NULL; - std::string functionName; + std::string functionName = concatSymbolTree(children[0]); if (children[1]->getData().getName() == "template_dec") { - functionName = concatSymbolTree(children[0]); functionDef = new NodeTree("function", ASTData(function, Symbol(functionName, true), new Type(template_type, from))); addToScope("~enclosing_scope", scope, functionDef); addToScope(functionName, functionDef, scope); @@ -304,7 +303,6 @@ NodeTree* ASTTransformation::secondPassFunction(NodeTree* from, //std::cout << "Finished Non-Instantiated Template function " << functionName << std::endl; return functionDef; } - functionName = concatSymbolTree(children[0]); auto returnTypeNode = getNode("type", getNode("typed_return", children)); // if null, the typed_return had no children and we're supposed to automatically do a void type auto returnType = returnTypeNode ? typeFromTypeNode(returnTypeNode, scope, templateTypeReplacements): new Type(void_type); if (!returnType) @@ -1629,7 +1627,15 @@ Type* ASTTransformation::typeFromTypeNode(NodeTree* typeNode, NodeTreegetDataRef()->type == type_def || definition->getDataRef()->type == adt_def) { + typeDefinition = definition; + break; + } + } traits = typeDefinition->getDataRef()->valueType->traits; } //So either this is an uninstatiated template class type, or this is literally a template type T, and we should get it from our diff --git a/src/CGenerator.cpp b/src/CGenerator.cpp index 033ea91..fe06abc 100644 --- a/src/CGenerator.cpp +++ b/src/CGenerator.cpp @@ -625,7 +625,9 @@ CCodeTriple CGenerator::generate(NodeTree* from, NodeTree* enc output.postValue += thingToMatch.postValue; for (auto case_stmt : slice(children, 1, -1)) { auto case_children = case_stmt->getChildren(); - std::string option = generate(case_children[0], enclosingObject, false, enclosingFunction).oneString(); + // was accidntally adding in prefix when it shouldn't, though maybe it should when both option and ADT name are identical, deal with this later + //std::string option = generate(case_children[0], enclosingObject, false, enclosingFunction).oneString(); + std::string option = case_children[0]->getDataRef()->symbol.getName(); std::string parentName = case_children[0]->getDataRef()->scope["~enclosing_scope"][0]->getDataRef()->symbol.getName(); output += "/* case " + option + " if " + thingToMatch.value + " */\n"; output += tabs() + "if ((" + thingToMatch.value + ").flag == " + parentName + "__" + option + ") {\n"; diff --git a/stdlib/ast_nodes.krak b/stdlib/ast_nodes.krak index 8545c8a..399cf5d 100644 --- a/stdlib/ast_nodes.krak +++ b/stdlib/ast_nodes.krak @@ -7,6 +7,7 @@ import util:* import string:* import mem:* import io:* +import type:* adt ast_node { @@ -127,11 +128,11 @@ obj import (Object) { return imported == other.imported && name == other.name } } -fun ast_identifier_ptr(name: *char): *ast_node { - return ast_identifier_ptr(string(name)) +fun ast_identifier_ptr(name: *char, type: *type): *ast_node { + return ast_identifier_ptr(string(name), type) } -fun ast_identifier_ptr(name: string): *ast_node { - var to_ret.construct(name): identifier +fun ast_identifier_ptr(name: string, type: *type): *ast_node { + var to_ret.construct(name, type): identifier var ptr = new() ptr->copy_construct(&ast_node::identifier(to_ret)) return ptr @@ -145,14 +146,17 @@ fun is_identifier(node: *ast_node): bool { obj identifier (Object) { var name: string var scope: map> - fun construct(nameIn: string): *identifier { - name.copy_construct(&nameIn) + var type: *type + fun construct(name_in: string, type_in: *type): *identifier { + name.copy_construct(&name_in) scope.construct() + type = type_in return this } fun copy_construct(old: *identifier) { name.copy_construct(&old->name) scope.copy_construct(&old->scope) + type = old->type } fun destruct() { name.destruct() @@ -163,7 +167,7 @@ obj identifier (Object) { copy_construct(&other) } fun operator==(other: ref identifier): bool { - return name == other.name + return name == other.name && type == other.type } } fun ast_type_def_ptr(name: string): *ast_node { @@ -238,8 +242,8 @@ obj adt_def (Object) { return name == other.name } } -fun ast_function_ptr(): *ast_node { - var to_ret.construct(): function +fun ast_function_ptr(name: string, type: *type, parameters: vector<*ast_node>): *ast_node { + var to_ret.construct(name, type, parameters): function var ptr = new() ptr->copy_construct(&ast_node::function(to_ret)) return ptr @@ -251,15 +255,26 @@ fun is_function(node: *ast_node): bool { return false } obj function (Object) { + var name: string + var type: *type + var parameters: vector<*ast_node> var scope: map> - fun construct(): *function { + fun construct(name_in: string, type_in: *type, parameters_in: vector<*ast_node>): *function { + name.copy_construct(&name_in) + parameters.copy_construct(¶meters_in) scope.construct() + type = type_in return this } fun copy_construct(old: *function) { + name.copy_construct(&old->name) + type = old->type + parameters.copy_construct(&old->parameters) scope.copy_construct(&old->scope) } fun destruct() { + name.destruct() + parameters.destruct() scope.destruct() } fun operator=(other: ref function) { @@ -267,7 +282,7 @@ obj function (Object) { copy_construct(&other) } fun operator==(other: ref function): bool { - return true + return name == name && type == other.type && parameters == other.parameters } } fun ast_code_block_ptr(): *ast_node { @@ -858,10 +873,10 @@ fun get_ast_name(node: *ast_node): string { match (*node) { ast_node::translation_unit(backing) return string("translation_unit: ") + backing.name ast_node::import(backing) return string("import: ") + backing.name + "; [" + backing.imported.reduce(fun(name: string, acc: string): string return acc + " " + name;, string()) + " ]" - ast_node::identifier(backing) return string("identifier: ") + backing.name + ast_node::identifier(backing) return string("identifier: ") + backing.name + ": " + backing.type->to_string() ast_node::type_def(backing) return string("type_def: ") + backing.name ast_node::adt_def(backing) return string("adt_def: ") + backing.name - ast_node::function(backing) return string("function") + ast_node::function(backing) return string("function: ") + backing.name + ": " + backing.type->to_string() ast_node::code_block(backing) return string("code_block") ast_node::statement(backing) return string("statement") ast_node::if_statement(backing) return string("if_statement") diff --git a/stdlib/ast_transformation.krak b/stdlib/ast_transformation.krak index 11c654e..5e33df6 100644 --- a/stdlib/ast_transformation.krak +++ b/stdlib/ast_transformation.krak @@ -86,8 +86,28 @@ obj ast_transformation (Object) { } }) } - fun second_pass_function(parse_tree: *tree, translation_unit: *ast_node, template_replacements: map): *ast_node { - return ast_function_ptr() + fun second_pass_function(node: *tree, translation_unit: *ast_node, template_replacements: map): *ast_node { + var function_name = concat_symbol_tree(get_node("func_identifier", node)) + // check to see if it is a template + // figure out return type + var typed_return_node = get_node("typed_return", node) + // darn no ternary yet + var return_type = null() + if (typed_return_node) return_type = transform_type(get_node("type", typed_return_node), translation_unit, template_replacements) + else return_type = type_ptr(base_type::void_return()) + // transform parameters + var parameters = vector<*ast_node>() + get_nodes("typed_parameter", node).for_each(fun(child: *tree) { + parameters.add(ast_identifier_ptr(concat_symbol_tree(get_node("identifier", child)), transform_type(get_node("type", child), translation_unit, template_replacements))) + }) + // figure out function type and make function_node + var function_node = ast_function_ptr(function_name, type_ptr(parameters.map(fun(parameter: *ast_node): *type return parameter->identifier.type;), return_type), parameters) + // add to scope (translation_unit) + add_to_scope(function_name, function_node, translation_unit) + add_to_scope("~enclosing_scope", translation_unit, function_node) + // add parameters to scope of function + parameters.for_each(fun(parameter: *ast_node) add_to_scope(parameter->identifier.name, parameter, function_node);) + return function_node } fun third_pass(parse_tree: *tree, translation_unit: *ast_node) { println(string("Third Pass for ") + translation_unit->translation_unit.name) @@ -95,6 +115,32 @@ obj ast_transformation (Object) { fun fourth_pass(parse_tree: *tree, translation_unit: *ast_node) { println(string("Fourth Pass for ") + translation_unit->translation_unit.name) } + fun transform_type(node: *tree, scope: *ast_node, template_replacements: map): *type { + // check for references and step down + // always get to pre-reffed level + var real_node = get_node("pre_reffed", node) + // check for indirection and step down + var type_syntax_str = concat_symbol_tree(real_node) + // should take into account indirection and references... + if (type_syntax_str == "void") + return type_ptr(base_type::void_return()) + else if (type_syntax_str == "bool") + return type_ptr(base_type::boolean()) + else if (type_syntax_str == "int") + return type_ptr(base_type::integer()) + else if (type_syntax_str == "float") + return type_ptr(base_type::floating()) + else if (type_syntax_str == "double") + return type_ptr(base_type::double_precision()) + else if (type_syntax_str == "char") + return type_ptr(base_type::character()) + else if (/* check for function type*/ true) + return type_ptr(base_type::function()) + else { + // do lookup for objects, ADTs, templates, etc + return type_ptr(base_type::none()) + } + } /*NodeTree* ASTTransformation::transform(NodeTree* from, NodeTree* scope, std::vector types, bool limitToFunction, std::map templateTypeReplacements) {*/ fun transform(node: *tree, scope: *ast_node): *ast_node { var name = node->data.name @@ -117,8 +163,9 @@ obj ast_transformation (Object) { } fun transform_identifier(node: *tree, scope: *ast_node): *ast_node { // for identifier we have to do scope lookup, etc, and maybe limit to function + // NOT THIS var name = concat_symbol_tree(node) - return ast_identifier_ptr(name) + return ast_identifier_ptr(name, type_ptr(base_type::void_return())) } fun transform_code_block(node: *tree, scope: *ast_node): *ast_node { var new_block = ast_code_block_ptr() diff --git a/stdlib/c_generator.krak b/stdlib/c_generator.krak index 0387505..5b29c64 100644 --- a/stdlib/c_generator.krak +++ b/stdlib/c_generator.krak @@ -29,8 +29,9 @@ obj c_generator (Object) { var structs: string = "" var function_typedef_string_pre: string = "" var function_typedef_string: string = "" - var function_prototypes: string = "" - var variable_declarations: string = "" + var function_prototypes: string = "\n/**Function Prototypes**/\n" + var function_definitions: string = "\n/**Function Definitions**/\n" + var variable_declarations: string = "\n/**Variable Declarations**/\n" // poset generation into structs string @@ -46,12 +47,30 @@ obj c_generator (Object) { top_level_c_passthrough += generate_simple_passthrough(backing.statement->statement.child) } ast_node::simple_passthrough(backing) top_level_c_passthrough += generate_simple_passthrough(child) + ast_node::function(backing) { + // make sure not a template + // or a passthrough + // check for and add to parameters if a closure + var parameter_types = string() + var parameters = string() + // also add in name decoration + backing.parameters.for_each(fun(parameter: *ast_node) { + if (parameter_types != "") { parameter_types += ", "; parameters += ", ";} + parameter_types += type_to_c(parameter->identifier.type) + parameters += type_to_c(parameter->identifier.type) + " " + parameter->identifier.name + }) + function_prototypes += type_to_c(backing.type->return_type) + " " + backing.name + "(" + parameter_types + ");\n" + + // add parameters to destructor thingy (for returns)? Or should that be a different pass? + function_definitions += type_to_c(backing.type->return_type) + " " + backing.name + "(" + parameters + ") { " + " /* body here */ " + // emit parameter destructors? + function_definitions += "}\n" + } } }) }) - var function_definitions: string = "" - return make_pair(prequal+plain_typedefs+top_level_c_passthrough+variable_extern_declarations+structs+function_typedef_string_pre+function_typedef_string+function_prototypes+variable_declarations+function_definitions, linker_string) + return make_pair(prequal+plain_typedefs+top_level_c_passthrough+variable_extern_declarations+structs+function_typedef_string_pre+function_typedef_string+function_prototypes+variable_declarations+function_definitions + "\n", linker_string) } fun generate_simple_passthrough(node: *ast_node): string { // deal with all the passthrough params @@ -63,6 +82,25 @@ obj c_generator (Object) { ast_node::simple_passthrough(backing) return generate_simple_passthrough(node) } } + fun type_to_c(type: *type): string { + match (type->base) { + base_type::none() return string("none") + base_type::template() return string("template") + base_type::template_type() return string("template_type") + base_type::void_return() return string("void") + base_type::boolean() return string("bool") + base_type::character() return string("char") + base_type::integer() return string("int") + base_type::floating() return string("float") + base_type::double_precision() return string("double") + base_type::function() { + var temp = string("function: (") + type->parameter_types.for_each(fun(parameter_type: *type) temp += parameter_type->to_string() + " ";) + return temp + ")" + type->return_type->to_string() + } + } + return string("impossible type") + } } diff --git a/stdlib/type.krak b/stdlib/type.krak index 377c4d5..30c3b4c 100644 --- a/stdlib/type.krak +++ b/stdlib/type.krak @@ -1,7 +1,9 @@ +import mem:* +import string:* +import vector:* // hmm, like the ast_node, this is another candadate for being fully an ADT // one issue is that there are properties shared between most of the options (indirection, say) - adt base_type { none, template, @@ -15,27 +17,40 @@ adt base_type { function } -fun type(): type { - var to_ret.construct(): type - return to_ret +fun type_ptr(): *type { + return new()->construct() } -fun type(base: base_type): type { - var to_ret.construct(base): type - return to_ret +fun type_ptr(base: base_type): *type { + return new()->construct(base) +} +fun type_ptr(parameters: vector<*type>, return_type: *type): *type { + return new()->construct(parameters, return_type) } obj type (Object) { var base: base_type + var parameter_types: vector<*type> + var return_type: *type fun construct(): *type { base.copy_construct(&base_type::none()) + parameter_types.construct() return this } fun construct(base_in: base_type): *type { base.copy_construct(&base_in) + parameter_types.construct() + return this + } + fun construct(parameter_types_in: vector<*type>, return_type_in: *type): *type { + base.copy_construct(&base_type::function()) + parameter_types.copy_construct(¶meter_types) + return_type = return_type_in return this } fun copy_construct(old: *type) { - base = old->base + base.copy_construct(&old->base) + parameter_types.copy_construct(&old->parameter_types) + return_type = old->return_type } fun operator=(other: ref type) { destruct() @@ -43,6 +58,26 @@ obj type (Object) { } fun destruct() { base.destruct() + parameter_types.destruct() + } + fun to_string(): string { + match (base) { + base_type::none() return string("none") + base_type::template() return string("template") + base_type::template_type() return string("template_type") + base_type::void_return() return string("void_return") + base_type::boolean() return string("boolean") + base_type::character() return string("character") + base_type::integer() return string("integer") + base_type::floating() return string("floating") + base_type::double_precision() return string("double_precision") + base_type::function() { + var temp = string("function: (") + parameter_types.for_each(fun(parameter_type: *type) temp += parameter_type->to_string() + " ";) + return temp + ")" + return_type->to_string() + } + } + return string("impossible type") } } diff --git a/tests/to_parse.krak b/tests/to_parse.krak index f79846e..1b22490 100644 --- a/tests/to_parse.krak +++ b/tests/to_parse.krak @@ -7,7 +7,10 @@ obj Something (ObjectTrait) { } } -fun main(): int { +fun some_function(): float { + return 0 +} +fun some_other_function(in: bool): int { return 0 }