From ae9e652f1ed49986f8bfcb423419cac1218959c1 Mon Sep 17 00:00:00 2001 From: Nathan Braswell Date: Sat, 24 May 2014 14:04:32 -0400 Subject: [PATCH] Mostly implemented Simultaneous Declaration, only template instantation during pass 2 remains to be implemented --- include/ASTTransformation.h | 17 ++ include/Importer.h | 15 +- src/ASTTransformation.cpp | 274 +++++++++++++++++- src/Importer.cpp | 91 ++++-- tests/functionOrderingTest.expected_results | 1 + tests/functionOrderingTest.krak | 17 ++ tests/moreObjectTemplateTest.expected_results | 1 + tests/moreObjectTemplateTest.krak | 41 +++ .../simpleObjectTemplateTest.expected_results | 4 + tests/simpleObjectTemplateTest.krak | 30 ++ 10 files changed, 461 insertions(+), 30 deletions(-) create mode 100644 tests/functionOrderingTest.expected_results create mode 100644 tests/functionOrderingTest.krak create mode 100644 tests/moreObjectTemplateTest.expected_results create mode 100644 tests/moreObjectTemplateTest.krak create mode 100644 tests/simpleObjectTemplateTest.expected_results create mode 100644 tests/simpleObjectTemplateTest.krak diff --git a/include/ASTTransformation.h b/include/ASTTransformation.h index 759ad67..c49969b 100644 --- a/include/ASTTransformation.h +++ b/include/ASTTransformation.h @@ -15,6 +15,23 @@ class ASTTransformation: public NodeTransformation { public: ASTTransformation(Importer* importerIn); ~ASTTransformation(); + + //First pass defines all type_defs (objects and ailises) + NodeTree* firstPass(std::string fileName, NodeTree* parseTree); + + //Second pass defines data inside objects, outside declaration statements, and function prototpyes (since we have type_defs now) + void secondPass(NodeTree* ast, NodeTree* parseTree); + NodeTree* secondPassDeclaration(NodeTree* from, NodeTree* scope, std::map templateTypeReplacements); + NodeTree* secondPassFunction(NodeTree* from, NodeTree* scope, std::map templateTypeReplacements); + + //Third pass redoes all imports to import the new function prototypes and identifiers + void thirdPass(NodeTree* ast); + + //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); + 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); std::vector*> transformChildren(std::vector*> children, std::set skipChildren, NodeTree* scope, std::vector types, std::map templateTypeReplacements); diff --git a/include/Importer.h b/include/Importer.h index dc79e7a..8ec0646 100644 --- a/include/Importer.h +++ b/include/Importer.h @@ -14,13 +14,26 @@ #include "CollapseTransformation.h" #include "ASTTransformation.h" +class ASTTransformation; + class Importer { public: Importer(Parser* parserIn, std::vector includePaths); ~Importer(); - NodeTree* import(std::string fileName); + void import(std::string fileName); + NodeTree* getUnit(std::string fileName); + NodeTree* importFirstPass(std::string fileName); + NodeTree* parseAndTrim(std::string fileName); + void registerAST(std::string name, NodeTree* ast, NodeTree* syntaxTree); std::map*> getASTMap(); private: + ASTTransformation *ASTTransformer; + struct importTriplet { + std::string name; + NodeTree* ast; + NodeTree* syntaxTree; + }; + std::vector importedTrips; std::vector includePaths; Parser* parser; std::vector removeSymbols; diff --git a/src/ASTTransformation.cpp b/src/ASTTransformation.cpp index 6d0d863..8663aec 100644 --- a/src/ASTTransformation.cpp +++ b/src/ASTTransformation.cpp @@ -33,6 +33,236 @@ ASTTransformation::~ASTTransformation() { // } +//First pass defines all type_defs (objects and ailises) +NodeTree* ASTTransformation::firstPass(std::string fileName, NodeTree* parseTree) { + NodeTree* translationUnit = new NodeTree("translation_unit", ASTData(translation_unit)); + std::vector*> children = parseTree->getChildren(); + 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 + for (NodeTree* i : children) { + if (i->getDataRef()->getName() == "type_def") { + std::string name; + if (i->getChildren()[0]->getData().getName() == "template_dec") // It's a template + name = concatSymbolTree(i->getChildren()[1]); + else //It's not + name = concatSymbolTree(i->getChildren()[0]); + NodeTree* firstDec = new NodeTree("type_def", ASTData(type_def, Symbol(name, true, name))); + //If this is a template, go ahead and set it up. Pass 2 needs templates set up so it can (partially) instantiate them. + if (i->getChildren()[0]->getData().getName() == "template_dec") + firstDec->getDataRef()->valueType = new Type(template_type, i); + //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. + + translationUnit->addChild(firstDec); + translationUnit->getDataRef()->scope[name].push_back(firstDec); + firstDec->getDataRef()->scope["~enclosing_scope"].push_back(translationUnit); + } + } + + //Now go through and do all imports + //We do this second so that if an import also imports us, all of our stuff has already been defined + for (NodeTree* i : children) { + if (i->getDataRef()->getName() == "import") { + std::string toImport = concatSymbolTree(i->getChildren()[0]); + translationUnit->addChild(new NodeTree("import", ASTData(import, Symbol(toImport, true)))); + //Do the imported file too + NodeTree* outsideTranslationUnit = importer->importFirstPass(toImport + ".krak"); + translationUnit->getDataRef()->scope[toImport].push_back(outsideTranslationUnit); //Put this transation_unit in the scope as it's files name + //Now add it to scope + for (auto i = outsideTranslationUnit->getDataRef()->scope.begin(); i != outsideTranslationUnit->getDataRef()->scope.end(); i++) + for (auto j : i->second) + translationUnit->getDataRef()->scope[i->first].push_back(j); + } + } + + return translationUnit; +} + +//Second pass defines data inside objects, outside declaration statements, and function prototypes (since we have type_defs now) +void ASTTransformation::secondPass(NodeTree* ast, NodeTree* parseTree) { + 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(); + + //Go through and declare data internal to objects as well as all function prototypes (methods and otherwise) + //Note that this pass can instantiate class templates + for (NodeTree* i : children) { + if (i->getDataRef()->getName() == "type_def") { + if (i->getChildren()[0]->getData().getName() == "template_dec") // It's a template + continue; //We've already set upt the class templates + std::vector*> typedefChildren = i->getChildren(); + std::string name = concatSymbolTree(typedefChildren[0]); + NodeTree* typeDef = ast->getDataRef()->scope[name][0]; //No overloaded types + + //It's an alias + if (typedefChildren[1]->getData().getName() == "type") { +/*HERE*/ typeDef->getDataRef()->valueType = typeFromTypeNode(typedefChildren[1], ast, std::map()); //No templates, we're in the traslation unit + continue; + } + //Do the inside of classes here + typeDef->getDataRef()->valueType = new Type(typeDef); + for (NodeTree* j : typedefChildren) { + if (j->getDataRef()->getName() == "declaration_statement") { + //do declaration + typeDef->addChild(secondPassDeclaration(j, typeDef, std::map())); + } else if (j->getDataRef()->getName() == "function") { + //do member method + typeDef->addChild(secondPassFunction(j, typeDef, std::map())); + } + } + + } else if (i->getDataRef()->getName() == "function") { + //Do prototypes of functions + ast->addChild(secondPassFunction(i, ast, std::map())); + } else if (i->getDataRef()->getName() == "declaration_statement") { + //Do declaration statements + ast->addChild(secondPassDeclaration(i, ast, std::map())); + } + } +} + +//This function may need to partially instantiate a class template +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); + 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); + decStmt->getDataRef()->scope["~enclosing_scope"].push_back(scope); + decStmt->addChild(newIdentifier); + + return decStmt; +} + +//This function may need to partially instantiate a class template +NodeTree* ASTTransformation::secondPassFunction(NodeTree* from, NodeTree* scope, std::map templateTypeReplacements) { + //If this is a function template + std::vector*> children = from->getChildren(); + NodeTree* functionDef = NULL; + std::string functionName; + if (children[0]->getData().getName() == "template_dec") { + functionName = concatSymbolTree(children[2]); + functionDef = new NodeTree("function", ASTData(function, Symbol(functionName, true), new Type(template_type, 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 + +/*HERE*/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() << "|| "; + std::cout << "DoneList" << std::endl; + functionDef->addChildren(transChildren); + + std::cout << "Finished Non-Instantiated Template function " << functionName << std::endl; + return functionDef; + } + functionName = concatSymbolTree(children[1]); +/*HERE*/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 +/*HERE*/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) + // std::cout << "||" << i->getDataRef()->toString() << "|| "; + // std::cout << "DoneList" << std::endl; + + + functionDef->addChildren(transChildren); + return functionDef; +} + +//Third pass redoes all imports to import the new function prototypes and identifiers +void ASTTransformation::thirdPass(NodeTree* ast) { + std::vector*> children = ast->getChildren(); + //Go through and do all imports again + for (NodeTree* i : children) { + if (i->getDataRef()->type == import) { + std::string toImport = i->getDataRef()->symbol.getName(); + NodeTree* outsideTranslationUnit = importer->getUnit(toImport + ".krak"); + //Now add all functions to scope + std::cout << "Trying to re-import from " << toImport << std::endl; + for (auto i = outsideTranslationUnit->getDataRef()->scope.begin(); i != outsideTranslationUnit->getDataRef()->scope.end(); i++) { + std::cout << "Looking through " << i->first << std::endl; + for (auto j : i->second) + if (j->getDataRef()->type == function || j->getDataRef()->type == identifier) + std::cout << "Copying " << i->first << std::endl, ast->getDataRef()->scope[i->first].push_back(j); + else + std::cout << "Not Copying " << i->first << std::endl; + } + } + } +} + +//The fourth pass finishes up by doing all function bodies +void ASTTransformation::fourthPass(NodeTree* ast, NodeTree* parseTree) { + 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(); + + //Go through and finish both regular functions and class methods + //Note that this pass can instantiate class AND function templates + for (NodeTree* i : children) { + if (i->getDataRef()->getName() == "type_def") { + if (i->getChildren()[0]->getData().getName() == "template_dec") // It's a template + continue; //We've already set up the class templates + std::vector*> typedefChildren = i->getChildren(); + std::string name = concatSymbolTree(typedefChildren[0]); + NodeTree* typeDef = ast->getDataRef()->scope[name][0]; //No overloaded types + + //It's an alias + if (typedefChildren[1]->getData().getName() == "type") + continue; //We're done with aliases too + + //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 + } + } + } 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()); + } + } +} + +//This function finds the right AST definition in a scope given its parseTree +NodeTree* ASTTransformation::seachScopeForFunctionDef(NodeTree* scope, NodeTree* parseTree, std::map templateTypeReplacements) { + std::string functionName = concatSymbolTree(parseTree->getChildren()[1]); + std::vector types; + std::vector*> children = parseTree->getChildren(); + //Skipping the initial return type and identifier as well as the final code block + 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); + std::cout << "Type made: " << type.toString() << std::endl; + types.push_back(type); + } + std::cout << "About to seach scope about " << concatSymbolTree(children[1]) << std::endl; + NodeTree* result = scopeLookup(scope, functionName, types); + std::cout << "Done searching scope about " << concatSymbolTree(children[1]) << std::endl; + return result; +} + +//This function does the function bodies given its start (the prototype) +//It is used in the fourth pass to finish things up +//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)); +} + + NodeTree* ASTTransformation::transform(NodeTree* from) { //Set up top scope return transform(from, NULL, std::vector(), std::map()); @@ -44,11 +274,25 @@ NodeTree* ASTTransformation::transform(NodeTree* from, NodeTree NodeTree* newNode = NULL; std::vector*> children = from->getChildren(); std::set skipChildren; - +/* if (name == "translation_unit") { newNode = new NodeTree(name, ASTData(translation_unit)); scope = newNode; topScope = newNode; //Top scope is maintained for templates, which need to add themselves to the top scope from where ever they are instantiated + + //One of Kraken's features is that definition order does not matter. This is done by doing a first pass across the translation unit + //to nominally add all the type_def's and function def's to the top scope before they're actually processed + for (NodeTree* i : children) { + if (i->getDataRef()->getName() == "type_def") { + std::string name; + if (i->getChildren()[0]->getData().getName() == "template_dec") // It's a template + name = concatSymbolTree(i->getChildren()[1]); + else //It's not + name = concatSymbolTree(i->getChildren()[0]); + scope->getDataRef()->scope[name].push_back(new NodeTree("type_def", ASTData(type_def, Symbol(name, true, name)))); //Just a placeholder + } + } + std::cout << "The scope here at first intantiation is " << scope->getDataRef()->toString() << std::endl; } else if (name == "interpreter_directive") { newNode = new NodeTree(name, ASTData(interpreter_directive)); } else if (name == "import" && !current.isTerminal()) { @@ -62,7 +306,7 @@ NodeTree* ASTTransformation::transform(NodeTree* from, NodeTree for (auto j : i->second) scope->getDataRef()->scope[i->first].push_back(j); return newNode; // Don't need children of import - } else if (name == "identifier") { + } else */if (name == "identifier") { //Make sure we get the entire name std::string lookupName = concatSymbolTree(from); std::cout << "Looking up: " << lookupName << std::endl; @@ -74,9 +318,14 @@ NodeTree* ASTTransformation::transform(NodeTree* from, NodeTree } else if (name == "type_def") { //If it is an alisis of a type std::string typeAlias; + std::cout << "The scope here at type_def is " << scope->getDataRef()->toString() << std::endl; if (children[1]->getData().getName() == "type") { typeAlias = concatSymbolTree(children[0]); - newNode = new NodeTree(name, ASTData(type_def, Symbol(typeAlias, true, typeAlias), typeFromTypeNode(children[1], scope, templateTypeReplacements))); + 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); skipChildren.insert(0); //Don't want any children, it's unnecessary for ailising skipChildren.insert(1); } else { //Is a struct or class @@ -84,20 +333,27 @@ NodeTree* ASTTransformation::transform(NodeTree* from, NodeTree if (children[0]->getData().getName() == "template_dec") { typeAlias = concatSymbolTree(children[1]); std::cout << "Template Type!"<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 + // std::cout << "typeAlias is " << typeAlias << " and newNode is " << newNode << std::endl; - newNode = new NodeTree(name, ASTData(type_def, Symbol(typeAlias, true, typeAlias))); + //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); } else { typeAlias = concatSymbolTree(children[0]); - newNode = new NodeTree(name, ASTData(type_def, Symbol(typeAlias, true, typeAlias))); + + 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 } newNode->getDataRef()->valueType = objectType; //Type is self-referential since this is the definition } - scope->getDataRef()->scope[typeAlias].push_back(newNode); + //scope->getDataRef()->scope[typeAlias].push_back(newNode); newNode->getDataRef()->scope["~enclosing_scope"].push_back(scope); //Templates are done here. No need to go farther @@ -475,6 +731,8 @@ NodeTree* ASTTransformation::scopeLookup(NodeTree* scope, std: if ((*i)->getDataRef()->type == type_def) return *i; + std::cout << lookup << " has " << elementIterator->second.size() << " possible solutions" << std::endl; + std::vector*> children = (*i)->getChildren(); //We subtract one from the children to get the type size only if there is at least one child AND // the last node is actually a body node, as it may not have been generated yet if we're in the body @@ -490,6 +748,10 @@ NodeTree* ASTTransformation::scopeLookup(NodeTree* scope, std: for (int j = 0; j < types.size(); j++) { Type* tmpType = children[j]->getDataRef()->valueType; //Don't worry if types don't match if it's a template type + // std::cout << "Checking for segfaults, we have" << std::endl; + // std::cout << types[j].toString() << std::endl; + // std::cout << tmpType->toString() << std::endl; + // std::cout << "Done!" << std::endl; if (types[j] != *tmpType && tmpType->baseType != template_type_type) { typesMatch = false; std::cout << "Types do not match between two " << lookup << " " << types[j].toString(); diff --git a/src/Importer.cpp b/src/Importer.cpp index 5539516..06f9de4 100644 --- a/src/Importer.cpp +++ b/src/Importer.cpp @@ -4,7 +4,9 @@ Importer::Importer(Parser* parserIn, std::vector includePaths) { //constructor parser = parserIn; this->includePaths = includePaths; + ASTTransformer = new ASTTransformation(this); + removeSymbols.push_back(Symbol("$NULL$", true)); removeSymbols.push_back(Symbol("WS", false)); removeSymbols.push_back(Symbol("\\(", true)); removeSymbols.push_back(Symbol("\\)", true)); @@ -37,10 +39,16 @@ Importer::Importer(Parser* parserIn, std::vector includePaths) { Importer::~Importer() { //destructor + delete ASTTransformer; } -NodeTree* Importer::import(std::string fileName) { +void Importer::registerAST(std::string name, NodeTree* ast, NodeTree* syntaxTree) { + imported[name] = ast; + importedTrips.push_back({name, ast, syntaxTree}); + std::cout << "REGISTERD " << name << std::endl; +} +NodeTree* Importer::getUnit(std::string fileName) { std::cout << "\n\nImporting " << fileName << " "; //Check to see if we've already done it if (imported.find(fileName) != imported.end()) { @@ -49,8 +57,65 @@ NodeTree* Importer::import(std::string fileName) { } std::cout << "Not yet imported" << std::endl; + return NULL; +} + +NodeTree* Importer::importFirstPass(std::string fileName) { + NodeTree* ast = getUnit(fileName); + if (ast == NULL) { + NodeTree* parseTree = parseAndTrim(fileName); + + //Call with ourself to allow the transformation to call us to import files that it needs + ast = ASTTransformer->firstPass(fileName, parseTree); //This firstPass will register itself + } + return ast; +} + +void Importer::import(std::string fileName) { + + //Start the ball rolling by importing and running the first pass on the first file. + //This will import, first pass and register all the other files too. + + std::cout << "\n\n =====FIRST PASS===== \n\n" << std::endl; + importFirstPass(fileName); //First pass defines all objects + + std::cout << "\n\n =====SECOND PASS===== \n\n" << std::endl; + for (importTriplet i : importedTrips) //Second pass defines data inside objects, outside declaration statements, + std::cout << "\n\nSecond pass for: " << i.name << std::endl, ASTTransformer->secondPass(i.ast, i.syntaxTree); //function prototypes, and identifiers (as we now have all type defs) + + std::cout << "\n\n =====THIRD PASS===== \n\n" << std::endl; + for (importTriplet i : importedTrips) //Third pass redoes all imports to import the new function prototypes and identifiers + std::cout << "\n\nThird pass for: " << i.name << std::endl, ASTTransformer->thirdPass(i.ast); + + std::cout << "\n\n =====FOURTH PASS===== \n\n" << std::endl; + for (importTriplet i : importedTrips) //Fourth pass finishes up by doing all function bodies + std::cout << "\n\nFourth pass for: " << i.name << std::endl, ASTTransformer->fourthPass(i.ast, i.syntaxTree); //With that, we're done + + //Note that class template instantiation can happen in the second or fourth passes and that function template instantion + //can happen in the fourth pass. + + std::ofstream outFileAST; + for (importTriplet i : importedTrips) { + std::string outputName = i.name + "out"; + outFileAST.open((outputName + ".AST.dot").c_str()); + if (!outFileAST.is_open()) { + std::cout << "Problem opening second output file " << outputName + ".AST.dot" << "\n"; + return; + } + if (i.ast) { + outFileAST << i.ast->DOTGraphString() << std::endl; + } else { + std::cout << "Tree returned from ASTTransformation is NULL!" << std::endl; + } + outFileAST.close(); + } +} + +NodeTree* Importer::parseAndTrim(std::string fileName) { + std::ifstream programInFile; - std::ofstream outFile, outFileTransformed, outFileAST; + std::ofstream outFile, outFileTransformed; + std::string outputName = fileName + "out"; @@ -78,12 +143,6 @@ NodeTree* Importer::import(std::string fileName) { return NULL; } - outFileAST.open((outputName + ".AST.dot").c_str()); - if (!outFileAST.is_open()) { - std::cout << "Probelm opening second output file " << outputName + ".AST.dot" << "\n"; - return NULL; - } - std::string programInputFileString, line; while(programInFile.good()) { getline(programInFile, line); @@ -119,21 +178,7 @@ NodeTree* Importer::import(std::string fileName) { } outFileTransformed.close(); - //Call with ourself to allow the transformation to call us to import files that it needs - NodeTree* AST = ASTTransformation(this).transform(parseTree); - - if (AST) { - outFileAST << AST->DOTGraphString() << std::endl; - } else { - std::cout << "Tree returned from ASTTransformation is NULL!" << std::endl; - } - outFileAST.close(); - - imported[fileName] = AST; - - std::cout << "Done importing " << fileName << "\n\n" << std::endl; - - return AST; + return parseTree; } std::map*> Importer::getASTMap() { diff --git a/tests/functionOrderingTest.expected_results b/tests/functionOrderingTest.expected_results new file mode 100644 index 0000000..48082f7 --- /dev/null +++ b/tests/functionOrderingTest.expected_results @@ -0,0 +1 @@ +12 diff --git a/tests/functionOrderingTest.krak b/tests/functionOrderingTest.krak new file mode 100644 index 0000000..8075128 --- /dev/null +++ b/tests/functionOrderingTest.krak @@ -0,0 +1,17 @@ +import io; + +int ret1() { + return ret2() / 2; +} + + +int main() { + print(ret1()); + print(ret2()); + print("\n"); + return 0; +} + +int ret2() { + return 2; +} diff --git a/tests/moreObjectTemplateTest.expected_results b/tests/moreObjectTemplateTest.expected_results new file mode 100644 index 0000000..3dddccb --- /dev/null +++ b/tests/moreObjectTemplateTest.expected_results @@ -0,0 +1 @@ +345Hello!Hello!Hello! \ No newline at end of file diff --git a/tests/moreObjectTemplateTest.krak b/tests/moreObjectTemplateTest.krak new file mode 100644 index 0000000..f2cd5e6 --- /dev/null +++ b/tests/moreObjectTemplateTest.krak @@ -0,0 +1,41 @@ +import io; +import trivial_container; + +typedef RegularObject { + MyInt num; + trivialContainer innerContainer; + void set(char* message, int number) { + innerContainer.data = message; + num = number; + } + char* get() { + return innerContainer.data; + } + void print() { + print(num); + innerContainer.print(); + } +}; + +typedef MyIntContainer trivialContainer; +typedef MyInt int; +MyInt c; +MyIntContainer roundabout; +RegularObject outsideDec; + +void print(trivialContainer toPrint) { + print(toPrint.data); +} + +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 diff --git a/tests/simpleObjectTemplateTest.expected_results b/tests/simpleObjectTemplateTest.expected_results new file mode 100644 index 0000000..40928fd --- /dev/null +++ b/tests/simpleObjectTemplateTest.expected_results @@ -0,0 +1,4 @@ +a: 5 +b: 7 +a: 9 +b: Hello Templates! diff --git a/tests/simpleObjectTemplateTest.krak b/tests/simpleObjectTemplateTest.krak new file mode 100644 index 0000000..9f16211 --- /dev/null +++ b/tests/simpleObjectTemplateTest.krak @@ -0,0 +1,30 @@ +import io; + + +typedef template TemplateTest { + int a; + T b; + void print() { + print("a: "); + print(a); + print("\n"); + print("b: "); + print(b); + print("\n"); + } +}; + +int main() { + + TemplateTest test; + TemplateTest test2; + test.a = 5; + test.b = 7; + test2.a = 9; + test2.b = "Hello Templates!"; + + test.print(); + test2.print(); + + return 0; +}