From 7dbfd8ca38059b14d811c45235d4ba1465fae1cb Mon Sep 17 00:00:00 2001 From: Nathan Braswell Date: Tue, 10 Jun 2014 00:53:30 -0700 Subject: [PATCH] Almost have it working, but member function lookup through a typedef doesn't quite work. (I think the problem's in CGenerator) --- include/ASTTransformation.h | 2 +- main.cpp | 10 +++++-- src/ASTTransformation.cpp | 28 +++++++++++++------ src/CGenerator.cpp | 14 ++++++---- tests/moreObjectTemplateTest.expected_results | 2 +- tests/moreObjectTemplateTest.krak | 8 ++---- 6 files changed, 39 insertions(+), 25 deletions(-) diff --git a/include/ASTTransformation.h b/include/ASTTransformation.h index c437681..dfaa553 100644 --- a/include/ASTTransformation.h +++ b/include/ASTTransformation.h @@ -21,7 +21,7 @@ class ASTTransformation: public NodeTransformation { //Second pass defines data inside objects, outside declaration statements, and function prototpyes (since we have type_defs now) void secondPass(NodeTree* ast, NodeTree* parseTree); - void secondPassDoClassInsides(NodeTree* typeDef, std::vector*> typedefChildren); + void secondPassDoClassInsides(NodeTree* typeDef, std::vector*> typedefChildren, std::map templateTypeReplacements); NodeTree* secondPassDeclaration(NodeTree* from, NodeTree* scope, std::map templateTypeReplacements); NodeTree* secondPassFunction(NodeTree* from, NodeTree* scope, std::map templateTypeReplacements); diff --git a/main.cpp b/main.cpp index 3654f6f..f33e2ed 100644 --- a/main.cpp +++ b/main.cpp @@ -21,7 +21,13 @@ int main(int argc, char* argv[]) { std::vector includePaths; - includePaths.push_back(""); //Local + includePaths.push_back(""); //Local + + if (argc <= 1) { + std::cout << "Kraken invocation: kraken sourceFile.krak grammerFile.kgm outputName" << std::endl; + std::cout << "Or for testing do: kraken --test [optional list of names of file (.krak .expected_results) without extentions to run]" << std::endl; + return 0; + } if (argc >= 2 && std::string(argv[1]) == "--test") { StringReader::test(); @@ -152,4 +158,4 @@ int main(int argc, char* argv[]) { CGenerator().generateCompSet(ASTs, outputName); return(0); } - + diff --git a/src/ASTTransformation.cpp b/src/ASTTransformation.cpp index cdc2c3c..61b7f69 100644 --- a/src/ASTTransformation.cpp +++ b/src/ASTTransformation.cpp @@ -98,12 +98,16 @@ void ASTTransformation::secondPass(NodeTree* ast, NodeTree* par //It's an alias if (typedefChildren[1]->getData().getName() == "type") { -/*HERE*/ typeDef->getDataRef()->valueType = typeFromTypeNode(typedefChildren[1], ast, std::map(), false); //No templates, we're in the traslation unit + Type* aliasedType = typeFromTypeNode(typedefChildren[1], ast, std::map(), false); //No templates, we're in the traslation unit + 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; + std::cout << "that is " << aliasedType->typeDefinition->getDataRef()->toString() << std::endl; continue; } //Do the inside of classes here typeDef->getDataRef()->valueType = new Type(typeDef); - secondPassDoClassInsides(typeDef, typedefChildren); + secondPassDoClassInsides(typeDef, typedefChildren, std::map()); } else if (i->getDataRef()->getName() == "function") { //Do prototypes of functions ast->addChild(secondPassFunction(i, ast, std::map())); @@ -114,15 +118,15 @@ void ASTTransformation::secondPass(NodeTree* ast, NodeTree* par } } -void ASTTransformation::secondPassDoClassInsides(NodeTree* typeDef, std::vector*> typedefChildren) { +void ASTTransformation::secondPassDoClassInsides(NodeTree* typeDef, std::vector*> typedefChildren, std::map templateTypeReplacements) { //We pull out this functionality into a new function because this is used in typeFromTypeNode to partially instantiate templates for (NodeTree* j : typedefChildren) { if (j->getDataRef()->getName() == "declaration_statement") { //do declaration - typeDef->addChild(secondPassDeclaration(j, typeDef, std::map())); + typeDef->addChild(secondPassDeclaration(j, typeDef, templateTypeReplacements)); } else if (j->getDataRef()->getName() == "function") { //do member method - typeDef->addChild(secondPassFunction(j, typeDef, std::map())); + typeDef->addChild(secondPassFunction(j, typeDef, templateTypeReplacements)); } } } @@ -214,11 +218,15 @@ void ASTTransformation::fourthPass(NodeTree* ast, NodeTree* par //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->baseType == template_type) + 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 @@ -874,8 +882,10 @@ Type* ASTTransformation::typeFromTypeNode(NodeTree* typeNode, NodeTreegetDataRef()->scope["~enclosing_scope"].push_back(templateDefinition); if (!instantiateTemplates) { - selfType->templateTypeReplacement = newTemplateTypeReplacement; //Save the types for use when this is fully instantiated in pass 4 - secondPassDoClassInsides(typeDefinition, templateSyntaxTree->getChildren()); + std::cout << "!instantiateTemplates, so only partially instantiating " << fullyInstantiatedName << std::endl; + 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; diff --git a/src/CGenerator.cpp b/src/CGenerator.cpp index f47ac6a..854f646 100644 --- a/src/CGenerator.cpp +++ b/src/CGenerator.cpp @@ -64,6 +64,8 @@ std::string CGenerator::generate(NodeTree* from, NodeTree* enc //In case there are pointer dependencies. If the typedef has no children, then it is a simple renaming and we don't need to predeclare the class (maybe?) if (classChildren.size()) output += "struct " + CifyName(children[i]->getDataRef()->symbol.getName()) + ";\n"; + else if (children[i]->getDataRef()->valueType->typeDefinition != children[i] && !children[i]->getDataRef()->valueType->templateDefinition) //Isn't uninstantiated template or 0 parameter class, so must be alias + typedefPoset.addRelationship(children[i], children[i]->getDataRef()->valueType->typeDefinition); //An alias typedef depends on the type it aliases being declared before it } } //Now generate the typedef's in the correct, topological order @@ -82,7 +84,7 @@ std::string CGenerator::generate(NodeTree* from, NodeTree* enc break; case function: { - if (declarationData.valueType->baseType == template_type) + if (declarationData.valueType->baseType == template_type) output += "/* template function " + declarationData.symbol.toString() + " */\n"; else if (decChildren.size() == 0) //Not a real function, must be a built in passthrough output += "/* built in function: " + declarationData.symbol.toString() + " */\n"; @@ -95,7 +97,7 @@ std::string CGenerator::generate(NodeTree* from, NodeTree* enc parameters += ValueTypeToCType(decChildren[j]->getData().valueType) + " " + generate(decChildren[j], enclosingObject); nameDecoration += "_" + ValueTypeToCTypeDecoration(decChildren[j]->getData().valueType); } - output += CifyName(declarationData.symbol.getName()) + nameDecoration + "(" + parameters + "); /*func*/\n"; + output += CifyName(declarationData.symbol.getName() + nameDecoration) + "(" + parameters + "); /*func*/\n"; } } break; @@ -165,7 +167,7 @@ std::string CGenerator::generate(NodeTree* from, NodeTree* enc parameters += ValueTypeToCType(children[j]->getData().valueType) + " " + generate(children[j], enclosingObject); nameDecoration += "_" + ValueTypeToCTypeDecoration(children[j]->getData().valueType); } - output += CifyName(data.symbol.getName()) + nameDecoration + "(" + parameters + ")\n" + generate(children[children.size()-1], enclosingObject); + output += CifyName(data.symbol.getName() + nameDecoration) + "(" + parameters + ")\n" + generate(children[children.size()-1], enclosingObject); return output; } case code_block: @@ -253,9 +255,9 @@ std::string CGenerator::generate(NodeTree* from, NodeTree* enc std::cout << "Decorating (in access-should be object) " << name << " " << functionDefChildren.size() << std::endl; for (int i = 0; i < (functionDefChildren.size() > 0 ? functionDefChildren.size()-1 : 0); i++) nameDecoration += "_" + ValueTypeToCTypeDecoration(functionDefChildren[i]->getData().valueType); -/*HERE*/ return CifyName(possibleObjectType->getDataRef()->symbol.getName()) +"__" + CifyName(functionName) + nameDecoration + "(" + (name == "." ? "&" : "") + generate(children[1], enclosingObject) + ","; +/*HERE*/ return CifyName(possibleObjectType->getDataRef()->symbol.getName()) +"__" + CifyName(functionName + nameDecoration) + "(" + (name == "." ? "&" : "") + generate(children[1], enclosingObject) + ","; //The comma lets the upper function call know we already started the param list - //Note that we got here from a function call. We just pass up this special case and let them finish with the perentheses + //Note that we got here from a function call. We just pass up this special case and let them finish with the perentheses } else { std::cout << "Is not in scope or not type" << std::endl; return "((" + generate(children[1], enclosingObject) + ")" + name + functionName + ")"; @@ -275,7 +277,7 @@ std::string CGenerator::generate(NodeTree* from, NodeTree* enc bool isSelfObjectMethod = enclosingObject && contains(enclosingObject->getChildren(), children[0]); if (isSelfObjectMethod) output += enclosingObject->getDataRef()->symbol.getName() +"__"; -/*HERE*/ output += CifyName(name) + nameDecoration + "("; +/*HERE*/ output += CifyName(name + nameDecoration) + "("; if (isSelfObjectMethod) output += children.size() > 1 ? "self," : "self"; } diff --git a/tests/moreObjectTemplateTest.expected_results b/tests/moreObjectTemplateTest.expected_results index 3dddccb..38c003f 100644 --- a/tests/moreObjectTemplateTest.expected_results +++ b/tests/moreObjectTemplateTest.expected_results @@ -1 +1 @@ -345Hello!Hello!Hello! \ No newline at end of file +45Hello!Hello!Hello! diff --git a/tests/moreObjectTemplateTest.krak b/tests/moreObjectTemplateTest.krak index f2cd5e6..1a08428 100644 --- a/tests/moreObjectTemplateTest.krak +++ b/tests/moreObjectTemplateTest.krak @@ -2,7 +2,7 @@ import io; import trivial_container; typedef RegularObject { - MyInt num; + int num; trivialContainer innerContainer; void set(char* message, int number) { innerContainer.data = message; @@ -18,8 +18,6 @@ typedef RegularObject { }; typedef MyIntContainer trivialContainer; -typedef MyInt int; -MyInt c; MyIntContainer roundabout; RegularObject outsideDec; @@ -28,14 +26,12 @@ void print(trivialContainer toPrint) { } int main() { - c = 3; roundabout.data = 4; outsideDec.set("Hello!", 5); - print(c); roundabout.print(); outsideDec.print(); print(outsideDec.get()); print(outsideDec.innerContainer); print("\n"); return 0; -} \ No newline at end of file +}