diff --git a/include/ASTTransformation.h b/include/ASTTransformation.h index 18f4e43..4d728a8 100644 --- a/include/ASTTransformation.h +++ b/include/ASTTransformation.h @@ -49,9 +49,10 @@ class ASTTransformation: public NodeTransformation { std::vector*> scopeLookup(NodeTree* scope, std::string lookup); Type* typeFromTypeNode(NodeTree* typeNode, NodeTree* scope, std::map templateTypeReplacements, bool instantiateTemplates); + NodeTree* templateClassLookup(NodeTree* scope, std::string name, std::vector templateInstantiationTypes); NodeTree* findOrInstantiateFunctionTemplate(std::vector*> children, NodeTree* scope, std::vector types, std::map templateTypeReplacements); std::map makeTemplateFunctionTypeMap(NodeTree* templateNode, std::vector types); - std::vector>> makeTemplateFunctionNameTraitPairs(NodeTree* templateNode); + std::vector>> makeTemplateNameTraitPairs(NodeTree* templateNode); private: Importer * importer; std::map*>> languageLevelReservedWords; diff --git a/include/Type.h b/include/Type.h index a56286e..a47fa7b 100644 --- a/include/Type.h +++ b/include/Type.h @@ -30,7 +30,7 @@ class Type { bool const operator==(const Type &other)const; bool const operator!=(const Type &other)const; Type* clone(); - std::string toString(); + std::string toString(bool showTraits = true); int getIndirection(); void setIndirection(int indirectionIn); void increaseIndirection(); diff --git a/src/ASTTransformation.cpp b/src/ASTTransformation.cpp index 33a456c..a5cd7bd 100644 --- a/src/ASTTransformation.cpp +++ b/src/ASTTransformation.cpp @@ -819,6 +819,59 @@ NodeTree* ASTTransformation::functionLookup(NodeTree* scope, s return NULL; } +//Lookup class templates. It evaluates possible matches on traits +NodeTree* ASTTransformation::templateClassLookup(NodeTree* scope, std::string lookup, std::vector templateInstantiationTypes) { + std::vector*> mostFittingTemplates; + int bestNumTraitsSatisfied = -1; + auto possibleMatches = scopeLookup(scope, lookup); + std::cout << "Template Class instantiation has " << possibleMatches.size() << " possible matches." << std::endl; + for (auto i : possibleMatches) { + NodeTree* templateSyntaxTree = i->getDataRef()->valueType->templateDefinition; + + auto nameTraitsPairs = makeTemplateNameTraitPairs(templateSyntaxTree->getChildren()[0]); + //Check if sizes match between the placeholder and actual template types + if (nameTraitsPairs.size() != templateInstantiationTypes.size()) + continue; + + bool traitsEqual = true; + int typeIndex = 0; + int currentTraitsSatisfied = 0; + for (auto j : nameTraitsPairs) { + if (j.second != templateInstantiationTypes[typeIndex]->traits) { + traitsEqual = false; + std::cout << "Traits unequal for " << j.first << " and " << templateInstantiationTypes[typeIndex]->toString() << ": "; + //std::cout << baseType << " " << indirection << " " << typeDefinition << " " << templateDefinition << " " << traits << ; + std::copy(j.second.begin(), j.second.end(), std::ostream_iterator(std::cout, " ")); + std::cout << " vs "; + std::copy(templateInstantiationTypes[typeIndex]->traits.begin(), templateInstantiationTypes[typeIndex]->traits.end(), std::ostream_iterator(std::cout, " ")); + std::cout << std::endl; + break; + } + currentTraitsSatisfied += templateInstantiationTypes[typeIndex]->traits.size(); + typeIndex++; + } + if (!traitsEqual) + continue; + + //See if this is a better match than the current best + if (currentTraitsSatisfied > bestNumTraitsSatisfied) { + mostFittingTemplates.clear(); + std::cout << "Class satisfying " << currentTraitsSatisfied << " beats previous " << bestNumTraitsSatisfied << std::endl; + bestNumTraitsSatisfied = currentTraitsSatisfied; + } else if (currentTraitsSatisfied < bestNumTraitsSatisfied) + continue; + mostFittingTemplates.push_back(i); + std::cout << "Current class fits, satisfying " << currentTraitsSatisfied << " traits" << std::endl; + } + if (!mostFittingTemplates.size()) { + std::cout << "No template classes fit for " << lookup << "!" << std::endl; + throw "No matching template classes"; + } else if (mostFittingTemplates.size() > 1) { + std::cout << "Multiple template classes fit with equal number of traits satisfied for " << lookup << "!" << std::endl; + throw "Multiple matching template classes"; + } + return mostFittingTemplates[0]; +} //Lookup function for template functions. It has some extra concerns compared to function lookup, namely traits NodeTree* ASTTransformation::templateFunctionLookup(NodeTree* scope, std::string lookup, std::vector templateInstantiationTypes, std::vector types) { @@ -826,12 +879,12 @@ NodeTree* ASTTransformation::templateFunctionLookup(NodeTree* int bestNumTraitsSatisfied = -1; auto possibleMatches = scopeLookup(scope, lookup); std::cout << "Template Function instantiation has " << possibleMatches.size() << " possible matches." << std::endl; + int index = 1; for (auto i : possibleMatches) { + std::cout << "Possibility " << index++ << std::endl; NodeTree* templateSyntaxTree = i->getDataRef()->valueType->templateDefinition; - //When called without a second parameter, makeTemplateFunctionTypeMap returns a map with blank Types filled in that contain the correct Traits - auto nameTraitsPairs = makeTemplateFunctionNameTraitPairs(templateSyntaxTree->getChildren()[0]); - + auto nameTraitsPairs = makeTemplateNameTraitPairs(templateSyntaxTree->getChildren()[0]); //Check if sizes match between the placeholder and actual template types if (nameTraitsPairs.size() != templateInstantiationTypes.size()) continue; @@ -869,7 +922,7 @@ NodeTree* ASTTransformation::templateFunctionLookup(NodeTree* std::cout << "Template param type: " << paramType->toString() << " : Needed Type: " << types[j].toString() << std::endl; if (*paramType != types[j]) { parameterTypesMatch = false; - std::cout << "Not equal: " << paramType->toString() << " : Needed Type: " << types[j].toString() << std::endl; + std::cout << "Not equal template param: " << paramType->toString() << " : Needed Type actual param: " << types[j].toString() << std::endl; break; } } @@ -896,7 +949,7 @@ NodeTree* ASTTransformation::templateFunctionLookup(NodeTree* } //Extract pairs of type names and traits -std::vector>> ASTTransformation::makeTemplateFunctionNameTraitPairs(NodeTree* templateNode) { +std::vector>> ASTTransformation::makeTemplateNameTraitPairs(NodeTree* templateNode) { std::vector*> templateParams = slice(templateNode->getChildren(), 1, -2, 2); //Skip <, >, and interveaning commas std::vector>> typePairs; for (auto i : templateParams) { @@ -909,7 +962,7 @@ std::vector>> ASTTransformation::ma } std::map ASTTransformation::makeTemplateFunctionTypeMap(NodeTree* templateNode, std::vector types) { - auto typePairs = makeTemplateFunctionNameTraitPairs(templateNode); + auto typePairs = makeTemplateNameTraitPairs(templateNode); std::map typeMap; int typeIndex = 0; std::cout << typePairs.size() << " " << types.size() << std::endl; @@ -984,9 +1037,18 @@ Type* ASTTransformation::typeFromTypeNode(NodeTree* typeNode, NodeTreegetChildren().size() > 1 && typeNode->getChildren()[1]->getData().getName() == "template_inst") { std::cout << "Template type: " << edited << " not yet instantiated" << std::endl; + + //We pull out the replacement types first so that we can choose the correct possibly overloaded template + std::vector*> templateParamInstantiationNodes = slice(typeNode->getChildren()[1]->getChildren(), 1, -2, 2); //same + std::vector templateParamInstantiationTypes; + std::string instTypeString = ""; + for (int i = 0; i < templateParamInstantiationNodes.size(); i++) { + Type* instType = typeFromTypeNode(templateParamInstantiationNodes[i], scope, templateTypeReplacements, instantiateTemplates); + templateParamInstantiationTypes.push_back(instType); + instTypeString += (instTypeString == "") ? instType->toString(false) : "," + instType->toString(false); + } //Look up this template's plain definition. It's type has the syntax tree that we need to parse - possibleMatches = scopeLookup(scope,concatSymbolTree(typeNode->getChildren()[0])); - NodeTree* templateDefinition = possibleMatches[0]; + NodeTree* templateDefinition = templateClassLookup(scope, concatSymbolTree(typeNode->getChildren()[0]), templateParamInstantiationTypes); if (templateDefinition == NULL) std::cout << "Template definition is null!" << std::endl; else @@ -994,25 +1056,23 @@ Type* ASTTransformation::typeFromTypeNode(NodeTree* typeNode, NodeTree* templateSyntaxTree = templateDefinition->getDataRef()->valueType->templateDefinition; //Create a new map of template type names to actual types. - std::map newTemplateTypeReplacement; -/*MULTHERE*/ std::vector*> templateParamPlaceholderNodes = slice(templateSyntaxTree->getChildren()[0]->getChildren(), 1, -2, 2); //Don't get beginning or end for < or >, skip commas in the middle - std::vector*> templateParamInstantiationNodes = slice(typeNode->getChildren()[1]->getChildren(), 1, -2, 2); //same - std::string instTypeString = ""; - for (int i = 0; i < templateParamPlaceholderNodes.size(); i++) { - Type* instType = typeFromTypeNode(templateParamInstantiationNodes[i],scope, templateTypeReplacements, instantiateTemplates); - newTemplateTypeReplacement[concatSymbolTree(templateParamPlaceholderNodes[i])] = instType; - instTypeString += (instTypeString == "") ? instType->toString() : "," + instType->toString(); - } + std::map newTemplateTypeReplacement; + for (int i = 0; i < templateParamInstantiationTypes.size(); i++) + newTemplateTypeReplacement[concatSymbolTree(templateParamPlaceholderNodes[i])] = templateParamInstantiationTypes[i]; + + //Finish creating the new name for this instantiation std::string classNameWithoutTemplate = concatSymbolTree(typeNode->getChildren()[0]); std::string fullyInstantiatedName = classNameWithoutTemplate + "<" + instTypeString + ">"; typeDefinition = new NodeTree("type_def", ASTData(type_def, Symbol(fullyInstantiatedName, true, fullyInstantiatedName))); - Type* selfType = new Type(typeDefinition); //Type is self-referential since this is the definition + traits = templateDefinition->getDataRef()->valueType->traits; // We have the same traits as the template definition + Type* selfType = new Type(typeDefinition, traits); // Type is self-referential since this is the definition. typeDefinition->getDataRef()->valueType = selfType; //Note that we're adding to the current top scope. This makes it more efficient by preventing multiple instantiation and should not cause any problems //It also makes sure it gets generated in the right place + std::cout << "Adding to top scope with fullyInstantiatedName " << fullyInstantiatedName << std::endl; topScope->getDataRef()->scope[fullyInstantiatedName].push_back(typeDefinition); topScope->addChild(typeDefinition); //Add this object the the highest scope's diff --git a/src/Type.cpp b/src/Type.cpp index f454127..a6988e6 100644 --- a/src/Type.cpp +++ b/src/Type.cpp @@ -65,7 +65,7 @@ const bool Type::operator!=(const Type &other) const { return(!this->operator==(other)); } -std::string Type::toString() { +std::string Type::toString(bool showTraits) { std::string typeString; switch (baseType) { case none: @@ -106,7 +106,7 @@ std::string Type::toString() { } for (int i = 0; i < indirection; i++) typeString += "*"; - if (traits.size()) { + if (traits.size() && showTraits) { typeString += "[ "; for (auto i : traits) typeString += i + " "; diff --git a/tests/traitsTest.expected_results b/tests/traitsTest.expected_results index 04f7294..603431e 100644 --- a/tests/traitsTest.expected_results +++ b/tests/traitsTest.expected_results @@ -3,3 +3,7 @@ First Trait Second Trait Both Traits +First Trait +Second Trait +Both Traits +No Traits diff --git a/tests/traitsTest.krak b/tests/traitsTest.krak index ff6162e..70e1ce9 100644 --- a/tests/traitsTest.krak +++ b/tests/traitsTest.krak @@ -30,11 +30,11 @@ template void OneTwoFunc(AlreadySpecilized obj) { //This should work for objects too! //To test, we cycle the mapping of traits +typedef template OneTwoObj (FirstTrait) {}; +typedef template OneTwoObj (SecondTrait) {}; +typedef template OneTwoObj (FirstTrait, SecondTrait) {}; +typedef template OneTwoObj {}; /* - *typedef template OneTwoObj (FirstTrait) {}; - *typedef template OneTwoObj (SecondTrait) {}; - *typedef template OneTwoObj (FirstTrait, SecondTrait) {}; - *typedef template OneTwoObj {}; *typedef template OneTwoObj { * void proveSpecilized() { * println("I'm specilized!"); @@ -57,21 +57,19 @@ int main() { println(); -/* - * OneTwoObj alpha; - * OneTwoObj beta; - * OneTwoObj gamma; - * OneTwoObj delta; - * OneTwoObj epsilon; - * - * OneTwoFunc>(alpha); - * OneTwoFunc>(b); - * OneTwoFunc>(c); - * OneTwoFunc>(d); - * - * //We can't pass along our inner part, so let's just make sure that it is the right object. - * //epsilon.proveSpecilized(); - */ + OneTwoObj alpha; + OneTwoObj beta; + OneTwoObj gamma; + OneTwoObj delta; +// OneTwoObj epsilon; + + OneTwoFunc>(alpha); + OneTwoFunc>(beta); + OneTwoFunc>(gamma); + OneTwoFunc>(delta); + + //We can't pass along our inner part, so let's just make sure that it is the right object. + //epsilon.proveSpecilized(); return 0; }