From 87ad0c187ef3719f25a6342ff474d650849b6ee2 Mon Sep 17 00:00:00 2001 From: Nathan Braswell Date: Wed, 23 Jul 2014 02:23:21 -0700 Subject: [PATCH] Fixed quite a few bugs, including makeing find template functions check for trait subset, not trait equality, and add the number required to the satisfied count. Based on what is now breaking, it looks like it's time to give the builtin functions types. --- include/ASTTransformation.h | 10 +- include/util.h | 9 ++ krakenGrammer.kgm | 2 +- src/ASTTransformation.cpp | 264 +++++++++++++++++++++--------------- stdlib/mem.krak | 5 +- stdlib/vector.krak | 4 +- tests/vectorTest.krak | 19 +-- 7 files changed, 182 insertions(+), 131 deletions(-) diff --git a/include/ASTTransformation.h b/include/ASTTransformation.h index 4d728a8..af5290a 100644 --- a/include/ASTTransformation.h +++ b/include/ASTTransformation.h @@ -34,21 +34,21 @@ class ASTTransformation: public NodeTransformation { //The fourth pass finishes up by doing all function bodies void fourthPass(NodeTree* ast, NodeTree* parseTree); - NodeTree* seachScopeForFunctionDef(NodeTree* scope, NodeTree* parseTree, std::map templateTypeReplacements); + NodeTree* searchScopeForFunctionDef(NodeTree* scope, NodeTree* parseTree, std::map templateTypeReplacements); void fourthPassFunction(NodeTree* from, NodeTree* functionDef, std::map templateTypeReplacements); virtual NodeTree* transform(NodeTree* from); - NodeTree* transform(NodeTree* from, NodeTree* scope, std::vector types, std::map templateTypeReplacements, bool instantiateTemplates); - std::vector*> transformChildren(std::vector*> children, std::set skipChildren, NodeTree* scope, std::vector types, std::map templateTypeReplacements, bool instantiateTemplates); + NodeTree* transform(NodeTree* from, NodeTree* scope, std::vector types, std::map templateTypeReplacements); + std::vector*> transformChildren(std::vector*> children, std::set skipChildren, NodeTree* scope, std::vector types, std::map templateTypeReplacements); std::vector mapNodesToTypes(std::vector*> nodes); std::string concatSymbolTree(NodeTree* root); 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); - std::vector*> scopeLookup(NodeTree* scope, std::string lookup); + std::vector*> scopeLookup(NodeTree* scope, std::string lookup, bool includeModules = false); - Type* typeFromTypeNode(NodeTree* typeNode, NodeTree* scope, std::map templateTypeReplacements, bool instantiateTemplates); + Type* typeFromTypeNode(NodeTree* typeNode, NodeTree* scope, std::map templateTypeReplacements); 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); diff --git a/include/util.h b/include/util.h index f836a79..2a5c70d 100644 --- a/include/util.h +++ b/include/util.h @@ -9,6 +9,7 @@ #include #include #include +#include #include #include @@ -40,6 +41,14 @@ std::vector slice(std::vector vec, int begin, int end, int step = 1) { toReturn.push_back(vec[i]); return toReturn; } + +template +bool subset(std::set a, std::set b) { + for (auto i : a) + if (b.find(i) == b.end()) + return false; + return true; +} /* std::vector split(std::string str, char delim) { std::stringstream stream(str); diff --git a/krakenGrammer.kgm b/krakenGrammer.kgm index 1e735b0..c1bfd26 100644 --- a/krakenGrammer.kgm +++ b/krakenGrammer.kgm @@ -79,7 +79,7 @@ function_call = unarad "\(" WS opt_parameter_list WS "\)" ; boolean_expression = boolean_expression WS "\|\|" WS and_boolean_expression | and_boolean_expression ; and_boolean_expression = and_boolean_expression "&&" bool_exp | bool_exp ; -bool_exp = expression WS comparator WS expression | bool | expression ; +bool_exp = expression WS comparator WS expression | expression ; comparator = "==" | "<=" | ">=" | "!=" | "<" | ">" ; expression = expression WS "<<" WS term | expression WS right_shift WS shiftand | shiftand ; diff --git a/src/ASTTransformation.cpp b/src/ASTTransformation.cpp index 688ba8d..efd6be0 100644 --- a/src/ASTTransformation.cpp +++ b/src/ASTTransformation.cpp @@ -118,7 +118,7 @@ void ASTTransformation::secondPass(NodeTree* ast, NodeTree* par //It's an alias. Note that if typedefChildren.size() == 1 it's because its a regular class with no body, i.e. {} if (typedefChildren.size() > 1 && typedefChildren[1]->getData().getName() == "type") { - Type* aliasedType = typeFromTypeNode(typedefChildren[1], ast, std::map(), false); //false - don't fully instantiate templates + Type* aliasedType = typeFromTypeNode(typedefChildren[1], ast, std::map()); typeDef->getDataRef()->valueType = aliasedType; typeDef->getDataRef()->scope["~enclosing_scope"][0] = aliasedType->typeDefinition; //So that object lookups find the right member. Note that this overrides translation_unit as a parent scope // std::cout << name << " alias's to " << aliasedType->typeDefinition << std::endl; @@ -155,7 +155,7 @@ NodeTree* ASTTransformation::secondPassDeclaration(NodeTree* fr //Check here for method call (an error here) NodeTree* decStmt = new NodeTree("declaration_statement", ASTData(declaration_statement)); std::string newIdentifierStr = concatSymbolTree(from->getChildren()[1]); - Type* identifierType = typeFromTypeNode(from->getChildren()[0], scope, templateTypeReplacements, false); + Type* identifierType = typeFromTypeNode(from->getChildren()[0], scope, templateTypeReplacements); std::cout << "Declaring an identifier " << newIdentifierStr << " to be of type " << identifierType->toString() << std::endl; NodeTree* newIdentifier = new NodeTree("identifier", ASTData(identifier, Symbol(newIdentifierStr, true), identifierType)); scope->getDataRef()->scope[newIdentifierStr].push_back(newIdentifier); @@ -184,7 +184,7 @@ 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 } - auto transChildren = transformChildren(slice(children,3,-2), std::set(), functionDef, std::vector(), yetToBeInstantiatedTemplateTypes, false); + auto transChildren = transformChildren(slice(children,3,-2), std::set(), functionDef, std::vector(), yetToBeInstantiatedTemplateTypes); std::cout << "Template function " << functionName << " has these parameters: "; for (auto i : transChildren) std::cout << "||" << i->getDataRef()->toString() << "|| "; @@ -195,11 +195,11 @@ NodeTree* ASTTransformation::secondPassFunction(NodeTree* from, return functionDef; } functionName = concatSymbolTree(children[1]); - functionDef = new NodeTree("function", ASTData(function, Symbol(functionName, true), typeFromTypeNode(children[0], scope, templateTypeReplacements, false))); + functionDef = new NodeTree("function", ASTData(function, Symbol(functionName, true), typeFromTypeNode(children[0], scope, templateTypeReplacements))); scope->getDataRef()->scope[functionName].push_back(functionDef); functionDef->getDataRef()->scope["~enclosing_scope"].push_back(scope); //We only do the parameter nodes. We don't do the body yet, as this is the secondPass - auto transChildren = transformChildren(slice(children,2,-2), std::set(), functionDef, std::vector(), templateTypeReplacements, false); + auto transChildren = transformChildren(slice(children,2,-2), std::set(), functionDef, std::vector(), templateTypeReplacements); // std::cout << "REGULAR function " << functionName << " has " << transChildren.size() << " parameters: "; // for (auto i : transChildren) @@ -240,22 +240,6 @@ void ASTTransformation::fourthPass(NodeTree* ast, NodeTree* par topScope = ast; //Top scope is maintained for templates, which need to add themselves to the top scope from where ever they are instantiated std::vector*> children = parseTree->getChildren(); - //First copy unfinished class templates into a new list and do them before anything else, so we know exactly which ones we need to do. - std::vector*> classTemplates; - for (auto i : ast->getDataRef()->scope) { - if (i.second[0]->getDataRef()->type == type_def && i.second[0]->getDataRef()->valueType->templateTypeReplacement.size()) { - classTemplates.push_back(i.second[0]); - std::cout << "Saving " << i.second[0]->getDataRef()->toString() << " to instantiate." << std::endl; - } - } - for (auto i : classTemplates) { - 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") - fourthPassFunction(j, seachScopeForFunctionDef(i, j, classTemplateType->templateTypeReplacement), classTemplateType->templateTypeReplacement); //do member method - } - //Go through and finish both regular functions and class methods //Note that this pass can instantiate class AND function templates for (NodeTree* i : children) { @@ -273,20 +257,44 @@ void ASTTransformation::fourthPass(NodeTree* ast, NodeTree* par //Do the inside of classes here for (NodeTree* j : typedefChildren) { if (j->getDataRef()->getName() == "function") { - fourthPassFunction(j, seachScopeForFunctionDef(typeDef, j, std::map()), std::map()); //do member method + fourthPassFunction(j, searchScopeForFunctionDef(typeDef, j, std::map()), std::map()); //do member method } } } else if (i->getDataRef()->getName() == "function") { //Do prototypes of functions if (i->getChildren()[0]->getData().getName() == "template_dec") continue; //We've already set up function templates - fourthPassFunction(i, seachScopeForFunctionDef(ast, i, std::map()), std::map()); + fourthPassFunction(i, searchScopeForFunctionDef(ast, i, std::map()), std::map()); } } + + // We do these here, in a loop, so that we can do mututally recursive definitions + // even inside of class templates. As its methods may cause partial instantiation of + // other class templates, we need to do this until the size no longer changes. + std::vector*> classTemplates; + int lastSize = 0; + while (lastSize != ast->getDataRef()->scope.size()) { + lastSize = ast->getDataRef()->scope.size(); + classTemplates.clear(); + for (auto i : ast->getDataRef()->scope) { + if (i.second[0]->getDataRef()->type == type_def && i.second[0]->getDataRef()->valueType->templateTypeReplacement.size()) { + classTemplates.push_back(i.second[0]); + std::cout << "Saving " << i.second[0]->getDataRef()->toString() << " to instantiate." << std::endl; + } + } + for (auto i : classTemplates) { + 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") + fourthPassFunction(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 + } + } } //This function finds the right AST definition in a scope given its parseTree -NodeTree* ASTTransformation::seachScopeForFunctionDef(NodeTree* scope, NodeTree* parseTree, std::map templateTypeReplacements) { +NodeTree* ASTTransformation::searchScopeForFunctionDef(NodeTree* scope, NodeTree* parseTree, std::map templateTypeReplacements) { std::string functionName = concatSymbolTree(parseTree->getChildren()[1]); std::vector types; std::vector*> children = parseTree->getChildren(); @@ -294,11 +302,11 @@ NodeTree* ASTTransformation::seachScopeForFunctionDef(NodeTree std::cout << "\n Searching scope for function def, function is :" << concatSymbolTree(children[1]) << ", children size is " << children.size() << std::endl; for (int i = 2; i < children.size()-1; i+=2) { //Skip over commas std::cout << "Making type for lookup ||" << concatSymbolTree(children[i]) << "||" << std::endl; - Type type = *typeFromTypeNode(children[i]->getChildren()[0], scope, templateTypeReplacements, true); + Type type = *typeFromTypeNode(children[i]->getChildren()[0], scope, templateTypeReplacements); std::cout << "Type made: " << type.toString() << std::endl; types.push_back(type); } - std::cout << "About to seach scope about " << concatSymbolTree(children[1]) << std::endl; + std::cout << "About to search scope about " << concatSymbolTree(children[1]) << std::endl; NodeTree* result = functionLookup(scope, functionName, types); std::cout << "Done searching scope about " << concatSymbolTree(children[1]) << std::endl; return result; @@ -309,15 +317,15 @@ NodeTree* ASTTransformation::seachScopeForFunctionDef(NodeTree //Note that it may instantiate class OR function templates, which need to be fully instantiated void ASTTransformation::fourthPassFunction(NodeTree* from, NodeTree* functionDef, std::map templateTypeReplacements) { NodeTree* codeBlock = from->getChildren()[from->getChildren().size()-1]; - functionDef->addChild(transform(codeBlock, functionDef, std::vector(), templateTypeReplacements, true)); + functionDef->addChild(transform(codeBlock, functionDef, std::vector(), templateTypeReplacements)); } NodeTree* ASTTransformation::transform(NodeTree* from) { //Set up top scope - return transform(from, NULL, std::vector(), std::map(), false); + return transform(from, NULL, std::vector(), std::map()); } -NodeTree* ASTTransformation::transform(NodeTree* from, NodeTree* scope, std::vector types, std::map templateTypeReplacements, bool instantiateTemplates) { +NodeTree* ASTTransformation::transform(NodeTree* from, NodeTree* scope, std::vector types, std::map templateTypeReplacements) { Symbol current = from->getData(); std::string name = current.getName(); NodeTree* newNode = NULL; @@ -351,8 +359,7 @@ NodeTree* ASTTransformation::transform(NodeTree* from, NodeTree newNode = scope->getDataRef()->scope[typeAlias][0]; //The node for this type_def has already been made by translation_unit. //This is done so that types that reference each other can be declared in any order - //newNode = new NodeTree(name, ASTData(type_def, Symbol(typeAlias, true, typeAlias), typeFromTypeNode(children[1], scope, templateTypeReplacements))); - newNode->getDataRef()->valueType = typeFromTypeNode(children[1], scope, templateTypeReplacements, instantiateTemplates); + newNode->getDataRef()->valueType = typeFromTypeNode(children[1], scope, templateTypeReplacements); skipChildren.insert(0); //Don't want any children, it's unnecessary for ailising skipChildren.insert(1); } else { //Is a struct or class @@ -364,7 +371,6 @@ NodeTree* ASTTransformation::transform(NodeTree* from, NodeTree //This is done so that types that reference each other can be declared in any order // std::cout << "typeAlias is " << typeAlias << " and newNode is " << newNode << std::endl; - //newNode = new NodeTree(name, ASTData(type_def, Symbol(typeAlias, true, typeAlias))); //So we give this typedef its name without any template types and make its type template_type, and point to this from node. //Then, when this template is instantiated, it will run transform on from with the types filled in. objectType = new Type(template_type, from); @@ -374,7 +380,6 @@ NodeTree* ASTTransformation::transform(NodeTree* from, NodeTree newNode = scope->getDataRef()->scope[typeAlias][0]; //The node for this type_def has already been made by translation_unit. //This is done so that types that reference each other can be declared in any order - //newNode = new NodeTree(name, ASTData(type_def, Symbol(typeAlias, true, typeAlias))); objectType = new Type(newNode); skipChildren.insert(0); //Identifier lookup will be ourselves, as we just added ourselves to the scope } @@ -400,7 +405,7 @@ NodeTree* ASTTransformation::transform(NodeTree* from, NodeTree for (auto i : slice(children[0]->getChildren(), 1, -1, 2)) //skip commas yetToBeInstantiatedTemplateTypes[concatSymbolTree(i)] = new Type(template_type_type); //This may have to be combined with templateTypeReplacements if we do templated member functions inside of templated classes - auto transChildren = transformChildren(slice(children,3,-2), std::set(), newNode, types, yetToBeInstantiatedTemplateTypes, instantiateTemplates); + auto transChildren = transformChildren(slice(children,3,-2), std::set(), newNode, types, yetToBeInstantiatedTemplateTypes); std::cout << "Template function " << functionName << " has these parameters: "; for (auto i : transChildren) std::cout << "||" << i->getDataRef()->toString() << "|| "; @@ -411,7 +416,7 @@ NodeTree* ASTTransformation::transform(NodeTree* from, NodeTree return newNode; } functionName = concatSymbolTree(children[1]); - newNode = new NodeTree(name, ASTData(function, Symbol(functionName, true), typeFromTypeNode(children[0], scope, templateTypeReplacements, instantiateTemplates))); + newNode = new NodeTree(name, ASTData(function, Symbol(functionName, true), typeFromTypeNode(children[0], scope, templateTypeReplacements))); skipChildren.insert(0); skipChildren.insert(1); scope->getDataRef()->scope[functionName].push_back(newNode); @@ -436,7 +441,7 @@ NodeTree* ASTTransformation::transform(NodeTree* from, NodeTree 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, instantiateTemplates))); + 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; @@ -446,7 +451,7 @@ NodeTree* ASTTransformation::transform(NodeTree* from, NodeTree if (children.size() > 1) { //We do children first so we can do appropriate scope searching with types (yay operator overloading!) skipChildren.insert(1); - std::vector*> transformedChildren = transformChildren(children, skipChildren, scope, types, templateTypeReplacements, instantiateTemplates); + std::vector*> transformedChildren = transformChildren(children, skipChildren, scope, types, templateTypeReplacements); std::string functionCallString = concatSymbolTree(children[1]); NodeTree* function = doFunction(scope, functionCallString, transformedChildren, templateTypeReplacements); if (function == NULL) { @@ -461,20 +466,20 @@ NodeTree* ASTTransformation::transform(NodeTree* from, NodeTree //std::cout << children.size() << std::endl; if (children.size() == 0) return new NodeTree(); - return transform(children[0], scope, types, templateTypeReplacements, instantiateTemplates); //Just a promoted term, so do child + return transform(children[0], scope, types, templateTypeReplacements); //Just a promoted term, so do child } //Here's the order of ops stuff } else if (name == "expression" || name == "shiftand" || name == "term" || name == "unarad" || name == "access_operation") { //If this is an actual part of an expression, not just a premoted child if (children.size() > 2) { - NodeTree* lhs = transform(children[0], scope, std::vector(), templateTypeReplacements, instantiateTemplates); //LHS does not inherit types + NodeTree* lhs = transform(children[0], scope, std::vector(), templateTypeReplacements); //LHS does not inherit types NodeTree* rhs; if (name == "access_operation") { std::cout << "lhs is: " << lhs->getDataRef()->toString() << std::endl; - rhs = transform(children[2], lhs->getDataRef()->valueType->typeDefinition, types, templateTypeReplacements, instantiateTemplates); //If an access operation, then the right side will be in the lhs's type's scope + 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 } else - rhs = transform(children[2], scope, types, templateTypeReplacements, instantiateTemplates); + rhs = transform(children[2], scope, types, templateTypeReplacements); std::string functionCallName = concatSymbolTree(children[1]); if (functionCallName == "[") @@ -501,7 +506,7 @@ NodeTree* ASTTransformation::transform(NodeTree* from, NodeTree //Is template instantiation return findOrInstantiateFunctionTemplate(children, scope, types, templateTypeReplacements); } else { - return transform(children[0], scope, types, templateTypeReplacements, instantiateTemplates); //Just a promoted child, so do it instead + return transform(children[0], scope, types, templateTypeReplacements); //Just a promoted child, so do it instead } } else if (name == "factor") { //Do factor here, as it has all the weird unary operators //If this is an actual part of an expression, not just a premoted child @@ -511,9 +516,9 @@ NodeTree* ASTTransformation::transform(NodeTree* from, NodeTree funcName = concatSymbolTree(children[0]); NodeTree* param; if (funcName == "*" || funcName == "&" || funcName == "++" || funcName == "--" || funcName == "-" || funcName == "!" || funcName == "~") - param = transform(children[1], scope, types, templateTypeReplacements, instantiateTemplates); + param = transform(children[1], scope, types, templateTypeReplacements); else - funcName = concatSymbolTree(children[1]), param = transform(children[0], scope, types, templateTypeReplacements, instantiateTemplates); + funcName = concatSymbolTree(children[1]), param = transform(children[0], scope, types, templateTypeReplacements); //std::cout << "scope lookup from factor" << std::endl; std::vector*> transformedChildren; transformedChildren.push_back(param); @@ -525,7 +530,7 @@ NodeTree* ASTTransformation::transform(NodeTree* from, NodeTree return function; } else { - return transform(children[0], scope, types, templateTypeReplacements, instantiateTemplates); //Just a promoted child, so do it instead + return transform(children[0], scope, types, templateTypeReplacements); //Just a promoted child, so do it instead } } else if (name == "statement") { newNode = new NodeTree(name, ASTData(statement)); @@ -541,12 +546,12 @@ NodeTree* ASTTransformation::transform(NodeTree* from, NodeTree newNode = new NodeTree(name, ASTData(assignment_statement)); std::string assignFuncName = concatSymbolTree(children[1]); if (assignFuncName == "=") { - newNode->addChild(transform(children[0], scope, types, templateTypeReplacements, instantiateTemplates)); - newNode->addChild(transform(children[2], scope, types, templateTypeReplacements, instantiateTemplates)); + newNode->addChild(transform(children[0], scope, types, templateTypeReplacements)); + newNode->addChild(transform(children[2], scope, types, templateTypeReplacements)); } else { //For assignments like += or *=, expand the syntatic sugar. - NodeTree* lhs = transform(children[0], scope, types, templateTypeReplacements, instantiateTemplates); - NodeTree* rhs = transform(children[2], scope, types, templateTypeReplacements, instantiateTemplates); + NodeTree* lhs = transform(children[0], scope, types, templateTypeReplacements); + NodeTree* rhs = transform(children[2], scope, types, templateTypeReplacements); std::vector*> transformedChildren; transformedChildren.push_back(lhs); transformedChildren.push_back(rhs); std::string functionName = assignFuncName.substr(0,1); NodeTree* operatorCall = doFunction(scope, functionName, transformedChildren, templateTypeReplacements); @@ -564,7 +569,7 @@ NodeTree* ASTTransformation::transform(NodeTree* from, NodeTree // NodeTree* newIdentifier = transform(children[1], scope); //Transform the identifier // newIdentifier->getDataRef()->valueType = Type(concatSymbolTree(children[0]));//set the type of the identifier std::string newIdentifierStr = concatSymbolTree(children[1]); - Type* identifierType = typeFromTypeNode(children[0], scope, templateTypeReplacements, instantiateTemplates); + Type* identifierType = typeFromTypeNode(children[0], scope, templateTypeReplacements); std::cout << "Declaring an identifier " << newIdentifierStr << " to be of type " << identifierType->toString() << std::endl; NodeTree* newIdentifier = new NodeTree("identifier", ASTData(identifier, Symbol(newIdentifierStr, true), identifierType)); scope->getDataRef()->scope[newIdentifierStr].push_back(newIdentifier); @@ -577,8 +582,8 @@ NodeTree* ASTTransformation::transform(NodeTree* from, NodeTree //This code is a simplified version of the code in function_call with respect to access_operation. //Note that in this case, what is lhs there is our newIdentifier here (the declaration of the left side of the access operation) auto sliced = slice(children, 4, -1); - std::vector*> initPositionFuncParams = transformChildren(sliced, std::set(), scope, types, templateTypeReplacements, instantiateTemplates); - NodeTree* rhs = transform(children[3], identifierType->typeDefinition, mapNodesToTypes(initPositionFuncParams), templateTypeReplacements, instantiateTemplates); //If an access operation, then the right side will be in the lhs's type's scope + std::vector*> initPositionFuncParams = transformChildren(sliced, std::set(), scope, types, templateTypeReplacements); + NodeTree* rhs = transform(children[3], identifierType->typeDefinition, mapNodesToTypes(initPositionFuncParams), templateTypeReplacements); //If an access operation, then the right side will be in the lhs's type's scope std::vector*> transformedChildren; transformedChildren.push_back(newIdentifier); transformedChildren.push_back(rhs); NodeTree* accessFuncCall = doFunction(scope, ".", transformedChildren, templateTypeReplacements); accessFuncCall->getDataRef()->valueType = rhs->getDataRef()->valueType; @@ -595,7 +600,7 @@ NodeTree* ASTTransformation::transform(NodeTree* from, NodeTree skipChildren.insert(0); //These, the type and the identifier, have been taken care of. skipChildren.insert(1); - newNode->addChildren(transformChildren(children, skipChildren, scope, types, templateTypeReplacements, instantiateTemplates)); + newNode->addChildren(transformChildren(children, skipChildren, scope, types, templateTypeReplacements)); return newNode; } else if (name == "if_comp") { newNode = new NodeTree(name, ASTData(if_comp)); @@ -608,12 +613,12 @@ NodeTree* ASTTransformation::transform(NodeTree* from, NodeTree newNode = new NodeTree(functionCallName, ASTData(function_call, Symbol(functionCallName, true))); skipChildren.insert(0); - std::vector*> transformedChildren = transformChildren(children, skipChildren, scope, types, templateTypeReplacements, instantiateTemplates); + std::vector*> transformedChildren = transformChildren(children, skipChildren, scope, types, templateTypeReplacements); std::cout << "scope lookup from function_call: " << functionCallName << std::endl; for (auto i : children) std::cout << i << " : " << i->getName() << " : " << i->getDataRef()->getName() << std::endl; - NodeTree* function = transform(children[0], scope, mapNodesToTypes(transformedChildren), templateTypeReplacements, instantiateTemplates); + NodeTree* function = transform(children[0], scope, mapNodesToTypes(transformedChildren), templateTypeReplacements); std::cout << "The thing: " << function << " : " << function->getName() << std::endl; for (auto i : function->getChildren()) std::cout << i->getName() << " "; @@ -623,12 +628,12 @@ NodeTree* ASTTransformation::transform(NodeTree* from, NodeTree newNode->addChildren(transformedChildren); return newNode; } else if (name == "parameter") { - return transform(children[0], scope, types, templateTypeReplacements, instantiateTemplates); //Don't need a parameter node, just the value + return transform(children[0], scope, types, templateTypeReplacements); //Don't need a parameter node, just the value } else if (name == "type") { std::string theConcat = concatSymbolTree(from); //We have no symbol, so this will concat our children - newNode = new NodeTree(name, ASTData(value, Symbol(theConcat, true), typeFromTypeNode(from, scope, templateTypeReplacements, instantiateTemplates))); + newNode = new NodeTree(name, ASTData(value, Symbol(theConcat, true), typeFromTypeNode(from, scope, templateTypeReplacements))); } else if (name == "number") { - return transform(children[0], scope, types, templateTypeReplacements, instantiateTemplates); + return transform(children[0], scope, types, templateTypeReplacements); } else if (name == "integer") { newNode = new NodeTree(name, ASTData(value, Symbol(concatSymbolTree(from), true), new Type(integer))); } else if (name == "floating_literal") { @@ -648,22 +653,27 @@ NodeTree* ASTTransformation::transform(NodeTree* from, NodeTree newNode = new NodeTree(name, ASTData(value, Symbol(concatSymbolTree(children[0]), true), new Type(character, 1))); //Indirection of 1 for array }else if (name == "character") { newNode = new NodeTree(name, ASTData(value, Symbol(concatSymbolTree(children[0]), true), new Type(character, 0))); //Indirection of 0 for character - } else { + } else if (name == "AmbiguityPackOuter" || name == "AmbiguityPackInner") { + std::cout << "Ambigious program when parsed by this grammer! This is a bug, please report it." << std::endl; + throw "Ambigious parse!"; + } else { + // Should get rid of this eventually. Right now it handles cases like sign, alpha, a comma, etc + std::cout << "Unhandled syntax node: " << name << std::endl; return new NodeTree(); } //Do all children but the ones we skip - newNode->addChildren(transformChildren(children, skipChildren, scope, types, templateTypeReplacements, instantiateTemplates)); + newNode->addChildren(transformChildren(children, skipChildren, scope, types, templateTypeReplacements)); return newNode; } //We use this functionality a lot at different places -std::vector*> ASTTransformation::transformChildren(std::vector*> children, std::set skipChildren, NodeTree* scope, std::vector types, std::map templateTypeReplacements, bool instantiateTemplates) { +std::vector*> ASTTransformation::transformChildren(std::vector*> children, std::set skipChildren, NodeTree* scope, std::vector types, std::map templateTypeReplacements) { std::vector*> transformedChildren; // In general, iterate through children and do them. Might not do this for all children. for (int i = 0; i < children.size(); i++) { if (skipChildren.find(i) == skipChildren.end()) { - NodeTree* transChild = transform(children[i], scope, types, templateTypeReplacements, instantiateTemplates); + NodeTree* transChild = transform(children[i], scope, types, templateTypeReplacements); if (transChild->getDataRef()->type) //Only add the children that have a real ASTData::ASTType, that is, legit ASTData. transformedChildren.push_back(transChild); else @@ -837,17 +847,24 @@ NodeTree* ASTTransformation::templateClassLookup(NodeTree* sco int typeIndex = 0; int currentTraitsSatisfied = 0; for (auto j : nameTraitsPairs) { - if (j.second != templateInstantiationTypes[typeIndex]->traits) { + if (!subset(j.second, templateInstantiationTypes[typeIndex]->traits)) { traitsEqual = false; - std::cout << "Traits unequal for " << j.first << " and " << templateInstantiationTypes[typeIndex]->toString() << ": "; + std::cout << "Traits not subset 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; + } else { + std::cout << "Traits ARE subset 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; } - currentTraitsSatisfied += templateInstantiationTypes[typeIndex]->traits.size(); + currentTraitsSatisfied += j.second.size(); typeIndex++; } if (!traitsEqual) @@ -898,18 +915,24 @@ NodeTree* ASTTransformation::templateFunctionLookup(NodeTree* int typeIndex = 0; int currentTraitsSatisfied = 0; for (auto j : nameTraitsPairs) { - if (j.second != templateInstantiationTypes[typeIndex]->traits) { + if (!subset(j.second, templateInstantiationTypes[typeIndex]->traits)) { traitsEqual = false; - std::cout << "Traits unequal for " << j.first << " and " << templateInstantiationTypes[typeIndex]->toString() << ": "; + std::cout << "Traits not a subset for " << j.first << " and " << templateInstantiationTypes[typeIndex]->toString() << ": "; 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; + } else { + std::cout << "Traits ARE a subset for " << j.first << " and " << templateInstantiationTypes[typeIndex]->toString() << ": "; + 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; } //As we go, build up the typeMap for when we transform the parameters for parameter checking typeMap[j.first] = templateInstantiationTypes[typeIndex]; - currentTraitsSatisfied += templateInstantiationTypes[typeIndex]->traits.size(); + currentTraitsSatisfied += j.second.size(); typeIndex++; } if (!traitsEqual) @@ -922,7 +945,7 @@ NodeTree* ASTTransformation::templateFunctionLookup(NodeTree* bool parameterTypesMatch = true; for (int j = 0; j < functionParameters.size(); j++) { - auto paramType = typeFromTypeNode(functionParameters[j]->getChildren()[0], scope, typeMap, false); + auto paramType = typeFromTypeNode(functionParameters[j]->getChildren()[0], scope, typeMap); std::cout << "Template param type: " << paramType->toString() << " : Needed Type: " << types[j].toString() << std::endl; if (*paramType != types[j]) { parameterTypesMatch = false; @@ -978,7 +1001,7 @@ std::map ASTTransformation::makeTemplateFunctionTypeMap(Node return typeMap; } -std::vector*> ASTTransformation::scopeLookup(NodeTree* scope, std::string lookup) { +std::vector*> ASTTransformation::scopeLookup(NodeTree* scope, std::string lookup, bool includeModules) { //We first check to see if it's one of the special reserved identifiers (only this, for now) and return early if it is. auto LLElementIterator = languageLevelReservedWords.find(lookup); if (LLElementIterator != languageLevelReservedWords.end()) { @@ -988,9 +1011,12 @@ std::vector*> ASTTransformation::scopeLookup(NodeTree std::vector*> matches; std::map*>> scopeMap = scope->getDataRef()->scope; auto possibleMatches = scopeMap.find(lookup); - if (possibleMatches != scopeMap.end()) - matches.insert(matches.end(), possibleMatches->second.begin(), possibleMatches->second.end()); - + if (possibleMatches != scopeMap.end()) { + for (auto i : possibleMatches->second) + if (includeModules || i->getName() != "translation_unit") + matches.push_back(i); + std::cout << "Found " << possibleMatches->second.size() << " match(s) at " << scope->getDataRef()->toString() << std::endl; + } // Add results from our enclosing scope, if it exists auto enclosingIterator = scopeMap.find("~enclosing_scope"); if (enclosingIterator != scopeMap.end()) { @@ -1001,7 +1027,7 @@ std::vector*> ASTTransformation::scopeLookup(NodeTree } //Create a type from a syntax tree. This can get complicated with templates -Type* ASTTransformation::typeFromTypeNode(NodeTree* typeNode, NodeTree* scope, std::map templateTypeReplacements, bool instantiateTemplates) { +Type* ASTTransformation::typeFromTypeNode(NodeTree* typeNode, NodeTree* scope, std::map templateTypeReplacements) { std::string typeIn = concatSymbolTree(typeNode); int indirection = 0; @@ -1044,6 +1070,14 @@ Type* ASTTransformation::typeFromTypeNode(NodeTree* typeNode, NodeTreegetChildren()[0]; + + std::cout << possibleMatches.size() << " " << typeNode->getChildren().size() << std::endl; + if (typeNode->getChildren().size() > 1) + std::cout << typeNode->getChildren()[1]->getDataRef()->getName() << std::endl; //If not, we better instantiate it and then add it to the highest (not current) scope if (possibleMatches.size() == 0 && typeNode->getChildren().size() > 1 && typeNode->getChildren()[1]->getData().getName() == "template_inst") { std::cout << "Template type: " << edited << " not yet instantiated" << std::endl; @@ -1053,55 +1087,63 @@ Type* ASTTransformation::typeFromTypeNode(NodeTree* typeNode, NodeTree templateParamInstantiationTypes; std::string instTypeString = ""; for (int i = 0; i < templateParamInstantiationNodes.size(); i++) { - Type* instType = typeFromTypeNode(templateParamInstantiationNodes[i], scope, templateTypeReplacements, instantiateTemplates); + Type* instType = typeFromTypeNode(templateParamInstantiationNodes[i], scope, templateTypeReplacements); 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 - NodeTree* templateDefinition = templateClassLookup(scope, concatSymbolTree(typeNode->getChildren()[0]), templateParamInstantiationTypes); - if (templateDefinition == NULL) - std::cout << "Template definition is null!" << std::endl; - else - std::cout << "Template definition is not null!" << std::endl; - - NodeTree* templateSyntaxTree = templateDefinition->getDataRef()->valueType->templateDefinition; - //Create a new map of template type names to actual types. - 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::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))); - 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; + // Recheck for prior definition here, now that we have the true name. + possibleMatches = scopeLookup(scope, fullyInstantiatedName); + if (possibleMatches.size()) { + typeDefinition = possibleMatches[0]; + traits = typeDefinition->getDataRef()->valueType->traits; + std::cout << "Found already instantiated template of " << fullyInstantiatedName << " at second check" << std::endl; + } else { + std::cout << "Did not find already instantiated template of " << fullyInstantiatedName << " at second check" << std::endl; + //Look up this template's plain definition. It's type has the syntax tree that we need to parse + NodeTree* templateDefinition = templateClassLookup(scope, concatSymbolTree(typeNode->getChildren()[0]), templateParamInstantiationTypes); + if (templateDefinition == NULL) + std::cout << "Template definition is null!" << std::endl; + else + std::cout << "Template definition is not null!" << std::endl; - //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 + NodeTree* templateSyntaxTree = templateDefinition->getDataRef()->valueType->templateDefinition; + //Create a new map of template type names to actual types. + 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::map newTemplateTypeReplacement; + for (int i = 0; i < templateParamInstantiationTypes.size(); i++) + newTemplateTypeReplacement[concatSymbolTree(templateParamPlaceholderNodes[i])] = templateParamInstantiationTypes[i]; + typeDefinition = new NodeTree("type_def", ASTData(type_def, Symbol(fullyInstantiatedName, true, fullyInstantiatedName))); + 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 the instantiated template's scope is the template's definition. - typeDefinition->getDataRef()->scope["~enclosing_scope"].push_back(templateDefinition); + //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 and template's origional scope with fullyInstantiatedName " << fullyInstantiatedName << std::endl; + topScope->getDataRef()->scope[fullyInstantiatedName].push_back(typeDefinition); + topScope->addChild(typeDefinition); //Add this object the the highest scope's + NodeTree* templateHighScope = templateDefinition->getDataRef()->scope["~enclosing_scope"][0]; + if (topScope != templateHighScope) + templateHighScope->getDataRef()->scope[fullyInstantiatedName].push_back(typeDefinition); - if (!instantiateTemplates) { - std::cout << "!instantiateTemplates, so only partially instantiating " << fullyInstantiatedName << std::endl; + //Note that the instantiated template's scope is the template's definition. + typeDefinition->getDataRef()->scope["~enclosing_scope"].push_back(templateDefinition); + + // We only partially instantiate templates no matter what now + // They are all fully instantiated in the loop at the end of the 4th pass + // This is done for code simplicity and so that that loop can do template class methods + // that instantiate other templates that instantiate other templates while still retaining the + // deferred method allowing us to correctly instantiate multiple levels of mututally recursive definitions. selfType->templateDefinition = templateSyntaxTree; //We're going to still need this when we finish instantiating selfType->templateTypeReplacement = newTemplateTypeReplacement; //Save the types for use when this is fully instantiated in pass 4 secondPassDoClassInsides(typeDefinition, templateSyntaxTree->getChildren(), newTemplateTypeReplacement); //Use these types when instantiating data members - } else { - //We're fully instantiating types. (we must be in pass 4) - std::set skipChildren; - skipChildren.insert(0); //Don't do the template part - skipChildren.insert(1); //Identifier lookup will be ourselves, as we just added ourselves to the scope - typeDefinition->addChildren(transformChildren(templateSyntaxTree->getChildren(), skipChildren, typeDefinition, std::vector(), newTemplateTypeReplacement, instantiateTemplates)); - } + } } else if (possibleMatches.size() == 0) { std::cout << "Could not find type " << edited << ", returning NULL" << std::endl; return NULL; @@ -1124,7 +1166,7 @@ NodeTree* ASTTransformation::findOrInstantiateFunctionTemplate(std::vec std::string instTypeString = ""; std::vector templateActualTypes; for (int i = 0; i < templateParamInstantiationNodes.size(); i++) { - Type* instType = typeFromTypeNode(templateParamInstantiationNodes[i],scope, templateTypeReplacements, true); + Type* instType = typeFromTypeNode(templateParamInstantiationNodes[i],scope, templateTypeReplacements); instTypeString += (instTypeString == "" ? instType->toString() : "," + instType->toString()); templateActualTypes.push_back(instType); } @@ -1163,7 +1205,7 @@ NodeTree* ASTTransformation::findOrInstantiateFunctionTemplate(std::vec 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, true))); + instantiatedFunction = new NodeTree("function", ASTData(function, Symbol(fullyInstantiatedName, true), typeFromTypeNode(templateChildren[1], scope, newTemplateTypeReplacement))); std::set skipChildren; skipChildren.insert(0); skipChildren.insert(1); @@ -1171,7 +1213,7 @@ NodeTree* ASTTransformation::findOrInstantiateFunctionTemplate(std::vec 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, true)); + 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 diff --git a/stdlib/mem.krak b/stdlib/mem.krak index 48b0505..0c4ca92 100644 --- a/stdlib/mem.krak +++ b/stdlib/mem.krak @@ -56,7 +56,7 @@ template void delete(T* toDelete, int itemCount) { } template void delete(T* toDelete, int itemCount) { - for (int i = 0; i < itemDestructCount; i++;) + for (int i = 0; i < itemCount; i++;) toDelete[i].destruct(); delete(toDelete); } @@ -67,7 +67,6 @@ template void delete(T* toDelete) { } template void delete(T* toDelete) { - if (destruct) - toDelete->destruct(); + toDelete->destruct(); free(toDelete); } diff --git a/stdlib/vector.krak b/stdlib/vector.krak index ca02a6a..ae52fe6 100644 --- a/stdlib/vector.krak +++ b/stdlib/vector.krak @@ -1,13 +1,13 @@ import mem; import util; -typedef template vector { +typedef template vector (Destructable) { T *data; int size; int available; bool destroyItems; - vector *construct(bool destroyItemsIn) { + vector* construct(bool destroyItemsIn) { destroyItems = destroyItemsIn; return construct(); size = 0; diff --git a/tests/vectorTest.krak b/tests/vectorTest.krak index 83d9898..878745f 100644 --- a/tests/vectorTest.krak +++ b/tests/vectorTest.krak @@ -1,7 +1,8 @@ import io; +import mem; import vector; -typedef Destructable { +typedef AbleToBeDestroyed (Destructable) { void destruct() { println("Destroyed!"); } @@ -9,19 +10,19 @@ typedef Destructable { int main() { vector intVec.construct(false); - intVec.addBack(1); - intVec.addBack(3); - intVec.addBack(3); - intVec.addBack(7); + intVec.addEnd(1); + intVec.addEnd(3); + intVec.addEnd(3); + intVec.addEnd(7); for (int i = 0; i < intVec.size(); i++;) print(intVec.at(i)); println(); - vector* desVec = new>()->construct(true); - Destructable testDestruct; - desVec->addBack(testDestruct); - delete>(desVec); + vector* desVec = new>()->construct(true); + AbleToBeDestroyed testDestruct; + desVec->addEnd(testDestruct); + delete>(desVec); return 0; }