diff --git a/include/ASTData.h b/include/ASTData.h index 5153779..4136645 100644 --- a/include/ASTData.h +++ b/include/ASTData.h @@ -27,6 +27,7 @@ class ASTData { ~ASTData(); std::string toString(); static std::string ASTTypeToString(ASTType type); + ASTType type; Type* valueType; Symbol symbol; diff --git a/include/ASTTransformation.h b/include/ASTTransformation.h index f6c4c01..3f1e763 100644 --- a/include/ASTTransformation.h +++ b/include/ASTTransformation.h @@ -48,7 +48,7 @@ class ASTTransformation: public NodeTransformation { NodeTree* doFunction(NodeTree* scope, std::string lookup, std::vector*> nodes, std::map templateTypeReplacements); NodeTree* functionLookup(NodeTree* scope, std::string lookup, std::vector types); - NodeTree* templateFunctionLookup(NodeTree* scope, std::string lookup, std::vector* templateInstantiationTypes, std::vector types); + NodeTree* templateFunctionLookup(NodeTree* scope, std::string lookup, std::vector* templateInstantiationTypes, std::vector types, std::map scopeTypeMap); std::vector*> scopeLookup(NodeTree* scope, std::string lookup, bool includeModules = false); std::vector*> scopeLookup(NodeTree* scope, std::string lookup, bool includeModules, std::vector*> visited); @@ -56,10 +56,10 @@ class ASTTransformation: public NodeTransformation { NodeTree* addToScope(std::string name, NodeTree* toAdd, NodeTree* addTo); Type* typeFromTypeNode(NodeTree* typeNode, NodeTree* scope, std::map templateTypeReplacements); NodeTree* templateClassLookup(NodeTree* scope, std::string name, std::vector templateInstantiationTypes); - void unifyType(NodeTree *syntaxType, Type type, std::map* templateTypeMap); - void unifyTemplateFunction(NodeTree* templateFunction, std::vector types, std::vector* templateInstantiationTypes); + void unifyType(NodeTree *syntaxType, Type type, std::map* templateTypeMap, std::map typeMap); + void unifyTemplateFunction(NodeTree* templateFunction, std::vector types, std::vector* templateInstantiationTypes, std::map typeMap); NodeTree* findOrInstantiateFunctionTemplate(std::vector*> children, NodeTree* scope, std::vector types, std::map templateTypeReplacements); - std::map makeTemplateFunctionTypeMap(NodeTree* templateNode, std::vector types); + std::map makeTemplateFunctionTypeMap(NodeTree* templateNode, std::vector types, std::map scopeTypeMap); std::vector>> makeTemplateNameTraitPairs(NodeTree* templateNode); private: diff --git a/src/ASTTransformation.cpp b/src/ASTTransformation.cpp index 939665a..f1f5b04 100644 --- a/src/ASTTransformation.cpp +++ b/src/ASTTransformation.cpp @@ -241,14 +241,6 @@ NodeTree* ASTTransformation::secondPassFunction(NodeTree* from, else //has traits yetToBeInstantiatedTemplateTypes[concatSymbolTree(i->getChildren()[0])] = new Type(template_type_type, parseTraits(i->getChildren()[1])); //This may have to be combined with templateTypeReplacements if we do templated member functions inside of templated classes } - // Just to see, I don't think templated functions actually need parameters at this point, and we might not have enough info anyway... - auto transChildren = transformChildren(slice(children,2,-3), std::set(), functionDef, std::vector(), yetToBeInstantiatedTemplateTypes); - std::cout << "Template function " << functionName << " has these parameters: "; - for (auto i : transChildren) - std::cout << "||" << i->getDataRef()->toString() << "|| "; - std::cout << "DoneList" << std::endl; - functionDef->addChildren(transChildren); - std::cout << "Finished Non-Instantiated Template function " << functionName << std::endl; return functionDef; } @@ -286,7 +278,8 @@ void ASTTransformation::thirdPass(NodeTree* ast, NodeTree* pars //Do the inside of classes here for (NodeTree* j : typedefChildren) { - if (j->getDataRef()->getName() == "function") { + // skip templated member functions + if (j->getDataRef()->getName() == "function" && j->getChildren()[1]->getDataRef()->getName() != "template_dec") { thirdPassFunction(j, searchScopeForFunctionDef(typeDef, j, std::map()), std::map()); //do member method } } @@ -316,7 +309,7 @@ void ASTTransformation::thirdPass(NodeTree* ast, NodeTree* pars Type* classTemplateType = i->getDataRef()->valueType; std::cout << "Instantiating template " << i->getDataRef()->toString() << std::endl; for (NodeTree* j : classTemplateType->templateDefinition->getChildren()) - if (j->getDataRef()->getName() == "function") + if (j->getDataRef()->getName() == "function" && j->getChildren()[1]->getDataRef()->getName() != "template_dec") thirdPassFunction(j, searchScopeForFunctionDef(i, j, classTemplateType->templateTypeReplacement), classTemplateType->templateTypeReplacement); //do member method classTemplateType->templateTypeReplacement.clear(); // This template has been fully instantiated, clear it's map so it won't be instantiated again } @@ -527,6 +520,9 @@ NodeTree* ASTTransformation::transform(NodeTree* from, NodeTree if (name == "access_operation") { std::cout << "lhs is: " << lhs->getDataRef()->toString() << std::endl; rhs = transform(children[2], lhs->getDataRef()->valueType->typeDefinition, types, templateTypeReplacements); //If an access operation, then the right side will be in the lhs's type's scope + // this might be a template member function, so do like below would do, but make it our rhs + if (rhs == nullptr) + rhs = findOrInstantiateFunctionTemplate(slice(children,2,-1), lhs->getDataRef()->valueType->typeDefinition, types, templateTypeReplacements); } else rhs = transform(children[2], scope, types, templateTypeReplacements); @@ -1013,11 +1009,14 @@ NodeTree* ASTTransformation::templateClassLookup(NodeTree* sco return *mostFittingTemplates.begin(); } -void ASTTransformation::unifyType(NodeTree *syntaxType, Type type, std::map* templateTypeMap) { +void ASTTransformation::unifyType(NodeTree *syntaxType, Type type, std::map* templateTypeMap, std::map typeMap) { // Ok, 3 options for syntaxType here. // 1) This a basic type. (int, or object, etc) // THIS ONE will fall through and get put in the map, but it // doesn't matter b/c it'll get filterd out in unifyTemplateFunction + // I also kina feel like maybe I need to worry about typeMap, which is why + // I passed it in... It would contain the typemap from our scope if we are + // doing a template member function of a templated object // 2) This is a template type type (i.e. T) // match! set up templateTypeMap[T] -> type // 3) This some sort of instantiated template @@ -1037,20 +1036,23 @@ void ASTTransformation::unifyType(NodeTree *syntaxType, Type type, std:: auto childrenTypes = getNodes("type", children.back()->getChildren()); // unify params for (int i = 0; i < childrenTypes.size()-1; i++) - unifyType(childrenTypes[i], *type.parameterTypes[i], templateTypeMap); - unifyType(childrenTypes.back(), *type.returnType, templateTypeMap); + unifyType(childrenTypes[i], *type.parameterTypes[i], templateTypeMap, typeMap); + unifyType(childrenTypes.back(), *type.returnType, templateTypeMap, typeMap); return; } if (children.size() == 1) { (*templateTypeMap)[concatSymbolTree(children.back())] = type; + // I also kina feel like maybe I need to worry about typeMap, which is why + // I passed it in... It would contain the typemap from our scope if we are + // doing a template member function of a templated object } else { // go down one in our pointer if (children.back()->getDataRef()->getValue() == "*") { // gotta be a better way to do this Type* clonedType = type.clone(); clonedType->decreaseIndirection(); - unifyType(children.front(), *clonedType, templateTypeMap); + unifyType(children.front(), *clonedType, templateTypeMap, typeMap); delete clonedType; return; } @@ -1068,7 +1070,7 @@ void ASTTransformation::unifyType(NodeTree *syntaxType, Type type, std:: std::vector*> uninTypeInstTypes = getNodes("type", getNode("template_inst", children)); std::vector*> typeInstTypes = getNodes("template_param", getNode("template_dec", typeTemplateDefinition->getChildren())); for (int i = 0; i < uninTypeInstTypes.size(); i++) - unifyType(uninTypeInstTypes[i], *origionalType->templateTypeReplacement[concatSymbolTree(typeInstTypes[i])], templateTypeMap); + unifyType(uninTypeInstTypes[i], *origionalType->templateTypeReplacement[concatSymbolTree(typeInstTypes[i])], templateTypeMap, typeMap); return; } @@ -1077,20 +1079,20 @@ void ASTTransformation::unifyType(NodeTree *syntaxType, Type type, std:: } } -void ASTTransformation::unifyTemplateFunction(NodeTree* templateFunction, std::vector types, std::vector* templateInstantiationTypes) { +void ASTTransformation::unifyTemplateFunction(NodeTree* templateFunction, std::vector types, std::vector* templateInstantiationTypes, std::map typeMap) { NodeTree* templateSyntaxTree = templateFunction->getDataRef()->valueType->templateDefinition; std::vector*> templateParameters = getNodes("typed_parameter", templateSyntaxTree); if (templateParameters.size() != types.size()) return; std::map templateTypeMap; for (int i = 0; i < types.size(); i++) - unifyType(getNode("type", templateParameters[i]), types[i], &templateTypeMap); + unifyType(getNode("type", templateParameters[i]), types[i], &templateTypeMap, typeMap); for (auto instantiationParam : getNodes("template_param", getNode("template_dec", templateSyntaxTree))) templateInstantiationTypes->push_back(templateTypeMap[concatSymbolTree(instantiationParam)].clone()); } //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) { +NodeTree* ASTTransformation::templateFunctionLookup(NodeTree* scope, std::string lookup, std::vector* templateInstantiationTypes, std::vector types, std::map scopeTypeMap) { std::map*, std::vector> templateInstantiationTypesPerFunction; std::set*> mostFittingTemplates; int bestNumTraitsSatisfied = -1; @@ -1104,17 +1106,19 @@ NodeTree* ASTTransformation::templateFunctionLookup(NodeTree* std::cout << "Not a template, skipping" << std::endl; continue; } + // We have the type map here because we might want to augment it with the typeMap from + // the current scope, which would happen if we're trying to instantiate a template member function + std::map typeMap = scopeTypeMap; // If template instantiation was explicit, use those types. Otherwise, unify to find them if (templateInstantiationTypes->size()) templateInstantiationTypesPerFunction[i] = *templateInstantiationTypes; else - unifyTemplateFunction(i, types, &templateInstantiationTypesPerFunction[i]); + unifyTemplateFunction(i, types, &templateInstantiationTypesPerFunction[i], typeMap); auto nameTraitsPairs = makeTemplateNameTraitPairs(templateSyntaxTree->getChildren()[1]); //Check if sizes match between the placeholder and actual template types if (nameTraitsPairs.size() != templateInstantiationTypesPerFunction[i].size()) continue; - std::map typeMap; bool traitsEqual = true; int typeIndex = 0; int currentTraitsSatisfied = 0; @@ -1197,9 +1201,11 @@ std::vector>> ASTTransformation::ma return typePairs; } -std::map ASTTransformation::makeTemplateFunctionTypeMap(NodeTree* templateNode, std::vector types) { +std::map ASTTransformation::makeTemplateFunctionTypeMap(NodeTree* templateNode, std::vector types, std::map scopeTypeMap) { auto typePairs = makeTemplateNameTraitPairs(templateNode); - std::map typeMap; + // we start with the scopeTypeMap because we want to combine + // them (this is for templated member functions of templated objects) + std::map typeMap = scopeTypeMap; int typeIndex = 0; std::cout << typePairs.size() << " " << types.size() << std::endl; for (auto i : typePairs) { @@ -1450,6 +1456,17 @@ NodeTree* ASTTransformation::findOrInstantiateFunctionTemplate(std::vec std::vector templateActualTypes; NodeTree* templateDefinition = NULL; + // If this is a templated member function, we should also add this function to the object + NodeTree* objectForTemplateMethod = NULL; + // Ok, our scope might have a typeMap if we are inside a templated object and are looking + // for a templated member function + std::map scopeTypeMap; + if (scope->getDataRef()->valueType && scope->getDataRef()->valueType->typeDefinition + && scope->getDataRef()->valueType->typeDefinition->getDataRef()->valueType) { + objectForTemplateMethod = scope->getDataRef()->valueType->typeDefinition; + scopeTypeMap = objectForTemplateMethod->getDataRef()->valueType->templateTypeReplacement; + } + // Are we supposed to infer our instantiation, or not? If we have only one child we're inferring as we don't // have the actual instantiation part. If do have the instantiation part, then we'll use that. // Note that as a part o finferring the instantiation we already find the template, so we make that @@ -1457,7 +1474,7 @@ NodeTree* ASTTransformation::findOrInstantiateFunctionTemplate(std::vec std::string instTypeString = ""; if (children.size() == 1) { // templateFunctionLookup adds the actual types to templateActualTypes if it's currently empty - templateDefinition = templateFunctionLookup(scope, functionName, &templateActualTypes, types); + templateDefinition = templateFunctionLookup(scope, functionName, &templateActualTypes, types, scopeTypeMap); for (auto instType : templateActualTypes) instTypeString += (instTypeString == "" ? instType->toString() : "," + instType->toString()); } else { @@ -1497,7 +1514,7 @@ NodeTree* ASTTransformation::findOrInstantiateFunctionTemplate(std::vec // by here, it's not as either we had the instantiation already or we figured out out before // and are not actually doing this call if (!templateDefinition) - templateDefinition = templateFunctionLookup(scope, functionName, &templateActualTypes, types); + templateDefinition = templateFunctionLookup(scope, functionName, &templateActualTypes, types, scopeTypeMap); if (templateDefinition == NULL) { std::cout << functionName << " search turned up null, returing null" << std::endl; return NULL; @@ -1505,7 +1522,7 @@ NodeTree* ASTTransformation::findOrInstantiateFunctionTemplate(std::vec NodeTree* templateSyntaxTree = templateDefinition->getDataRef()->valueType->templateDefinition; // Makes a map between the names of the template placeholder parameters and the provided types - std::map newTemplateTypeReplacement = makeTemplateFunctionTypeMap(templateSyntaxTree->getChildren()[1], templateActualTypes); + std::map newTemplateTypeReplacement = makeTemplateFunctionTypeMap(templateSyntaxTree->getChildren()[1], templateActualTypes, scopeTypeMap); std::vector*> templateChildren = templateSyntaxTree->getChildren(); for (int i = 0; i < templateChildren.size(); i++) @@ -1516,7 +1533,8 @@ NodeTree* ASTTransformation::findOrInstantiateFunctionTemplate(std::vec addToScope("~enclosing_scope", templateDefinition->getDataRef()->scope["~enclosing_scope"][0], instantiatedFunction); // Arrrrrgh this has a hard time working because the functions will need to see their parameter once they are emitted as C. // HAHAHAHAHA DOESN'T MATTER ALL ONE C FILE NOW, swap back to old way - auto templateTopScope = getUpperTranslationUnit(templateDefinition); + // OR, THIS IS A TEMPLATE METHOD AND ADD TO THE OBJECT + auto templateTopScope = objectForTemplateMethod ? objectForTemplateMethod : getUpperTranslationUnit(templateDefinition); addToScope(fullyInstantiatedName, instantiatedFunction, templateTopScope); templateTopScope->addChild(instantiatedFunction); // Add this object the the highest scope's diff --git a/src/CGenerator.cpp b/src/CGenerator.cpp index 6cad067..1aa4630 100644 --- a/src/CGenerator.cpp +++ b/src/CGenerator.cpp @@ -227,7 +227,8 @@ std::pair CGenerator::generateTranslationUnit(std::str std::string objectFunctionDefinitions = "/* Method Definitions for " + declarationData.symbol.getName() + " */\n"; for (int j = 0; j < decChildren.size(); j++) { std::cout << decChildren[j]->getName() << std::endl; - if (decChildren[j]->getName() == "function") //If object method + if (decChildren[j]->getName() == "function" + && decChildren[j]->getDataRef()->valueType->baseType != template_type) //If object method and not template objectFunctionDefinitions += generateObjectMethod(declaration, decChildren[j], &functionPrototypes) + "\n"; } // Add all aliases to the plain typedefs. This will add any alias that aliases to this object, and any alias that aliases to that, and so on @@ -397,7 +398,7 @@ std::string CGenerator::generate(NodeTree* from, NodeTree* enc && children[1]->getChildren()[0]->getChildren()[1] == children[0]) { //That is, if we're a declaration with an init position call (Object a.construct()) //We can tell if our function call (children[1])'s access operation([0])'s lhs ([1]) is the thing we just declared (children[0]) - return ValueTypeToCType(children[0]->getData().valueType, generate(children[0], enclosingObject, justFuncName)) + "; " + generate(children[1]) + "/*Init Position Call*/"; + return ValueTypeToCType(children[0]->getData().valueType, generate(children[0], enclosingObject, justFuncName)) + "; " + generate(children[1], enclosingObject, true) + "/*Init Position Call*/"; } else return ValueTypeToCType(children[0]->getData().valueType, generate(children[0], enclosingObject, justFuncName)) + " = " + generate(children[1], enclosingObject, true) + ";"; case if_comp: diff --git a/stdlib/vector.krak b/stdlib/vector.krak index 2d09690..963c888 100644 --- a/stdlib/vector.krak +++ b/stdlib/vector.krak @@ -26,6 +26,13 @@ obj vector (Destructable) { delete(data); } + fun clone(): vector { + var newVec.construct(size): vector + for (var i = 0; i < size; i++;) + newVec.set(i, data[i]) + return newVec + } + fun resize(newSize: int): bool { var newData: T* = new(newSize); if (!newData) @@ -67,5 +74,15 @@ obj vector (Destructable) { resize(size*2); data[size-1] = dataIn; } + fun in_place(func: fun(T):T):void { + for (var i = 0; i < size; i++;) + data[i] = func(data[i]) + } + fun map(func: fun(T):U):vector { + var newVec.construct(size): vector + for (var i = 0; i < size; i++;) + newVec.set(i, func(data[i])) + return newVec + } }; diff --git a/tests/test_templateMemberFunction.expected_results b/tests/test_templateMemberFunction.expected_results new file mode 100644 index 0000000..416d846 --- /dev/null +++ b/tests/test_templateMemberFunction.expected_results @@ -0,0 +1,3 @@ +3.141592 +7 +hi diff --git a/tests/test_templateMemberFunction.krak b/tests/test_templateMemberFunction.krak new file mode 100644 index 0000000..c15737b --- /dev/null +++ b/tests/test_templateMemberFunction.krak @@ -0,0 +1,30 @@ +import io:* + +obj templd { + var data: T + fun construct(dataIn:T):void { + data = dataIn + } + fun conv(func: fun(T):U): U { + return func(data) + } +} + +obj onlyMember { + var data: int + fun printAThing(otherDat: T):void { + println(data) + println(otherDat) + } +} + +fun main():int { + var hmm.construct(3): templd + println(hmm.conv(fun(it:int):double { return it + 0.141592; })) + + var onlyM: onlyMember + onlyM.data = 7 + onlyM.printAThing("hi") + return 0 +} + diff --git a/tests/test_vectorTest.expected_results b/tests/test_vectorTest.expected_results index e38777c..5f4449b 100644 --- a/tests/test_vectorTest.expected_results +++ b/tests/test_vectorTest.expected_results @@ -1,3 +1,6 @@ 4 1337 +26614 +15513 +3.7000007.7000007.70000015.700000 Destroyed! diff --git a/tests/test_vectorTest.krak b/tests/test_vectorTest.krak index d4a5d69..ac80972 100644 --- a/tests/test_vectorTest.krak +++ b/tests/test_vectorTest.krak @@ -17,7 +17,22 @@ fun main(): int { println(intVec.size); for (var i: int = 0; i < intVec.size; i++;) print(intVec.at(i)); + println(); + // in place lambda map + intVec.in_place(fun(it:int):int { return it*2; }) + for (var i: int = 0; i < intVec.size; i++;) + print(intVec.at(i)); + println(); + + var subd = intVec.map(fun(it:int):int { return it-1; }) + for (var i: int = 0; i < subd.size; i++;) + print(subd.at(i)); + println(); + + var newType = intVec.map(fun(it:int):double { return it+1.7; }) + for (var i: int = 0; i < newType.size; i++;) + print(newType.at(i)); println(); var desVec: vector* = new>()->construct();