Added (then fixed) templates with multiple parameters for both classes and functions!

This commit is contained in:
Nathan Braswell
2014-06-17 00:10:57 -07:00
parent e7a631240f
commit 82d8a15de0
10 changed files with 117 additions and 36 deletions

View File

@@ -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)

View File

@@ -30,15 +30,24 @@ bool contains(std::vector<T> vec, T item) {
}
template <typename T>
std::vector<T> slice(std::vector<T> vec, int begin, int end) {
std::vector<T> slice(std::vector<T> vec, int begin, int end, int step = 1) {
std::vector<T> 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<std::string> split(std::string str, char delim) {
std::stringstream stream(str);
std::string item;
std::vector<std::string> results;
while(std::getline(stream, item, delim))
results.push_back(item);
return results;
}
*/
#endif

View File

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

View File

@@ -40,8 +40,7 @@ NodeTree<ASTData>* ASTTransformation::firstPass(std::string fileName, NodeTree<S
importer->registerAST(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<Symbol>* i : children) {
if (i->getDataRef()->getName() == "type_def") {
std::string name;
@@ -98,7 +97,7 @@ void ASTTransformation::secondPass(NodeTree<ASTData>* ast, NodeTree<Symbol>* par
//It's an alias
if (typedefChildren[1]->getData().getName() == "type") {
Type* aliasedType = typeFromTypeNode(typedefChildren[1], ast, std::map<std::string, Type*>(), false); //No templates, we're in the traslation unit
Type* aliasedType = typeFromTypeNode(typedefChildren[1], ast, std::map<std::string, Type*>(), 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<ASTData>* typeDef, std
NodeTree<ASTData>* ASTTransformation::secondPassDeclaration(NodeTree<Symbol>* from, NodeTree<ASTData>* scope, std::map<std::string, Type*> templateTypeReplacements) {
NodeTree<ASTData>* decStmt = new NodeTree<ASTData>("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<ASTData>* newIdentifier = new NodeTree<ASTData>("identifier", ASTData(identifier, Symbol(newIdentifierStr, true), identifierType));
scope->getDataRef()->scope[newIdentifierStr].push_back(newIdentifier);
@@ -157,10 +156,11 @@ NodeTree<ASTData>* ASTTransformation::secondPassFunction(NodeTree<Symbol>* from,
scope->getDataRef()->scope[functionName].push_back(functionDef);
functionDef->getDataRef()->scope["~enclosing_scope"].push_back(scope);
std::map<std::string, Type*> 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<int>(), functionDef, std::vector<Type>(), yetToBeInstantiatedTemplateTypes, false);
auto transChildren = transformChildren(slice(children,3,-2), std::set<int>(), functionDef, std::vector<Type>(), yetToBeInstantiatedTemplateTypes, false);
std::cout << "Template function " << functionName << " has these parameters: ";
for (auto i : transChildren)
std::cout << "||" << i->getDataRef()->toString() << "|| ";
@@ -171,11 +171,11 @@ NodeTree<ASTData>* ASTTransformation::secondPassFunction(NodeTree<Symbol>* from,
return functionDef;
}
functionName = concatSymbolTree(children[1]);
/*HERE*/functionDef = new NodeTree<ASTData>("function", ASTData(function, Symbol(functionName, true), typeFromTypeNode(children[0], scope, templateTypeReplacements, false)));
functionDef = new NodeTree<ASTData>("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<int>(), functionDef, std::vector<Type>(), templateTypeReplacements, false);
auto transChildren = transformChildren(slice(children,2,-2), std::set<int>(), functionDef, std::vector<Type>(), templateTypeReplacements, false);
// std::cout << "REGULAR function " << functionName << " has " << transChildren.size() << " parameters: ";
// for (auto i : transChildren)
@@ -387,7 +387,7 @@ NodeTree<ASTData>* ASTTransformation::transform(NodeTree<Symbol>* 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<ASTData>(name, ASTData(function, Symbol(functionName, true), new Type(template_type, from)));
@@ -395,9 +395,10 @@ NodeTree<ASTData>* ASTTransformation::transform(NodeTree<Symbol>* from, NodeTree
newNode->getDataRef()->scope["~enclosing_scope"].push_back(scope);
std::map<std::string, Type*> 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<int>(), newNode, types, yetToBeInstantiatedTemplateTypes, instantiateTemplates);
auto transChildren = transformChildren(slice(children,3,-2), std::set<int>(), 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<Symbol>* typeNode, NodeTree<A
NodeTree<Symbol>* templateSyntaxTree = templateDefinition->getDataRef()->valueType->templateDefinition;
//Create a new map of template type names to actual types.
std::map<std::string, Type*> 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<NodeTree<Symbol>*> templateParamPlaceholderNodes = slice(templateSyntaxTree->getChildren()[0]->getChildren(), 1, -2, 2); //Don't get beginning or end for < or >, skip commas in the middle
std::vector<NodeTree<Symbol>*> 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<ASTData>("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<Symbol>* typeNode, NodeTree<A
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<Type>(), 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<Symbol>* typeNode, NodeTree<A
NodeTree<ASTData>* ASTTransformation::findOrInstantiateFunctionTemplate(std::vector<NodeTree<Symbol>*> children, NodeTree<ASTData>* scope, std::vector<Type> types, std::map<std::string, Type*> 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<NodeTree<Symbol>*> templateParamInstantiationNodes = slice(unsliced, 1 , -2, 2);//skip <, >, and commas
std::string instTypeString = "";
std::vector<Type*> 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<ASTData>* ASTTransformation::findOrInstantiateFunctionTemplate(std::vec
}
NodeTree<Symbol>* templateSyntaxTree = templateDefinition->getDataRef()->valueType->templateDefinition;
std::string templateParameterName = concatSymbolTree(templateSyntaxTree->getChildren()[0]->getChildren()[1]);
std::map<std::string, Type*> newTemplateTypeReplacement;
newTemplateTypeReplacement[templateParameterName] = templateActualType;
auto tmunsliced = templateSyntaxTree->getChildren()[0]->getChildren();
std::vector<NodeTree<Symbol>*> 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<NodeTree<Symbol>*> templateChildren = templateSyntaxTree->getChildren();
std::vector<NodeTree<Symbol>*> templateChildren = templateSyntaxTree->getChildren();
for (int i = 0; i < templateChildren.size(); i++)
std::cout << ", " << i << " : " << templateChildren[i]->getDataRef()->getName();
std::cout << std::endl;

View File

@@ -35,6 +35,8 @@ Importer::Importer(Parser* parserIn, std::vector<std::string> 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<Symbol>* 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<Symbol>* 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();

View File

@@ -0,0 +1 @@
22.141590

View File

@@ -0,0 +1,13 @@
import io;
template <T,J> void addAndPrint(T a, J b) {
print(a+b);
}
int main() {
addAndPrint<int,float>(10,12.14159);
print("\n");
return 0;
}

View File

@@ -11,4 +11,4 @@ int main() {
print("\n");
return 0;
}
}

View File

@@ -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.

View File

@@ -0,0 +1,30 @@
import io;
typedef template <T,J> TemplateTest {
T a;
J b;
void print() {
print("a: ");
print(a);
print("\n");
print("b: ");
print(b);
print("\n");
}
};
int main() {
TemplateTest<int, char*> test;
TemplateTest<char*, char*> 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;
}