diff --git a/CMakeLists.txt b/CMakeLists.txt index ab50798..8dc844b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,6 +2,7 @@ cmake_minimum_required (VERSION 2.6) project(Kraken) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") set( MY_INCLUDES ${PROJECT_SOURCE_DIR}/include) diff --git a/include/util.h b/include/util.h index 87edef2..f836a79 100644 --- a/include/util.h +++ b/include/util.h @@ -30,15 +30,24 @@ bool contains(std::vector vec, T item) { } template -std::vector slice(std::vector vec, int begin, int end) { +std::vector slice(std::vector vec, int begin, int end, int step = 1) { std::vector toReturn; if (begin < 0) begin += vec.size()+1; if (end < 0) end += vec.size()+1; - for (int i = begin; i < end; i++) + for (int i = begin; i < end; i += step) toReturn.push_back(vec[i]); return toReturn; } - +/* +std::vector split(std::string str, char delim) { + std::stringstream stream(str); + std::string item; + std::vector results; + while(std::getline(stream, item, delim)) + results.push_back(item); + return results; +} +*/ #endif diff --git a/krakenGrammer.kgm b/krakenGrammer.kgm index bc0d40b..8fdfba6 100644 --- a/krakenGrammer.kgm +++ b/krakenGrammer.kgm @@ -3,10 +3,16 @@ translation_unit = interpreter_directive WS unorderd_list_part WS ; unorderd_list_part = import WS unorderd_list_part | function WS unorderd_list_part | type_def WS ";" WS unorderd_list_part | if_comp WS unorderd_list_part | simple_passthrough WS unorderd_list_part | declaration_statement WS ";" WS unorderd_list_part | import | function | type_def WS ";" | if_comp | simple_passthrough | declaration_statement WS ";" ; type = type WS "\*" | "void" | "int" | "float" | "double" | "char" | identifier | identifier WS template_inst ; -template_inst = "<" WS type WS ">" ; + +template_inst = "<" WS type_list WS ">" ; +type_list = type_list WS "," WS type | type ; + +template_dec = "template" WS "<" WS identifier_list WS ">" ; +identifier_list = identifier_list WS "," WS identifier | identifier ; import = "import" WS identifier WS ";" ; + interpreter_directive = "#!" WS path | ; path = path path_part | path_part ; path_part = forward_slash alphanumeric | back_slash alphanumeric ; @@ -43,7 +49,6 @@ parameter_list = parameter_list WS "," WS parameter | parameter ; parameter = boolean_expression ; type_def = "typedef" WS identifier WS type | "typedef" WS template_dec WS identifier WS "{" WS class_innerds WS "}" | "typedef" WS identifier WS "{" WS class_innerds WS "}" | "typedef" WS template_dec WS identifier WS "{" WS declaration_block WS "}" | "typedef" WS identifier WS "{" WS declaration_block WS "}" ; -template_dec = "template" WS "<" WS identifier WS ">" ; class_innerds = visibility_block WS class_innerds | visibility_block ; visibility_block = "public:" WS declaration_block | "protected:" WS declaration_block | "private:" WS declaration_block ; declaration_block = declaration_statement WS ";" WS declaration_block | function WS declaration_block | declaration_statement WS ";" | function ; diff --git a/src/ASTTransformation.cpp b/src/ASTTransformation.cpp index b08fc3c..bb7a322 100644 --- a/src/ASTTransformation.cpp +++ b/src/ASTTransformation.cpp @@ -40,8 +40,7 @@ NodeTree* ASTTransformation::firstPass(std::string fileName, NodeTreeregisterAST(fileName, translationUnit, parseTree); //Register ourselves with the importer. //This puts us in the scope and the list of ASTs that go through all the passes - //Go through and define all types (type_defs wether they are classes or ailises) - //We fully create template types here because class templates can be instantiated in the next (second) pass + //Go through and define all types (type_defs whether they are classes or ailises, as well as including non-instantiated templates) for (NodeTree* i : children) { if (i->getDataRef()->getName() == "type_def") { std::string name; @@ -98,7 +97,7 @@ void ASTTransformation::secondPass(NodeTree* ast, NodeTree* par //It's an alias if (typedefChildren[1]->getData().getName() == "type") { - Type* aliasedType = typeFromTypeNode(typedefChildren[1], ast, std::map(), false); //No templates, we're in the traslation unit + Type* aliasedType = typeFromTypeNode(typedefChildren[1], ast, std::map(), false); //false - don't fully instantiate templates 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; @@ -135,7 +134,7 @@ void ASTTransformation::secondPassDoClassInsides(NodeTree* typeDef, std NodeTree* ASTTransformation::secondPassDeclaration(NodeTree* from, NodeTree* scope, std::map templateTypeReplacements) { NodeTree* decStmt = new NodeTree("declaration_statement", ASTData(declaration_statement)); std::string newIdentifierStr = concatSymbolTree(from->getChildren()[1]); -/*HERE*/Type* identifierType = typeFromTypeNode(from->getChildren()[0], scope, templateTypeReplacements, false); + Type* identifierType = typeFromTypeNode(from->getChildren()[0], scope, templateTypeReplacements, false); 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); @@ -157,10 +156,11 @@ NodeTree* ASTTransformation::secondPassFunction(NodeTree* from, scope->getDataRef()->scope[functionName].push_back(functionDef); functionDef->getDataRef()->scope["~enclosing_scope"].push_back(scope); std::map yetToBeInstantiatedTemplateTypes; //So that template types (like T) that have not been placed yet are found and given - //a special Type() - baseType = template_type_type - yetToBeInstantiatedTemplateTypes[concatSymbolTree(children[0]->getChildren()[1])] = new Type(template_type_type); //This may have to be combined with templateTypeReplacements if we do templated member functions inside of templated classes +/*MULTHERE*/ //a special Type() - baseType = template_type_type + 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 -/*HERE*/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, false); std::cout << "Template function " << functionName << " has these parameters: "; for (auto i : transChildren) std::cout << "||" << i->getDataRef()->toString() << "|| "; @@ -171,11 +171,11 @@ NodeTree* ASTTransformation::secondPassFunction(NodeTree* from, return functionDef; } functionName = concatSymbolTree(children[1]); -/*HERE*/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, false))); 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 -/*HERE*/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, false); // std::cout << "REGULAR function " << functionName << " has " << transChildren.size() << " parameters: "; // for (auto i : transChildren) @@ -387,7 +387,7 @@ NodeTree* ASTTransformation::transform(NodeTree* from, NodeTree scope = newNode; } else if (name == "function") { std::string functionName; - //If this is a function template +/*MULTHERE*/ //If this is a function template if (children[0]->getData().getName() == "template_dec") { functionName = concatSymbolTree(children[2]); newNode = new NodeTree(name, ASTData(function, Symbol(functionName, true), new Type(template_type, from))); @@ -395,9 +395,10 @@ NodeTree* ASTTransformation::transform(NodeTree* from, NodeTree newNode->getDataRef()->scope["~enclosing_scope"].push_back(scope); std::map yetToBeInstantiatedTemplateTypes; //So that template types (like T) that have not been placed yet are found and given //a special Type() - baseType = template_type_type - yetToBeInstantiatedTemplateTypes[concatSymbolTree(children[0]->getChildren()[1])] = new Type(template_type_type); //This may have to be combined with templateTypeReplacements if we do templated member functions inside of templated classes + 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, instantiateTemplates); std::cout << "Template function " << functionName << " has these parameters: "; for (auto i : transChildren) std::cout << "||" << i->getDataRef()->toString() << "|| "; @@ -861,12 +862,17 @@ Type* ASTTransformation::typeFromTypeNode(NodeTree* typeNode, NodeTree* templateSyntaxTree = templateDefinition->getDataRef()->valueType->templateDefinition; //Create a new map of template type names to actual types. std::map newTemplateTypeReplacement; - std::string templateParameterName = concatSymbolTree(templateSyntaxTree->getChildren()[0]->getChildren()[1]); - Type* replacementType = typeFromTypeNode(typeNode->getChildren()[1]->getChildren()[1], scope, templateTypeReplacements, instantiateTemplates); - newTemplateTypeReplacement[templateParameterName] = replacementType; - - std::string classNameWithoutTemplate = concatSymbolTree(typeNode->getChildren()[0]); - std::string fullyInstantiatedName = classNameWithoutTemplate + "<" + replacementType->toString() + ">"; +/*MULTHERE*/ + std::vector*> templateParamPlaceholderNodes = slice(templateSyntaxTree->getChildren()[0]->getChildren(), 1, -2, 2); //Don't get beginning or end for < or >, skip commas in the middle + std::vector*> templateParamInstantiationNodes = slice(typeNode->getChildren()[1]->getChildren(), 1, -2, 2); //same + std::string instTypeString = ""; + for (int i = 0; i < templateParamPlaceholderNodes.size(); i++) { + Type* instType = typeFromTypeNode(templateParamInstantiationNodes[i],scope, templateTypeReplacements, instantiateTemplates); + newTemplateTypeReplacement[concatSymbolTree(templateParamPlaceholderNodes[i])] = instType; + instTypeString += (instTypeString == "") ? instType->toString() : "," + instType->toString(); + } + std::string classNameWithoutTemplate = concatSymbolTree(typeNode->getChildren()[0]); + std::string fullyInstantiatedName = classNameWithoutTemplate + "<" + instTypeString + ">"; typeDefinition = new NodeTree("type_def", ASTData(type_def, Symbol(fullyInstantiatedName, true, fullyInstantiatedName))); Type* selfType = new Type(typeDefinition); //Type is self-referential since this is the definition @@ -892,7 +898,6 @@ Type* ASTTransformation::typeFromTypeNode(NodeTree* typeNode, NodeTreeaddChildren(transformChildren(templateSyntaxTree->getChildren(), skipChildren, typeDefinition, std::vector(), newTemplateTypeReplacement, instantiateTemplates)); - std::cout << "Done instantating " << fullyInstantiatedName << " that had template parameter " << templateParameterName << " with " << replacementType->toString() << std::endl; } } else if (typeDefinition == NULL) { std::cout << "Could not find type " << edited << ", returning NULL" << std::endl; @@ -908,13 +913,23 @@ Type* ASTTransformation::typeFromTypeNode(NodeTree* typeNode, NodeTree* ASTTransformation::findOrInstantiateFunctionTemplate(std::vector*> children, NodeTree* scope, std::vector types, std::map templateTypeReplacements) { //First look to see if we can find this already instantiated - std::cout << "Finding or instantiating templated function" << std::endl; + std::cout << "\n\nFinding or instantiating templated function\n\n" << std::endl; std::string functionName = concatSymbolTree(children[0]); - Type* templateActualType = typeFromTypeNode(children[1]->getChildren()[1], scope, templateTypeReplacements, true); - std::string fullyInstantiatedName = functionName + "<" + templateActualType->toString() + ">"; + + auto unsliced = children[1]->getChildren(); + std::vector*> templateParamInstantiationNodes = slice(unsliced, 1 , -2, 2);//skip <, >, and commas + std::string instTypeString = ""; + std::vector templateActualTypes; + for (int i = 0; i < templateParamInstantiationNodes.size(); i++) { + Type* instType = typeFromTypeNode(templateParamInstantiationNodes[i],scope, templateTypeReplacements, true); + instTypeString += (instTypeString == "" ? instType->toString() : "," + instType->toString()); + templateActualTypes.push_back(instType); + } + std::cout << "Size: " << templateParamInstantiationNodes.size() << std::endl; + std::string fullyInstantiatedName = functionName + "<" + instTypeString + ">"; std::cout << "Looking for " << fullyInstantiatedName << std::endl; - std::cout << "Types are : "; + std::cout << "Types are : "; for (auto i : types) std::cout << " " << i.toString(); std::cout << std::endl; @@ -937,12 +952,13 @@ NodeTree* ASTTransformation::findOrInstantiateFunctionTemplate(std::vec } NodeTree* templateSyntaxTree = templateDefinition->getDataRef()->valueType->templateDefinition; - std::string templateParameterName = concatSymbolTree(templateSyntaxTree->getChildren()[0]->getChildren()[1]); - std::map newTemplateTypeReplacement; - newTemplateTypeReplacement[templateParameterName] = templateActualType; + auto tmunsliced = templateSyntaxTree->getChildren()[0]->getChildren(); + std::vector*> templateParamPlaceholderNodes = slice(tmunsliced, 1, -2, 2);//skip <, >, and commas + for (int i = 0; i < templateParamPlaceholderNodes.size(); i++) + newTemplateTypeReplacement[concatSymbolTree(templateParamPlaceholderNodes[i])] = templateActualTypes[i]; - std::vector*> templateChildren = templateSyntaxTree->getChildren(); + std::vector*> templateChildren = templateSyntaxTree->getChildren(); for (int i = 0; i < templateChildren.size(); i++) std::cout << ", " << i << " : " << templateChildren[i]->getDataRef()->getName(); std::cout << std::endl; diff --git a/src/Importer.cpp b/src/Importer.cpp index 06f9de4..fb45a03 100644 --- a/src/Importer.cpp +++ b/src/Importer.cpp @@ -35,6 +35,8 @@ Importer::Importer(Parser* parserIn, std::vector includePaths) { collapseSymbols.push_back(Symbol("unorderd_list_part", false)); collapseSymbols.push_back(Symbol("if_comp_pred", false)); collapseSymbols.push_back(Symbol("declaration_block", false)); + collapseSymbols.push_back(Symbol("type_list", false)); + collapseSymbols.push_back(Symbol("identifier_list", false)); } Importer::~Importer() { @@ -105,7 +107,7 @@ void Importer::import(std::string fileName) { if (i.ast) { outFileAST << i.ast->DOTGraphString() << std::endl; } else { - std::cout << "Tree returned from ASTTransformation is NULL!" << std::endl; + std::cout << "Tree returned from ASTTransformation for " << fileName << " is NULL!" << std::endl; } outFileAST.close(); } @@ -118,7 +120,7 @@ NodeTree* Importer::parseAndTrim(std::string fileName) { std::string outputName = fileName + "out"; - + for (auto i : includePaths) { programInFile.open(i+fileName); if (programInFile.is_open()) @@ -157,7 +159,7 @@ NodeTree* Importer::parseAndTrim(std::string fileName) { //std::cout << parseTree->DOTGraphString() << std::endl; outFile << parseTree->DOTGraphString() << std::endl; } else { - std::cout << "ParseTree returned from parser is NULL!" << std::endl; + std::cout << "ParseTree returned from parser for " << fileName << " is NULL!" << std::endl; } outFile.close(); diff --git a/tests/functionMultipleTemplateTest.expected_results b/tests/functionMultipleTemplateTest.expected_results new file mode 100644 index 0000000..81f5bd9 --- /dev/null +++ b/tests/functionMultipleTemplateTest.expected_results @@ -0,0 +1 @@ +22.141590 diff --git a/tests/functionMultipleTemplateTest.krak b/tests/functionMultipleTemplateTest.krak new file mode 100644 index 0000000..f780891 --- /dev/null +++ b/tests/functionMultipleTemplateTest.krak @@ -0,0 +1,13 @@ +import io; + +template void addAndPrint(T a, J b) { + print(a+b); +} + +int main() { + + addAndPrint(10,12.14159); + print("\n"); + + return 0; +} diff --git a/tests/functionTemplateTest.krak b/tests/functionTemplateTest.krak index dd51c3d..16fabea 100644 --- a/tests/functionTemplateTest.krak +++ b/tests/functionTemplateTest.krak @@ -11,4 +11,4 @@ int main() { print("\n"); return 0; -} \ No newline at end of file +} diff --git a/tests/simpleObjectMultipleTemplateTest.expected_results b/tests/simpleObjectMultipleTemplateTest.expected_results new file mode 100644 index 0000000..2452da9 --- /dev/null +++ b/tests/simpleObjectMultipleTemplateTest.expected_results @@ -0,0 +1,4 @@ +a: 24 +b: Hello World +a: Pi incoming +b: 3.14159 - Fooled you! txt pi. C is being weird with floats. Not a Kraken problem. Ahh Well. diff --git a/tests/simpleObjectMultipleTemplateTest.krak b/tests/simpleObjectMultipleTemplateTest.krak new file mode 100644 index 0000000..cb8b831 --- /dev/null +++ b/tests/simpleObjectMultipleTemplateTest.krak @@ -0,0 +1,30 @@ +import io; + + +typedef template TemplateTest { + T a; + J b; + void print() { + print("a: "); + print(a); + print("\n"); + print("b: "); + print(b); + print("\n"); + } +}; + +int main() { + + TemplateTest test; + TemplateTest test2; + test.a = 24; + test.b = "Hello World"; + test2.a = "Pi incoming"; + test2.b = "3.14159 - Fooled you! txt pi. C is being weird with floats. Not a Kraken problem. Ahh Well."; + + test.print(); + test2.print(); + + return 0; +}