diff --git a/include/ASTTransformation.h b/include/ASTTransformation.h index 4ae3e41..759ad67 100644 --- a/include/ASTTransformation.h +++ b/include/ASTTransformation.h @@ -23,6 +23,7 @@ class ASTTransformation: public NodeTransformation { NodeTree* doFunction(NodeTree* scope, std::string lookup, std::vector*> nodes, std::map templateTypeReplacements); NodeTree* scopeLookup(NodeTree* scope, std::string lookup, std::vector types = std::vector()); Type* typeFromTypeNode(NodeTree* typeNode, NodeTree* scope, std::map templateTypeReplacements); + NodeTree* findOrInstantiateFunctionTemplate(std::vector*> children, NodeTree* scope, std::vector types, std::map templateTypeReplacements); private: Importer * importer; std::map*>> languageLevelScope; diff --git a/krakenGrammer.kgm b/krakenGrammer.kgm index 66bc097..4cc0d2a 100644 --- a/krakenGrammer.kgm +++ b/krakenGrammer.kgm @@ -32,7 +32,7 @@ identifier = alpha | alpha alphanumeric ; overloadable_operator = "\+" | "-" | "\*" | "/" | "%" | "^" | "&" | "\|" | "~" | "\!" | "," | "=" | "\+\+" | "--" | "<<" | ">>" | "==" | "!=" | "&&" | "\|\|" | "\+=" | "-=" | "/=" | "%=" | "^=" | "&=" | "\|=" | "\*=" | "<<=" | ">>=" | "->" ; func_identifier = identifier | identifier overloadable_operator ; -function = type WS func_identifier WS "\(" WS opt_typed_parameter_list WS "\)" WS code_block ; +function = template_dec WS type WS func_identifier WS "\(" WS opt_typed_parameter_list WS "\)" WS code_block | type WS func_identifier WS "\(" WS opt_typed_parameter_list WS "\)" WS code_block ; opt_typed_parameter_list = typed_parameter_list | ; typed_parameter_list = typed_parameter_list WS "," WS typed_parameter | typed_parameter ; @@ -42,8 +42,8 @@ opt_parameter_list = parameter_list | ; parameter_list = parameter_list WS "," WS parameter | parameter ; parameter = boolean_expression ; -type_def = "typedef" WS identifier WS type | "typedef" WS template_dec WS identifier WS "{" WS class_innerds WS "}" | "typedef" WS template_dec WS identifier WS "{" WS declaration_block WS "}" ; -template_dec = "template" WS "<" WS identifier WS ">" | ; +type_def = "typedef" WS identifier WS type | "typedef" WS template_dec WS identifier WS "{" WS class_innerds WS "}" | "typedef" WS identifier WS "{" WS class_innerds WS "}" | "typedef" WS template_dec WS identifier WS "{" WS declaration_block WS "}" ; +template_dec = "template" WS "<" WS identifier WS ">" ; class_innerds = visibility_block WS class_innerds | visibility_block ; visibility_block = "public:" WS declaration_block | "protected:" WS declaration_block | "private:" WS declaration_block ; declaration_block = declaration_statement WS ";" WS declaration_block | function WS declaration_block | declaration_statement WS ";" | function ; @@ -71,7 +71,7 @@ expression = expression WS "<<" WS term | expression WS ">>" WS shiftand | shift shiftand = shiftand WS "-" WS term | shiftand WS "\+" WS term | term ; term = term WS forward_slash WS factor | term WS "\*" WS factor | term WS "%" WS factor | factor ; factor = "\+\+" WS unarad | unarad WS "\+\+" | "--" WS unarad | unarad WS "--" | "\+" WS unarad | "-" WS unarad | "!" WS unarad | "~" WS unarad | "\(" WS type WS "\)" WS unarad | "\*" WS unarad | "&" WS unarad | unarad WS "[" WS expression WS "]" | unarad ; -unarad = number | identifier | function_call | bool | string | character | "\(" WS boolean_expression WS "\)" | access_operation ; +unarad = number | identifier | identifier WS template_inst | function_call | bool | string | character | "\(" WS boolean_expression WS "\)" | access_operation ; number = integer | float | double ; access_operation = unarad "." identifier | unarad "->" identifier ; diff --git a/src/ASTTransformation.cpp b/src/ASTTransformation.cpp index 84215d0..00f4605 100644 --- a/src/ASTTransformation.cpp +++ b/src/ASTTransformation.cpp @@ -110,7 +110,16 @@ NodeTree* ASTTransformation::transform(NodeTree* from, NodeTree scope = newNode; //return newNode; } else if (name == "function") { - std::string functionName = concatSymbolTree(children[1]); + std::string functionName; + //If this is a function template + if (children[0]->getData().getName() == "template_dec") { + functionName = concatSymbolTree(children[2]); + newNode = new NodeTree(name, ASTData(function, Symbol(functionName, true), new Type(template_type, from))); + scope->getDataRef()->scope[functionName].push_back(newNode); + newNode->getDataRef()->scope["~enclosing_scope"].push_back(scope); + return newNode; + } + functionName = concatSymbolTree(children[1]); newNode = new NodeTree(name, ASTData(function, Symbol(functionName, true), typeFromTypeNode(children[0], scope, templateTypeReplacements))); skipChildren.insert(0); skipChildren.insert(1); @@ -126,7 +135,7 @@ NodeTree* ASTTransformation::transform(NodeTree* from, NodeTree // newNode->addChildren(transChildren); // return newNode; - std::cout << "finished function " << functionName << std::endl; + std::cout << "finished function (kinda, not children) " << functionName << std::endl; } else if (name == "code_block") { newNode = new NodeTree(name, ASTData(code_block)); newNode->getDataRef()->scope["~enclosing_scope"].push_back(scope); @@ -134,10 +143,12 @@ NodeTree* ASTTransformation::transform(NodeTree* from, NodeTree } else if (name == "typed_parameter") { //newNode = transform(children[1]); //Transform to get the identifier std::string parameterName = concatSymbolTree(children[1]); + std::cout << "Doing typed parameter " << parameterName << std::endl; //std::string typeString = concatSymbolTree(children[0]);//Get the type (left child) and set our new identifer to be that type newNode = new NodeTree("identifier", ASTData(identifier, Symbol(parameterName, true), typeFromTypeNode(children[0], scope, templateTypeReplacements))); scope->getDataRef()->scope[parameterName].push_back(newNode); newNode->getDataRef()->scope["~enclosing_scope"].push_back(scope); + std::cout << "Done doing typed_parameter " << parameterName << std::endl; return newNode; } else if (name == "boolean_expression" || name == "and_boolean_expression" || name == "bool_exp") { //If this is an actual part of an expression, not just a premoted term @@ -201,6 +212,9 @@ NodeTree* ASTTransformation::transform(NodeTree* from, NodeTree std::cout << "function call to " << functionCallName << " - " << function->getName() << " is now " << newNode->getDataRef()->valueType << std::endl; return newNode; //skipChildren.insert(1); + } else if (children.size() == 2) { + //Is template instantiation + return findOrInstantiateFunctionTemplate(children, scope, types, templateTypeReplacements); } else { return transform(children[0], scope, types, templateTypeReplacements); //Just a promoted child, so do it instead } @@ -294,10 +308,7 @@ NodeTree* ASTTransformation::transform(NodeTree* from, NodeTree } else if (name == "function_call") { std::string functionCallName = concatSymbolTree(children[0]); newNode = new NodeTree(functionCallName, ASTData(function_call, Symbol(functionCallName, true))); - // if (function == NULL) { - // std::cout << "scope lookup error! Could not find " << functionCallName << " in function_call " << std::endl; - // throw "LOOKUP ERROR: " + functionCallName; - // } + skipChildren.insert(0); std::vector*> transformedChildren = transformChildren(children, skipChildren, scope, types, templateTypeReplacements); std::cout << "scope lookup from function_call: " << functionCallName << std::endl; @@ -533,10 +544,16 @@ Type* ASTTransformation::typeFromTypeNode(NodeTree* typeNode, NodeTreeclone(); templateTypeReplacement->indirection += indirection; return templateTypeReplacement; + } else { + std::cout << edited << " was not found in templateTypeReplacements" << std::endl; + std::cout << "templateTypeReplacements consists of : "; + for (auto i : templateTypeReplacements) + std::cout << i.first << " "; + std::cout << std::endl; } //If not, we better instantiate it and then add it to the highest (not current) scope if (typeDefinition == NULL && typeNode->getChildren().size() > 1 && typeNode->getChildren()[1]->getData().getName() == "template_inst") { @@ -576,10 +593,53 @@ Type* ASTTransformation::typeFromTypeNode(NodeTree* typeNode, NodeTreeaddChildren(transformChildren(templateSyntaxTree->getChildren(), skipChildren, typeDefinition, std::vector(), newTemplateTypeReplacement)); std::cout << "Done instantating " << fullyInstantiatedName << " that had template parameter " << templateParameterName << " with " << replacementType->toString() << std::endl; } else { - std::cout << "Type: " << edited << " already instantiated!" << std::endl; + std::cout << "Type: " << edited << " already instantiated with " << typeDefinition << ", will be " << Type(baseType, typeDefinition, indirection).toString() << std::endl; } } Type* toReturn = new Type(baseType, typeDefinition, indirection); std::cout << "Returning type " << toReturn->toString() << std::endl; return toReturn; } + +NodeTree* ASTTransformation::findOrInstantiateFunctionTemplate(std::vector*> children, NodeTree* scope, std::vector types, std::map templateTypeReplacements) { + //First look to see if we can find this already instantiated + std::cout << "Finding or instantiating templated function" << std::endl; + std::string functionName = concatSymbolTree(children[0]); + std::string fullyInstantiatedName = functionName + concatSymbolTree(children[1]); + std::cout << "Looking for " << fullyInstantiatedName << std::endl; + NodeTree* instantiatedFunction = scopeLookup(scope, fullyInstantiatedName); + //If it already exists, return it + if (instantiatedFunction) + return instantiatedFunction; + + //Otherwise, we're going to instantiate it + //Find the template definition + NodeTree* templateDefinition = scopeLookup(scope,functionName); + NodeTree* templateSyntaxTree = templateDefinition->getDataRef()->valueType->templateDefinition; + std::string templateParameterName = concatSymbolTree(templateSyntaxTree->getChildren()[0]->getChildren()[1]); + std::map newTemplateTypeReplacement; + newTemplateTypeReplacement[templateParameterName] = typeFromTypeNode(children[1]->getChildren()[1], scope, templateTypeReplacements); + + std::vector*> templateChildren = templateSyntaxTree->getChildren(); + for (int i = 0; i < templateChildren.size(); i++) + std::cout << ", " << i << " : " << templateChildren[i]->getDataRef()->getName(); + std::cout << std::endl; + + instantiatedFunction = new NodeTree("function", ASTData(function, Symbol(fullyInstantiatedName, true), typeFromTypeNode(templateChildren[1], scope, newTemplateTypeReplacement))); + std::set skipChildren; + skipChildren.insert(0); + skipChildren.insert(1); + skipChildren.insert(2); + scope->getDataRef()->scope[fullyInstantiatedName].push_back(instantiatedFunction); + instantiatedFunction->getDataRef()->scope["~enclosing_scope"].push_back(templateDefinition->getDataRef()->scope["~enclosing_scope"][0]); //Instantiated Template Function's scope is it's template's definition's scope + std::cout << "About to do children of " << functionName << " to " << fullyInstantiatedName << std::endl; + instantiatedFunction->addChildren(transformChildren(templateSyntaxTree->getChildren(), skipChildren, instantiatedFunction, std::vector(), newTemplateTypeReplacement)); + + topScope->getDataRef()->scope[fullyInstantiatedName].push_back(instantiatedFunction); + topScope->addChild(instantiatedFunction); //Add this object the the highest scope's + + std::cout << "Fully Instantiated function " << functionName << " to " << fullyInstantiatedName << std::endl; + + return instantiatedFunction; +} + diff --git a/src/CGenerator.cpp b/src/CGenerator.cpp index bf146ae..e4ec64f 100644 --- a/src/CGenerator.cpp +++ b/src/CGenerator.cpp @@ -126,6 +126,8 @@ std::string CGenerator::generate(NodeTree* from, NodeTree* enc } case function: { + if (data.valueType->baseType == template_type) + return "/* template function: " + data.symbol.getName() + " */"; output += "\n" + ValueTypeToCType(data.valueType) + " "; std::string nameDecoration, parameters; for (int j = 0; j < children.size()-1; j++) {