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; }