From 1997ba49d2f63830b01d91e0cbd2bddb3cf5fc7e Mon Sep 17 00:00:00 2001 From: Nathan Braswell Date: Sun, 27 Apr 2014 02:48:57 -0400 Subject: [PATCH 01/37] Fixed operator overloading so that both method and non-method operator overloads work. --- include/ASTTransformation.h | 2 +- src/ASTTransformation.cpp | 86 ++++++++++++++++++++----------------- 2 files changed, 47 insertions(+), 41 deletions(-) diff --git a/include/ASTTransformation.h b/include/ASTTransformation.h index fccf125..36e4819 100644 --- a/include/ASTTransformation.h +++ b/include/ASTTransformation.h @@ -20,7 +20,7 @@ class ASTTransformation: public NodeTransformation { std::vector*> transformChildren(std::vector*> children, std::set skipChildren, NodeTree* scope, std::vector types); std::vector mapNodesToTypes(std::vector*> nodes); std::string concatSymbolTree(NodeTree* root); - NodeTree* scopeLookup(NodeTree* scope, std::string lookup, std::vector*> nodes); + NodeTree* doFunction(NodeTree* scope, std::string lookup, std::vector*> nodes); NodeTree* scopeLookup(NodeTree* scope, std::string lookup, std::vector types = std::vector()); Type* typeFromString(std::string type, NodeTree* scope); private: diff --git a/src/ASTTransformation.cpp b/src/ASTTransformation.cpp index c91572a..7ac6686 100644 --- a/src/ASTTransformation.cpp +++ b/src/ASTTransformation.cpp @@ -122,14 +122,15 @@ NodeTree* ASTTransformation::transform(NodeTree* from, NodeTree skipChildren.insert(1); std::vector*> transformedChildren = transformChildren(children, skipChildren, scope, types); std::string functionCallString = concatSymbolTree(children[1]); - NodeTree* function = scopeLookup(scope, functionCallString, transformedChildren); + NodeTree* function = doFunction(scope, functionCallString, transformedChildren); if (function == NULL) { std::cout << "scope lookup error! Could not find " << functionCallString << " in boolean stuff " << std::endl; throw "LOOKUP ERROR: " + functionCallString; } - newNode = new NodeTree(functionCallString, ASTData(function_call, function->getDataRef()->valueType)); - newNode->addChild(function); // First child of function call is a link to the function - newNode->addChildren(transformedChildren); + newNode = function; + // newNode = new NodeTree(functionCallString, ASTData(function_call, function->getDataRef()->valueType)); + // newNode->addChild(function); // First child of function call is a link to the function + // newNode->addChildren(transformedChildren); } else { //std::cout << children.size() << std::endl; if (children.size() == 0) @@ -150,20 +151,21 @@ NodeTree* ASTTransformation::transform(NodeTree* from, NodeTree std::string functionCallName = concatSymbolTree(children[1]); //std::cout << "scope lookup from expression or similar" << std::endl; std::vector*> transformedChildren; transformedChildren.push_back(lhs); transformedChildren.push_back(rhs); - NodeTree* function = scopeLookup(scope, functionCallName, transformedChildren); + NodeTree* function = doFunction(scope, functionCallName, transformedChildren); if (function == NULL) { std::cout << "scope lookup error! Could not find " << functionCallName << " in expression " << std::endl; throw "LOOKUP ERROR: " + functionCallName; } - newNode = new NodeTree(functionCallName, ASTData(function_call, Symbol(functionCallName, true))); - newNode->addChild(function); // First child of function call is a link to the function definition - newNode->addChild(lhs); - newNode->addChild(rhs); + newNode = function; + // newNode = new NodeTree(functionCallName, ASTData(function_call, Symbol(functionCallName, true))); + // newNode->addChild(function); // First child of function call is a link to the function definition + // newNode->addChild(lhs); + // newNode->addChild(rhs); - if (name == "access_operation") - std::cout << "Access Operation: " << lhs->getDataRef()->symbol.getName() << " : " << rhs->getDataRef()->symbol.getName() << std::endl; - std::cout << functionCallName << " - " << function->getName() << " has value type " << function->getDataRef()->valueType << " and rhs " << rhs->getDataRef()->valueType << std::endl; - //Set the value of this function call + // if (name == "access_operation") + // std::cout << "Access Operation: " << lhs->getDataRef()->symbol.getName() << " : " << rhs->getDataRef()->symbol.getName() << std::endl; + // std::cout << functionCallName << " - " << function->getName() << " has value type " << function->getDataRef()->valueType << " and rhs " << rhs->getDataRef()->valueType << std::endl; + // //Set the value of this function call if (function->getDataRef()->valueType) newNode->getDataRef()->valueType = function->getDataRef()->valueType; else if (rhs->getDataRef()->valueType) @@ -189,18 +191,19 @@ NodeTree* ASTTransformation::transform(NodeTree* from, NodeTree //std::cout << "scope lookup from factor" << std::endl; std::vector*> transformedChildren; transformedChildren.push_back(param); - NodeTree* function = scopeLookup(scope, funcName, transformedChildren); + NodeTree* function = doFunction(scope, funcName, transformedChildren); if (function == NULL) { std::cout << "scope lookup error! Could not find " << funcName << " in factor " << std::endl; throw "LOOKUP ERROR: " + funcName; } - newNode = new NodeTree(funcName, ASTData(function_call, Symbol(funcName, true))); - newNode->addChild(function); - newNode->addChild(param); - if (function->getDataRef()->valueType) - newNode->getDataRef()->valueType = function->getDataRef()->valueType; - else - newNode->getDataRef()->valueType = param->getDataRef()->valueType; + newNode = function; + // newNode = new NodeTree(funcName, ASTData(function_call, Symbol(funcName, true))); + // newNode->addChild(function); + // newNode->addChild(param); + // if (function->getDataRef()->valueType) + // newNode->getDataRef()->valueType = function->getDataRef()->valueType; + // else + // newNode->getDataRef()->valueType = param->getDataRef()->valueType; return newNode; } else { @@ -228,17 +231,13 @@ NodeTree* ASTTransformation::transform(NodeTree* from, NodeTree NodeTree* rhs = transform(children[2], scope, types); std::vector*> transformedChildren; transformedChildren.push_back(lhs); transformedChildren.push_back(rhs); std::string functionName = assignFuncName.substr(0,1); - NodeTree* childCall = new NodeTree(functionName, ASTData(function_call, Symbol(functionName, true))); - NodeTree* functionDef = scopeLookup(scope, functionName, transformedChildren); - if (functionDef == NULL) { + NodeTree* operatorCall = doFunction(scope, functionName, transformedChildren); + if (operatorCall == NULL) { std::cout << "scope lookup error! Could not find " << functionName << " in assignment_statement " << std::endl; throw "LOOKUP ERROR: " + functionName; } - childCall->addChild(functionDef); //First child of function call is definition of the function - childCall->addChild(lhs); - childCall->addChild(rhs); newNode->addChild(lhs); - newNode->addChild(childCall); + newNode->addChild(operatorCall); } return newNode; } else if (name == "declaration_statement") { @@ -363,9 +362,10 @@ std::string ASTTransformation::concatSymbolTree(NodeTree* root) { } //Overloaded with the actual children to allow us to handle operator methods -NodeTree* ASTTransformation::scopeLookup(NodeTree* scope, std::string lookup, std::vector*> nodes) { +NodeTree* ASTTransformation::doFunction(NodeTree* scope, std::string lookup, std::vector*> nodes) { // auto LLElementIterator = languageLevelScope.find(lookup); + NodeTree* newNode; if (LLElementIterator != languageLevelScope.end()) { std::cout << "Checking for early method level operator overload" << std::endl; std::string lookupOp = "operator" + lookup; @@ -379,23 +379,29 @@ NodeTree* ASTTransformation::scopeLookup(NodeTree* scope, std: //Ok, so we construct std::cout << "Early method level operator was found" << std::endl; //return operatorMethod; - newNode = new NodeTree(functionCallName, ASTData(function_call, Symbol(functionCallName, true))); - newNode->addChild(function); // First child of function call is a link to the function definition - newNode->addChild(lhs); - newNode->addChild(rhs); + NodeTree* newNode = new NodeTree(lookupOp, ASTData(function_call, Symbol(lookupOp, true))); + NodeTree* dotFunctionCall = new NodeTree(".", ASTData(function_call, Symbol(".", true))); + dotFunctionCall->addChild(languageLevelScope["."][0]); //function definition + dotFunctionCall->addChild(nodes[0]); // The object whose method we're calling + dotFunctionCall->addChild(operatorMethod); //The method we're calling + newNode->addChild(dotFunctionCall); // First child of function call is a link to the function definition + newNode->addChildren(slice(nodes, 1, -1)); //The rest of the parameters to the operator //Set the value of this function call - if (function->getDataRef()->valueType) - newNode->getDataRef()->valueType = function->getDataRef()->valueType; - else if (rhs->getDataRef()->valueType) - newNode->getDataRef()->valueType = rhs->getDataRef()->valueType; - else - newNode->getDataRef()->valueType = NULL; + newNode->getDataRef()->valueType = operatorMethod->getDataRef()->valueType; + return newNode; } std::cout << "Early method level operator was NOT found" << std::endl; } - return scopeLookup(scope, lookup, mapNodesToTypes(nodes)); + + newNode = new NodeTree(lookup, ASTData(function_call, Symbol(lookup, true))); + NodeTree* function = scopeLookup(scope, lookup, mapNodesToTypes(nodes)); + newNode->addChild(function); + newNode->addChildren(nodes); + newNode->getDataRef()->valueType = function->getDataRef()->valueType; + + return newNode; } NodeTree* ASTTransformation::scopeLookup(NodeTree* scope, std::string lookup, std::vector types) { From 6a75832b598d9c96723fa855528c469ce586aa9b Mon Sep 17 00:00:00 2001 From: Nathan Braswell Date: Thu, 1 May 2014 01:18:01 -0400 Subject: [PATCH 02/37] Added trivial standard library and search paths. --- CMakeLists.txt | 2 ++ include/Importer.h | 3 ++- main.cpp | 12 ++++++++++-- src/Importer.cpp | 9 +++++++-- stdlib/io.krak | 30 ++++++++++++++++++++++++++++++ stdlib/math.krak | 9 +++++++++ 6 files changed, 60 insertions(+), 5 deletions(-) create mode 100644 stdlib/io.krak create mode 100644 stdlib/math.krak diff --git a/CMakeLists.txt b/CMakeLists.txt index db3eb07..12ef013 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -12,3 +12,5 @@ include_directories( ${MY_INCLUDES} ) add_executable(kraken ${MY_SOURCES}) +file(COPY stdlib DESTINATION .) + diff --git a/include/Importer.h b/include/Importer.h index c0b4f55..dc79e7a 100644 --- a/include/Importer.h +++ b/include/Importer.h @@ -16,11 +16,12 @@ class Importer { public: - Importer(Parser* parserIn); + Importer(Parser* parserIn, std::vector includePaths); ~Importer(); NodeTree* import(std::string fileName); std::map*> getASTMap(); private: + std::vector includePaths; Parser* parser; std::vector removeSymbols; std::vector collapseSymbols; diff --git a/main.cpp b/main.cpp index 90028d0..06d6e61 100644 --- a/main.cpp +++ b/main.cpp @@ -18,6 +18,9 @@ #include "util.h" int main(int argc, char* argv[]) { + std::vector includePaths; + includePaths.push_back(""); //Local + if (argc == 2 && std::string(argv[1]) == "--test") { StringReader::test(); RegEx::test(); @@ -25,7 +28,9 @@ int main(int argc, char* argv[]) { //std::cout << strSlice("123", 0, -1) << std::endl; return 0; } - + std::string krakenDir = argv[0]; + krakenDir = strSlice(krakenDir, 0, -(std::string("kraken").length()+1)); + includePaths.push_back(krakenDir + "stdlib/"); std::string programName = argv[1]; std::string grammerFileString = argv[2]; std::string outputName = argv[3]; @@ -134,9 +139,12 @@ int main(int argc, char* argv[]) { //outFile << parser.grammerToDOT() << std::endl; std::cout << "\nParsing" << std::endl; - Importer importer(&parser); + Importer importer(&parser, includePaths); /*NodeTree* AST =*/ + for (auto i : includePaths) + std::cout << i << std::endl; + importer.import(programName); std::map*> ASTs = importer.getASTMap(); diff --git a/src/Importer.cpp b/src/Importer.cpp index 88c367f..edfcc47 100644 --- a/src/Importer.cpp +++ b/src/Importer.cpp @@ -1,8 +1,9 @@ #include "Importer.h" -Importer::Importer(Parser* parserIn) { +Importer::Importer(Parser* parserIn, std::vector includePaths) { //constructor parser = parserIn; + this->includePaths = includePaths; removeSymbols.push_back(Symbol("WS", false)); removeSymbols.push_back(Symbol("\\(", true)); @@ -47,7 +48,11 @@ NodeTree* Importer::import(std::string fileName) { std::string outputName = fileName + "out"; - programInFile.open(fileName); + for (auto i : includePaths) { + programInFile.open(i+fileName); + if (programInFile.is_open()) + break; + } if (!programInFile.is_open()) { std::cout << "Problem opening programInFile " << fileName << "\n"; return NULL; diff --git a/stdlib/io.krak b/stdlib/io.krak new file mode 100644 index 0000000..44c72a2 --- /dev/null +++ b/stdlib/io.krak @@ -0,0 +1,30 @@ +__if_comp__ __C__ __simple_passthrough__ """ + #include +""" + +void print(char* toPrint) { + __if_comp__ __C__ { + __simple_passthrough__ """ + printf(toPrint); + """ + } + return; +} + +void print(int toPrint) { + __if_comp__ __C__ { + __simple_passthrough__ """ + printf("%d", toPrint); + """ + } + return; +} + +void print(float toPrint) { + __if_comp__ __C__ { + __simple_passthrough__ """ + printf("%f", toPrint); + """ + } + return; +} \ No newline at end of file diff --git a/stdlib/math.krak b/stdlib/math.krak new file mode 100644 index 0000000..5b245ab --- /dev/null +++ b/stdlib/math.krak @@ -0,0 +1,9 @@ + +int NotPi = 3; +float Pi = 3.141592654; + +int fibanacci(int num) { + if (num < 2) + return 1; + return fibanacci(num-1) + fibanacci(num-2); +} \ No newline at end of file From 9a4507a0f59a1d21dab440cb07250b87a3bca192 Mon Sep 17 00:00:00 2001 From: Nathan Braswell Date: Sat, 3 May 2014 20:46:10 -0400 Subject: [PATCH 03/37] Added passthroughs and small fix for malloc/free --- src/ASTTransformation.cpp | 4 +++- src/Importer.cpp | 2 ++ stdlib/mem.krak | 23 +++++++++++++++++++++++ 3 files changed, 28 insertions(+), 1 deletion(-) create mode 100644 stdlib/mem.krak diff --git a/src/ASTTransformation.cpp b/src/ASTTransformation.cpp index 7ac6686..7f286c6 100644 --- a/src/ASTTransformation.cpp +++ b/src/ASTTransformation.cpp @@ -305,10 +305,12 @@ NodeTree* ASTTransformation::transform(NodeTree* from, NodeTree newNode = new NodeTree(name, ASTData(value, Symbol(concatSymbolTree(from), true), new Type(floating))); } else if (name == "double") { newNode = new NodeTree(name, ASTData(value, Symbol(concatSymbolTree(from), true), new Type(double_percision))); - } else if (name == "char") { + } else if (name == "char") { //Is this correct? This might be a useless old thing newNode = new NodeTree(name, ASTData(value, Symbol(concatSymbolTree(children[0]), true), new Type(character, 1))); //Indirection of 1 for array } else if (name == "string" || name == "triple_quoted_string") { 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 { return new NodeTree(); } diff --git a/src/Importer.cpp b/src/Importer.cpp index edfcc47..eaf8838 100644 --- a/src/Importer.cpp +++ b/src/Importer.cpp @@ -52,6 +52,8 @@ NodeTree* Importer::import(std::string fileName) { programInFile.open(i+fileName); if (programInFile.is_open()) break; + else + std::cout << i+fileName << " is no good" << std::endl; } if (!programInFile.is_open()) { std::cout << "Problem opening programInFile " << fileName << "\n"; diff --git a/stdlib/mem.krak b/stdlib/mem.krak new file mode 100644 index 0000000..e4dafa2 --- /dev/null +++ b/stdlib/mem.krak @@ -0,0 +1,23 @@ +__if_comp__ __C__ __simple_passthrough__ """ + #include +""" + +char* nullPtr = 0; + +char* malloc(int size) { + char* memPtr = nullPtr; + __if_comp__ __C__ { + __simple_passthrough__ """ + memPtr = malloc(size); + """ + } + return memPtr; +} + +void free(char* memPtr) { + __if_comp__ __C__ { + __simple_passthrough__ """ + free(memPtr); + """ + } +} From 209985310eab66753955ab3145918512550c84c9 Mon Sep 17 00:00:00 2001 From: Nathan Braswell Date: Mon, 5 May 2014 13:52:12 -0400 Subject: [PATCH 04/37] Fixed type propagation for dereference and address-of, needs work for all the other operators also. Starting ground work for array notation --- include/Type.h | 1 + krakenGrammer.kgm | 2 +- src/ASTTransformation.cpp | 22 +++++++++++++++++++--- src/Type.cpp | 4 ++++ 4 files changed, 25 insertions(+), 4 deletions(-) diff --git a/include/Type.h b/include/Type.h index 882e143..62bd270 100644 --- a/include/Type.h +++ b/include/Type.h @@ -27,6 +27,7 @@ class Type { ~Type(); bool const operator==(const Type &other)const; bool const operator!=(const Type &other)const; + Type* clone(); std::string toString(); ValueType baseType; NodeTree* typeDefinition; diff --git a/krakenGrammer.kgm b/krakenGrammer.kgm index 9438a5a..352eb4d 100644 --- a/krakenGrammer.kgm +++ b/krakenGrammer.kgm @@ -68,7 +68,7 @@ comparator = "==" | "<=" | ">=" | "!=" | "<" | ">" ; expression = expression WS "<<" WS term | expression WS ">>" WS shiftand | shiftand ; shiftand = shiftand WS "-" WS term | shiftand WS "\+" WS term | term ; term = term WS forward_slash WS factor | term WS "\*" WS factor | term WS "%" WS factor | factor ; -factor = "\+\+" WS unarad | unarad WS "\+\+" | "--" WS unarad | unarad WS "--" | "\+" WS unarad | "-" WS unarad | "!" WS unarad | "~" WS unarad | "\(" WS type WS "\)" WS unarad | "\*" WS unarad | "&" WS unarad | unarad ; +factor = "\+\+" WS unarad | unarad WS "\+\+" | "--" WS unarad | unarad WS "--" | "\+" WS unarad | "-" WS unarad | "!" WS unarad | "~" WS unarad | "\(" WS type WS "\)" WS unarad | "\*" WS unarad | "&" WS unarad | unarad WS "[" WS expression WS "]" | unarad ; unarad = number | identifier | function_call | bool | string | character | "\(" WS boolean_expression WS "\)" | access_operation ; number = integer | float | double ; access_operation = unarad "." identifier | unarad "->" identifier ; diff --git a/src/ASTTransformation.cpp b/src/ASTTransformation.cpp index 7f286c6..900c66f 100644 --- a/src/ASTTransformation.cpp +++ b/src/ASTTransformation.cpp @@ -346,8 +346,10 @@ std::vector*> ASTTransformation::transformChildren(std::vector std::vector ASTTransformation::mapNodesToTypes(std::vector*> nodes) { std::vector types; - for (auto i : nodes) + for (auto i : nodes) { + std::cout << i->getDataRef()->toString() << std::endl; types.push_back(*(i->getDataRef()->valueType)); + } return types; } @@ -401,7 +403,21 @@ NodeTree* ASTTransformation::doFunction(NodeTree* scope, std:: NodeTree* function = scopeLookup(scope, lookup, mapNodesToTypes(nodes)); newNode->addChild(function); newNode->addChildren(nodes); - newNode->getDataRef()->valueType = function->getDataRef()->valueType; + + //Specially handle dereference and address of to assign the correct type + //We need some significant other type corrections here, maybe to the point of being their own function. (int + float, etc.) + for (auto i : nodes) + std::cout << i->getDataRef()->toString() << " "; + std::cout< oldTypes = mapNodesToTypes(nodes); + if (lookup == "*" || lookup == "&") { + Type* newType = oldTypes[0].clone(); + lookup == "*" ? newType->indirection-- : newType->indirection++; + newNode->getDataRef()->valueType = newType, std::cout << "Operator " + lookup << std::endl; + } else { + newNode->getDataRef()->valueType = function->getDataRef()->valueType, std::cout << "Some other ||" << lookup << "||" << std::endl; + } return newNode; } @@ -436,7 +452,7 @@ NodeTree* ASTTransformation::scopeLookup(NodeTree* scope, std: for (int j = 0; j < types.size(); j++) { if (types[j] != *(children[j]->getDataRef()->valueType)) { typesMatch = false; - std::cout << "Types do not match between two " << lookup << std::endl; + std::cout << "Types do not match between two " << lookup << " " << types[j].toString() << " vs " << children[j]->getDataRef()->valueType->toString() << std::endl; break; } } diff --git a/src/Type.cpp b/src/Type.cpp index 2e40328..3f12bbf 100644 --- a/src/Type.cpp +++ b/src/Type.cpp @@ -83,3 +83,7 @@ std::string Type::toString() { typeString += "*"; return typeString; } + +Type* Type::clone() { + return new Type(baseType, typeDefinition, indirection); +} From c4dea26cca91421f78eb5218d56c9bc0d9f5fe96 Mon Sep 17 00:00:00 2001 From: Nathan Braswell Date: Tue, 6 May 2014 13:54:53 -0400 Subject: [PATCH 05/37] Finished simple array notation, fixed address of operator. --- src/ASTTransformation.cpp | 31 ++++++++++++++++++------------- src/CGenerator.cpp | 6 ++++-- 2 files changed, 22 insertions(+), 15 deletions(-) diff --git a/src/ASTTransformation.cpp b/src/ASTTransformation.cpp index 900c66f..97b7c15 100644 --- a/src/ASTTransformation.cpp +++ b/src/ASTTransformation.cpp @@ -23,6 +23,7 @@ ASTTransformation::ASTTransformation(Importer *importerIn) { languageLevelScope["-="].push_back(new NodeTree("function", ASTData(function, Symbol("-=", true), NULL))); languageLevelScope["."].push_back(new NodeTree("function", ASTData(function, Symbol(".", true), NULL))); languageLevelScope["->"].push_back(new NodeTree("function", ASTData(function, Symbol("->", true), NULL))); + languageLevelScope["[]"].push_back(new NodeTree("function", ASTData(function, Symbol("[]", true), NULL))); } ASTTransformation::~ASTTransformation() { @@ -181,8 +182,9 @@ NodeTree* ASTTransformation::transform(NodeTree* from, NodeTree } 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 //NO SUPPORT FOR CASTING YET + std::string funcName; if (children.size() == 2) { - std::string funcName = concatSymbolTree(children[0]); + funcName = concatSymbolTree(children[0]); NodeTree* param; if (funcName == "*" || funcName == "&" || funcName == "++" || funcName == "--" || funcName == "-" || funcName == "!" || funcName == "~") param = transform(children[1], scope, types); @@ -196,16 +198,19 @@ NodeTree* ASTTransformation::transform(NodeTree* from, NodeTree std::cout << "scope lookup error! Could not find " << funcName << " in factor " << std::endl; throw "LOOKUP ERROR: " + funcName; } - newNode = function; - // newNode = new NodeTree(funcName, ASTData(function_call, Symbol(funcName, true))); - // newNode->addChild(function); - // newNode->addChild(param); - // if (function->getDataRef()->valueType) - // newNode->getDataRef()->valueType = function->getDataRef()->valueType; - // else - // newNode->getDataRef()->valueType = param->getDataRef()->valueType; - return newNode; + return function; + } else if (children.size() >= 4) { //Array brackets [] + funcName = "[]"; + std::vector*> transformedChildren; + transformedChildren.push_back(transform(children[0], scope, types)); + transformedChildren.push_back(transform(children[2], scope, types)); + NodeTree* function = doFunction(scope, funcName, transformedChildren); + if (function == NULL) { + std::cout << "scope lookup error! Could not find " << funcName << " in factor " << std::endl; + throw "LOOKUP ERROR: " + funcName; + } + return function; } else { return transform(children[0], scope, types); //Just a promoted child, so do it instead } @@ -411,10 +416,10 @@ NodeTree* ASTTransformation::doFunction(NodeTree* scope, std:: std::cout< oldTypes = mapNodesToTypes(nodes); - if (lookup == "*" || lookup == "&") { + if (lookup == "*" || lookup == "&" || lookup == "[]") { Type* newType = oldTypes[0].clone(); - lookup == "*" ? newType->indirection-- : newType->indirection++; - newNode->getDataRef()->valueType = newType, std::cout << "Operator " + lookup << std::endl; + lookup == "*" || lookup == "[]" ? newType->indirection-- : newType->indirection++; + newNode->getDataRef()->valueType = newType, std::cout << "Operator " + lookup << " is altering indirection "<< std::endl; } else { newNode->getDataRef()->valueType = function->getDataRef()->valueType, std::cout << "Some other ||" << lookup << "||" << std::endl; } diff --git a/src/CGenerator.cpp b/src/CGenerator.cpp index c6c7723..3a856f6 100644 --- a/src/CGenerator.cpp +++ b/src/CGenerator.cpp @@ -198,8 +198,10 @@ std::string CGenerator::generate(NodeTree* from, NodeTree* enc if (funcType == function) { if (name == "++" || name == "--") return generate(children[1], enclosingObject) + name; - if (name == "*" && children.size() == 2) //Is dereference, not multiplication - return "*(" + generate(children[1], enclosingObject) + ")"; + if (name == "*" || name == "&" && children.size() == 2) //Is dereference, not multiplication, or address-of + return name + "(" + generate(children[1], enclosingObject) + ")"; + if (name == "[]") + return "(" + generate(children[1], enclosingObject) + ")[" +generate(children[2],enclosingObject) + "]"; if (name == "+" || name == "-" || name == "*" || name == "/" || name == "==" || name == ">=" || name == "<=" || name == "!=" || name == "<" || name == ">" || name == "%" || name == "+=" || name == "-=" || name == "*=" || name == "/=" || name == "||" || name == "&&" || name == "!" ) From 6c3267a8b23730ff88bcffde24c16e267d53cfee Mon Sep 17 00:00:00 2001 From: Nathan Braswell Date: Wed, 7 May 2014 02:33:04 -0400 Subject: [PATCH 06/37] Some groundwork for templates --- include/ASTTransformation.h | 2 +- krakenGrammer.kgm | 6 +++-- src/ASTTransformation.cpp | 52 +++++++++++++++++++++---------------- src/Importer.cpp | 3 ++- 4 files changed, 37 insertions(+), 26 deletions(-) diff --git a/include/ASTTransformation.h b/include/ASTTransformation.h index 36e4819..4fb8d09 100644 --- a/include/ASTTransformation.h +++ b/include/ASTTransformation.h @@ -22,7 +22,7 @@ class ASTTransformation: public NodeTransformation { std::string concatSymbolTree(NodeTree* root); NodeTree* doFunction(NodeTree* scope, std::string lookup, std::vector*> nodes); NodeTree* scopeLookup(NodeTree* scope, std::string lookup, std::vector types = std::vector()); - Type* typeFromString(std::string type, NodeTree* scope); + Type* typeFromTypeNode(NodeTree* typeNode, NodeTree* scope); private: Importer * importer; std::map*>> languageLevelScope; diff --git a/krakenGrammer.kgm b/krakenGrammer.kgm index 352eb4d..66bc097 100644 --- a/krakenGrammer.kgm +++ b/krakenGrammer.kgm @@ -2,7 +2,8 @@ Goal = translation_unit ; 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 ; +type = type WS "\*" | "void" | "int" | "float" | "double" | "char" | identifier | identifier WS template_inst ; +template_inst = "<" WS type WS ">" ; import = "import" WS identifier WS ";" ; @@ -41,7 +42,8 @@ opt_parameter_list = parameter_list | ; parameter_list = parameter_list WS "," WS parameter | parameter ; parameter = boolean_expression ; -type_def = "typedef" WS identifier WS type | "typedef" WS identifier WS "{" WS class_innerds WS "}" | "typedef" WS identifier WS "{" WS declaration_block WS "}" ; +type_def = "typedef" WS identifier WS type | "typedef" WS template_dec WS identifier WS "{" WS class_innerds WS "}" | "typedef" WS template_dec 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 97b7c15..751b64c 100644 --- a/src/ASTTransformation.cpp +++ b/src/ASTTransformation.cpp @@ -72,23 +72,34 @@ NodeTree* ASTTransformation::transform(NodeTree* from, NodeTree } //newNode = new NodeTree(name, ASTData(identifier, Symbol(concatSymbolTree(children[0]), true))); } else if (name == "type_def") { - std::string typeAlias = concatSymbolTree(children[0]); //If it is an alisis of a type + std::string typeAlias; if (children[1]->getData().getName() == "type") { - newNode = new NodeTree(name, ASTData(type_def, Symbol(typeAlias, true, typeAlias), typeFromString(concatSymbolTree(children[1]), scope))); + typeAlias = concatSymbolTree(children[0]); + newNode = new NodeTree(name, ASTData(type_def, Symbol(typeAlias, true, typeAlias), typeFromTypeNode(children[1], scope))); skipChildren.insert(1); //Don't want any children, it's unnecessary for ailising } else { //Is a struct or class + Type* objectType = NULL; + if (children[0]->getData().getName() == "template_dec") { + typeAlias = concatSymbolTree(children[1]); + objectType = new Type(newNode), std::cout << "Template Type!"<(name, ASTData(type_def, Symbol(typeAlias, true, typeAlias))); - newNode->getDataRef()->valueType = new Type(newNode); //Type is self-referential since this is the definition + newNode->getDataRef()->valueType = objectType; //Type is self-referential since this is the definition } scope->getDataRef()->scope[typeAlias].push_back(newNode); newNode->getDataRef()->scope["~enclosing_scope"].push_back(scope); scope = newNode; - skipChildren.insert(0); //Identifier lookup will be ourselves, as we just added ourselves to the scope //return newNode; } else if (name == "function") { std::string functionName = concatSymbolTree(children[1]); - newNode = new NodeTree(name, ASTData(function, Symbol(functionName, true), typeFromString(concatSymbolTree(children[0]), scope))); + newNode = new NodeTree(name, ASTData(function, Symbol(functionName, true), typeFromTypeNode(children[0], scope))); skipChildren.insert(0); skipChildren.insert(1); scope->getDataRef()->scope[functionName].push_back(newNode); @@ -111,8 +122,8 @@ NodeTree* ASTTransformation::transform(NodeTree* from, NodeTree } else if (name == "typed_parameter") { //newNode = transform(children[1]); //Transform to get the identifier std::string parameterName = concatSymbolTree(children[1]); - 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), typeFromString(typeString, scope))); + //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))); scope->getDataRef()->scope[parameterName].push_back(newNode); newNode->getDataRef()->scope["~enclosing_scope"].push_back(scope); return newNode; @@ -252,21 +263,12 @@ NodeTree* ASTTransformation::transform(NodeTree* from, NodeTree // newIdentifier->getDataRef()->valueType = Type(concatSymbolTree(children[0]));//set the type of the identifier std::string newIdentifierStr = concatSymbolTree(children[1]); std::string typeString = concatSymbolTree(children[0]);//Get the type (left child) and set our new identifer to be that type - Type* identifierType = typeFromString(typeString, scope); + Type* identifierType = typeFromTypeNode(children[0], scope); NodeTree* newIdentifier = new NodeTree("identifier", ASTData(identifier, Symbol(newIdentifierStr, true), identifierType)); scope->getDataRef()->scope[newIdentifierStr].push_back(newIdentifier); newNode->getDataRef()->scope["~enclosing_scope"].push_back(scope); - //Now we don't do this thing - // if (identifierType->typeDefinition) { - // //Is a custom type. Populate this declaration's scope with it's inner declarations - // std::vector*> definitions = identifierType->typeDefinition->getChildren(); - // for (auto i : definitions) { - // //Point to the identifier. May need to change so it points to the declaration or something, with new declarations..... - // newIdentifier->getDataRef()->scope[i->get(0)->getDataRef()->symbol.getName()] = i->get(0); //make each declaration's name point to it's definition, like above - // } - // } - newNode->addChild(newIdentifier); + skipChildren.insert(0); //These, the type and the identifier, have been taken care of. skipChildren.insert(1); } else if (name == "if_comp") { @@ -301,7 +303,7 @@ NodeTree* ASTTransformation::transform(NodeTree* from, NodeTree return transform(children[0], scope, types); //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), typeFromString(theConcat, scope))); + newNode = new NodeTree(name, ASTData(value, Symbol(theConcat, true), typeFromTypeNode(from, scope))); } else if (name == "number") { return transform(children[0], scope, types); } else if (name == "integer") { @@ -486,7 +488,13 @@ NodeTree* ASTTransformation::scopeLookup(NodeTree* scope, std: return NULL; } -Type* ASTTransformation::typeFromString(std::string typeIn, NodeTree* scope) { +Type* ASTTransformation::typeFromTypeNode(NodeTree* typeNode, NodeTree* scope) { + std::string typeIn; + if (typeNode->getChildren().size() > 1 && typeNode->getChildren()[1]->getData().getName() == "template_inst") + typeIn = concatSymbolTree(typeNode->getChildren()[0]); //Not including the possible template for now + else + typeIn = concatSymbolTree(typeNode); + int indirection = 0; ValueType baseType; NodeTree* typeDefinition = NULL; @@ -499,8 +507,8 @@ Type* ASTTransformation::typeFromString(std::string typeIn, NodeTree* s else if (edited == "int") baseType = integer; else if (edited == "float") - baseType = floating -; else if (edited == "double") + baseType = floating; + else if (edited == "double") baseType = double_percision; else if (edited == "char") baseType = character; diff --git a/src/Importer.cpp b/src/Importer.cpp index eaf8838..db04e72 100644 --- a/src/Importer.cpp +++ b/src/Importer.cpp @@ -14,13 +14,14 @@ Importer::Importer(Parser* parserIn, std::vector includePaths) { removeSymbols.push_back(Symbol("}", true)); removeSymbols.push_back(Symbol("(", true)); removeSymbols.push_back(Symbol(")", true)); - removeSymbols.push_back(Symbol("import", true)); //Don't need the actual text of the symbol + removeSymbols.push_back(Symbol("import", true)); removeSymbols.push_back(Symbol("interpreter_directive", false)); removeSymbols.push_back(Symbol("if", true)); removeSymbols.push_back(Symbol("while", true)); removeSymbols.push_back(Symbol("__if_comp__", true)); removeSymbols.push_back(Symbol("comp_simple_passthrough", true)); removeSymbols.push_back(Symbol("typedef", true)); + removeSymbols.push_back(Symbol("template", true)); collapseSymbols.push_back(Symbol("opt_typed_parameter_list", false)); collapseSymbols.push_back(Symbol("opt_parameter_list", false)); From 5de2ff58bbd9f35c9b575c888b650ace86255459 Mon Sep 17 00:00:00 2001 From: Nathan Braswell Date: Thu, 8 May 2014 01:07:57 -0400 Subject: [PATCH 07/37] Some template implementation/tests --- include/ASTData.h | 3 +++ src/ASTData.cpp | 9 +++++++++ src/ASTTransformation.cpp | 16 +++++++++++++--- 3 files changed, 25 insertions(+), 3 deletions(-) diff --git a/include/ASTData.h b/include/ASTData.h index 48bee63..8717a75 100644 --- a/include/ASTData.h +++ b/include/ASTData.h @@ -26,10 +26,13 @@ class ASTData { ~ASTData(); std::string toString(); static std::string ASTTypeToString(ASTType type); + void addTemplateTypeDefToReplace(NodeTree* typeDefToReplace); + std::vector*> getTemplateTypeDefsToReplace(); ASTType type; Type* valueType; Symbol symbol; std::map*>> scope; + std::vector*> templateTypeDefsToReplace; //Used only by template classes/functions to keep track of pointers to the typedefs that need to be changed private: }; diff --git a/src/ASTData.cpp b/src/ASTData.cpp index 22fc30d..e4a399d 100644 --- a/src/ASTData.cpp +++ b/src/ASTData.cpp @@ -74,3 +74,12 @@ std::string ASTData::ASTTypeToString(ASTType type) { return "unknown_ASTType"; } } + +void ASTData::addTemplateTypeDefToReplace(NodeTree* typeDefToReplace) { + templateTypeDefsToReplace.push_back(typeDefToReplace); +} + +std::vector*> ASTData::getTemplateTypeDefsToReplace() { + return templateTypeDefsToReplace; +} + diff --git a/src/ASTTransformation.cpp b/src/ASTTransformation.cpp index 751b64c..361cbc0 100644 --- a/src/ASTTransformation.cpp +++ b/src/ASTTransformation.cpp @@ -77,20 +77,30 @@ NodeTree* ASTTransformation::transform(NodeTree* from, NodeTree 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))); - skipChildren.insert(1); //Don't want any children, it's unnecessary for ailising + skipChildren.insert(0); //Don't want any children, it's unnecessary for ailising + skipChildren.insert(1); } else { //Is a struct or class Type* objectType = NULL; if (children[0]->getData().getName() == "template_dec") { typeAlias = concatSymbolTree(children[1]); + newNode = new NodeTree(name, ASTData(type_def, Symbol(typeAlias, true, typeAlias))); objectType = new Type(newNode), std::cout << "Template Type!"<getChildren()[1]); + NodeTree* templateTypeDef = new NodeTree(name, ASTData(type_def, Symbol(templateTypeName, true, templateTypeName), NULL)); + newNode->getDataRef()->scope[templateTypeName].push_back(templateTypeDef); + newNode->getDataRef()->addTemplateTypeDefToReplace(templateTypeDef); + skipChildren.insert(0); //Don't try to transform the template skipChildren.insert(1); //Identifier lookup will be ourselves, as we just added ourselves to the scope } else { typeAlias = concatSymbolTree(children[0]); + 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 = new NodeTree(name, ASTData(type_def, Symbol(typeAlias, true, typeAlias))); newNode->getDataRef()->valueType = objectType; //Type is self-referential since this is the definition } scope->getDataRef()->scope[typeAlias].push_back(newNode); From 5022fc080288dfeba1a5059531e5bf167e1dd320 Mon Sep 17 00:00:00 2001 From: Nathan Braswell Date: Fri, 9 May 2014 02:56:55 -0400 Subject: [PATCH 08/37] Significant work on templates. They should be close to working now (for single replacement). However, they do not show up in the global scope the the C generator can't see them. Plus, their names will have to be Cified. --- include/ASTData.h | 3 - include/ASTTransformation.h | 8 +- include/Type.h | 4 +- src/ASTData.cpp | 9 -- src/ASTTransformation.cpp | 166 +++++++++++++++++++++++------------- src/Type.cpp | 17 +++- 6 files changed, 130 insertions(+), 77 deletions(-) diff --git a/include/ASTData.h b/include/ASTData.h index 8717a75..48bee63 100644 --- a/include/ASTData.h +++ b/include/ASTData.h @@ -26,13 +26,10 @@ class ASTData { ~ASTData(); std::string toString(); static std::string ASTTypeToString(ASTType type); - void addTemplateTypeDefToReplace(NodeTree* typeDefToReplace); - std::vector*> getTemplateTypeDefsToReplace(); ASTType type; Type* valueType; Symbol symbol; std::map*>> scope; - std::vector*> templateTypeDefsToReplace; //Used only by template classes/functions to keep track of pointers to the typedefs that need to be changed private: }; diff --git a/include/ASTTransformation.h b/include/ASTTransformation.h index 4fb8d09..0766b94 100644 --- a/include/ASTTransformation.h +++ b/include/ASTTransformation.h @@ -16,13 +16,13 @@ class ASTTransformation: public NodeTransformation { ASTTransformation(Importer* importerIn); ~ASTTransformation(); virtual NodeTree* transform(NodeTree* from); - NodeTree* transform(NodeTree* from, NodeTree* scope, std::vector types = std::vector()); - std::vector*> transformChildren(std::vector*> children, std::set skipChildren, NodeTree* scope, std::vector types); + 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); + NodeTree* doFunction(NodeTree* scope, std::string lookup, std::vector*> nodes, std::map templateTypeReplacements); NodeTree* scopeLookup(NodeTree* scope, std::string lookup, std::vector types = std::vector()); - Type* typeFromTypeNode(NodeTree* typeNode, NodeTree* scope); + Type* typeFromTypeNode(NodeTree* typeNode, NodeTree* scope, std::map templateTypeReplacements); private: Importer * importer; std::map*>> languageLevelScope; diff --git a/include/Type.h b/include/Type.h index 62bd270..ba5891f 100644 --- a/include/Type.h +++ b/include/Type.h @@ -13,7 +13,7 @@ class ASTData; #include "ASTData.h" #include "util.h" -enum ValueType {none, void_type, boolean, integer, floating, double_percision, character }; +enum ValueType {none, template_type, void_type, boolean, integer, floating, double_percision, character }; class Type { @@ -24,6 +24,7 @@ class Type { Type(NodeTree* typeDefinitionIn); Type(NodeTree* typeDefinitionIn, int indirectionIn); Type(ValueType typeIn, NodeTree* typeDefinitionIn, int indirectionIn); + Type(ValueType typeIn, NodeTree* templateDefinitionIn); ~Type(); bool const operator==(const Type &other)const; bool const operator!=(const Type &other)const; @@ -32,6 +33,7 @@ class Type { ValueType baseType; NodeTree* typeDefinition; int indirection; + NodeTree* templateDefinition; private: }; diff --git a/src/ASTData.cpp b/src/ASTData.cpp index e4a399d..22fc30d 100644 --- a/src/ASTData.cpp +++ b/src/ASTData.cpp @@ -74,12 +74,3 @@ std::string ASTData::ASTTypeToString(ASTType type) { return "unknown_ASTType"; } } - -void ASTData::addTemplateTypeDefToReplace(NodeTree* typeDefToReplace) { - templateTypeDefsToReplace.push_back(typeDefToReplace); -} - -std::vector*> ASTData::getTemplateTypeDefsToReplace() { - return templateTypeDefsToReplace; -} - diff --git a/src/ASTTransformation.cpp b/src/ASTTransformation.cpp index 361cbc0..2411fbc 100644 --- a/src/ASTTransformation.cpp +++ b/src/ASTTransformation.cpp @@ -32,10 +32,10 @@ ASTTransformation::~ASTTransformation() { NodeTree* ASTTransformation::transform(NodeTree* from) { //Set up top scope - return transform(from, NULL, std::vector()); + return transform(from, NULL, std::vector(), std::map()); } -NodeTree* ASTTransformation::transform(NodeTree* from, NodeTree* scope, std::vector types) { +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; @@ -76,25 +76,21 @@ NodeTree* ASTTransformation::transform(NodeTree* from, NodeTree std::string typeAlias; 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))); + newNode = new NodeTree(name, ASTData(type_def, Symbol(typeAlias, true, typeAlias), 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 Type* objectType = NULL; if (children[0]->getData().getName() == "template_dec") { typeAlias = concatSymbolTree(children[1]); - newNode = new NodeTree(name, ASTData(type_def, Symbol(typeAlias, true, typeAlias))); - objectType = new Type(newNode), std::cout << "Template Type!"<getChildren()[1]); - NodeTree* templateTypeDef = new NodeTree(name, ASTData(type_def, Symbol(templateTypeName, true, templateTypeName), NULL)); - newNode->getDataRef()->scope[templateTypeName].push_back(templateTypeDef); - newNode->getDataRef()->addTemplateTypeDefToReplace(templateTypeDef); - skipChildren.insert(0); //Don't try to transform the template - skipChildren.insert(1); //Identifier lookup will be ourselves, as we just added ourselves to the scope + 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); + // skipChildren.insert(0); //Don't try to transform the template + // skipChildren.insert(1); //Identifier lookup will be ourselves, as we just added ourselves to the scope } else { typeAlias = concatSymbolTree(children[0]); newNode = new NodeTree(name, ASTData(type_def, Symbol(typeAlias, true, typeAlias))); @@ -105,11 +101,15 @@ NodeTree* ASTTransformation::transform(NodeTree* from, NodeTree } scope->getDataRef()->scope[typeAlias].push_back(newNode); newNode->getDataRef()->scope["~enclosing_scope"].push_back(scope); + + //Templates are done here. No need to go farther + if (children[0]->getData().getName() == "template_dec") + return newNode; scope = newNode; //return newNode; } else if (name == "function") { std::string functionName = concatSymbolTree(children[1]); - newNode = new NodeTree(name, ASTData(function, Symbol(functionName, true), typeFromTypeNode(children[0], scope))); + 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); @@ -133,7 +133,7 @@ NodeTree* ASTTransformation::transform(NodeTree* from, NodeTree //newNode = transform(children[1]); //Transform to get the identifier std::string parameterName = concatSymbolTree(children[1]); //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))); + 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); return newNode; @@ -142,9 +142,9 @@ 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); + std::vector*> transformedChildren = transformChildren(children, skipChildren, scope, types, templateTypeReplacements); std::string functionCallString = concatSymbolTree(children[1]); - NodeTree* function = doFunction(scope, functionCallString, transformedChildren); + NodeTree* function = doFunction(scope, functionCallString, transformedChildren, templateTypeReplacements); if (function == NULL) { std::cout << "scope lookup error! Could not find " << functionCallString << " in boolean stuff " << std::endl; throw "LOOKUP ERROR: " + functionCallString; @@ -157,23 +157,25 @@ 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); //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") { //unarad can ride through, it should always just be a promoted child //If this is an actual part of an expression, not just a premoted child if (children.size() > 2) { - NodeTree* lhs = transform(children[0], scope); //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") - rhs = transform(children[2], lhs->getDataRef()->valueType->typeDefinition, types); //If an access operation, then the right side will be in the lhs's type's scope + if (name == "access_operation") { + std::cout << "lhs is: " << lhs->getDataRef()->toString() << std::endl; + 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); + rhs = transform(children[2], scope, types, templateTypeReplacements); std::string functionCallName = concatSymbolTree(children[1]); //std::cout << "scope lookup from expression or similar" << std::endl; std::vector*> transformedChildren; transformedChildren.push_back(lhs); transformedChildren.push_back(rhs); - NodeTree* function = doFunction(scope, functionCallName, transformedChildren); + NodeTree* function = doFunction(scope, functionCallName, transformedChildren, templateTypeReplacements); if (function == NULL) { std::cout << "scope lookup error! Could not find " << functionCallName << " in expression " << std::endl; throw "LOOKUP ERROR: " + functionCallName; @@ -198,7 +200,7 @@ NodeTree* ASTTransformation::transform(NodeTree* from, NodeTree return newNode; //skipChildren.insert(1); } else { - return transform(children[0], scope, types); //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 @@ -208,13 +210,13 @@ 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); + param = transform(children[1], scope, types, templateTypeReplacements); else - funcName = concatSymbolTree(children[1]), param = transform(children[0], scope, types); + 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); - NodeTree* function = doFunction(scope, funcName, transformedChildren); + NodeTree* function = doFunction(scope, funcName, transformedChildren, templateTypeReplacements); if (function == NULL) { std::cout << "scope lookup error! Could not find " << funcName << " in factor " << std::endl; throw "LOOKUP ERROR: " + funcName; @@ -224,16 +226,16 @@ NodeTree* ASTTransformation::transform(NodeTree* from, NodeTree } else if (children.size() >= 4) { //Array brackets [] funcName = "[]"; std::vector*> transformedChildren; - transformedChildren.push_back(transform(children[0], scope, types)); - transformedChildren.push_back(transform(children[2], scope, types)); - NodeTree* function = doFunction(scope, funcName, transformedChildren); + transformedChildren.push_back(transform(children[0], scope, types, templateTypeReplacements)); + transformedChildren.push_back(transform(children[2], scope, types, templateTypeReplacements)); + NodeTree* function = doFunction(scope, funcName, transformedChildren, templateTypeReplacements); if (function == NULL) { std::cout << "scope lookup error! Could not find " << funcName << " in factor " << std::endl; throw "LOOKUP ERROR: " + funcName; } return function; } else { - return transform(children[0], scope, types); //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)); @@ -249,15 +251,15 @@ 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)); - newNode->addChild(transform(children[2], scope, types)); + 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); - NodeTree* rhs = transform(children[2], scope, types); + 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); + NodeTree* operatorCall = doFunction(scope, functionName, transformedChildren, templateTypeReplacements); if (operatorCall == NULL) { std::cout << "scope lookup error! Could not find " << functionName << " in assignment_statement " << std::endl; throw "LOOKUP ERROR: " + functionName; @@ -272,8 +274,8 @@ 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]); - std::string typeString = concatSymbolTree(children[0]);//Get the type (left child) and set our new identifer to be that type - Type* identifierType = typeFromTypeNode(children[0], scope); + 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); newNode->getDataRef()->scope["~enclosing_scope"].push_back(scope); @@ -295,12 +297,12 @@ NodeTree* ASTTransformation::transform(NodeTree* from, NodeTree // throw "LOOKUP ERROR: " + functionCallName; // } skipChildren.insert(0); - std::vector*> transformedChildren = transformChildren(children, skipChildren, scope, types); + 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)); + 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() << " "; @@ -310,12 +312,12 @@ NodeTree* ASTTransformation::transform(NodeTree* from, NodeTree newNode->addChildren(transformedChildren); return newNode; } else if (name == "parameter") { - return transform(children[0], scope, types); //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))); + newNode = new NodeTree(name, ASTData(value, Symbol(theConcat, true), typeFromTypeNode(from, scope, templateTypeReplacements))); } else if (name == "number") { - return transform(children[0], scope, types); + 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 == "float") { @@ -335,7 +337,7 @@ NodeTree* ASTTransformation::transform(NodeTree* from, NodeTree //Do all children but the ones we skip for (int i = 0; i < children.size(); i++) { if (skipChildren.find(i) == skipChildren.end()) { - NodeTree* transChild = transform(children[i], scope, types); + 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. newNode->addChild(transChild); else @@ -346,12 +348,12 @@ NodeTree* ASTTransformation::transform(NodeTree* from, NodeTree } //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::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); + 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 @@ -361,6 +363,7 @@ std::vector*> ASTTransformation::transformChildren(std::vector return transformedChildren; } +//Extract types from already transformed nodes std::vector ASTTransformation::mapNodesToTypes(std::vector*> nodes) { std::vector types; for (auto i : nodes) { @@ -370,6 +373,7 @@ std::vector ASTTransformation::mapNodesToTypes(std::vector* root) { std::string concatString; std::string ourValue = root->getDataRef()->getValue(); @@ -382,9 +386,8 @@ std::string ASTTransformation::concatSymbolTree(NodeTree* root) { return concatString; } -//Overloaded with the actual children to allow us to handle operator methods -NodeTree* ASTTransformation::doFunction(NodeTree* scope, std::string lookup, std::vector*> nodes) { - // +//We pass in the actual children (parameters) to allow us to handle overloaded operator methods (where a parameter is actually the scope of the method) +NodeTree* ASTTransformation::doFunction(NodeTree* scope, std::string lookup, std::vector*> nodes, std::map templateTypeReplacements) { auto LLElementIterator = languageLevelScope.find(lookup); NodeTree* newNode; if (LLElementIterator != languageLevelScope.end()) { @@ -435,10 +438,11 @@ NodeTree* ASTTransformation::doFunction(NodeTree* scope, std:: } else { newNode->getDataRef()->valueType = function->getDataRef()->valueType, std::cout << "Some other ||" << lookup << "||" << std::endl; } - return newNode; } +//Search recursively through levels of scope (each ASTData, that is, every node, has its own scope) +//We pass in types so that if we're searching for a function we can find the right overloaded one NodeTree* ASTTransformation::scopeLookup(NodeTree* scope, std::string lookup, std::vector types) { //We first search the languageLevelScope to see if it's an operator. If so, we modifiy the lookup with a preceding "operator" auto LLElementIterator = languageLevelScope.find(lookup); @@ -456,7 +460,7 @@ NodeTree* ASTTransformation::scopeLookup(NodeTree* scope, std: //Types and functions cannot have the same name, and types very apparently do not have parameter types, so check and short-circuit if ((*i)->getDataRef()->type == type_def) return *i; - //return *i; + std::vector*> children = (*i)->getChildren(); if (types.size() != ((children.size() > 0) ? children.size()-1 : 0)) { std::cout << "Type sizes do not match between two " << lookup << "(" << types.size() << "," << ((children.size() > 0) ? children.size()-1 : 0) << "), types are: "; @@ -498,12 +502,10 @@ NodeTree* ASTTransformation::scopeLookup(NodeTree* scope, std: return NULL; } -Type* ASTTransformation::typeFromTypeNode(NodeTree* typeNode, NodeTree* scope) { +//Create a type from a syntax tree. This can get complicated with templates +Type* ASTTransformation::typeFromTypeNode(NodeTree* typeNode, NodeTree* scope, std::map templateTypeReplacements) { std::string typeIn; - if (typeNode->getChildren().size() > 1 && typeNode->getChildren()[1]->getData().getName() == "template_inst") - typeIn = concatSymbolTree(typeNode->getChildren()[0]); //Not including the possible template for now - else - typeIn = concatSymbolTree(typeNode); + typeIn = concatSymbolTree(typeNode); int indirection = 0; ValueType baseType; @@ -525,7 +527,53 @@ Type* ASTTransformation::typeFromTypeNode(NodeTree* typeNode, NodeTreeclone(); + templateTypeReplacement->indirection += indirection; + return templateTypeReplacement; + } + //If not, we better instantiate it and then add it to the scope + //Note that this means the template instantiation is scoped, which is inefficient, though it has a nice correctness about it + if (typeDefinition == NULL && typeNode->getChildren().size() > 1 && typeNode->getChildren()[1]->getData().getName() == "template_inst") { + std::cout << "Template type: " << edited << " not yet instantiated" << std::endl; + //Look up this template's plain definition. It's type has the syntax tree that we need to parse + NodeTree* templateDefinition = scopeLookup(scope,concatSymbolTree(typeNode->getChildren()[0])); + 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::map newTemplateTypeReplacement; + std::string templateParameterName = concatSymbolTree(templateSyntaxTree->getChildren()[0]->getChildren()[1]); + Type* replacementType = typeFromTypeNode(typeNode->getChildren()[1]->getChildren()[1], scope, templateTypeReplacements); + newTemplateTypeReplacement[templateParameterName] = replacementType; + + std::string classNameWithoutTemplate = concatSymbolTree(typeNode->getChildren()[0]); + std::string fullyInstantiatedName = classNameWithoutTemplate + "<" + replacementType->toString() + ">"; + + typeDefinition = new NodeTree("type_def", ASTData(type_def, Symbol(fullyInstantiatedName, true, fullyInstantiatedName))); + typeDefinition->getDataRef()->valueType = new Type(typeDefinition);; //Type is self-referential since this is the definition + + scope->getDataRef()->scope[fullyInstantiatedName].push_back(typeDefinition); + //Note that the instantiated template's scope is the template's definition. + typeDefinition->getDataRef()->scope["~enclosing_scope"].push_back(templateDefinition); + + 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)); + std::cout << "Done instantating " << fullyInstantiatedName << " that had template parameter " << templateParameterName << " with " << replacementType->toString() << std::endl; + } else { + std::cout << "Type: " << edited << " already instantiated!" << std::endl; + } } - return new Type(baseType, typeDefinition, indirection); + Type* toReturn = new Type(baseType, typeDefinition, indirection); + std::cout << "Returning type " << toReturn->toString() << std::endl; + return toReturn; } diff --git a/src/Type.cpp b/src/Type.cpp index 3f12bbf..a87aa03 100644 --- a/src/Type.cpp +++ b/src/Type.cpp @@ -4,42 +4,55 @@ Type::Type() { indirection = 0; baseType = none; typeDefinition = NULL; + templateDefinition = NULL; } Type::Type(ValueType typeIn) { indirection = 0; baseType = typeIn; typeDefinition = NULL; + templateDefinition = NULL; } Type::Type(ValueType typeIn, int indirectionIn) { indirection = indirectionIn; baseType = typeIn; typeDefinition = NULL; + templateDefinition = NULL; } Type::Type(NodeTree* typeDefinitionIn) { indirection = 0; baseType = none; typeDefinition = typeDefinitionIn; + templateDefinition = NULL; } Type::Type(NodeTree* typeDefinitionIn, int indirectionIn) { indirection = indirectionIn; baseType = none; typeDefinition = typeDefinitionIn; + templateDefinition = NULL; } Type::Type(ValueType typeIn, NodeTree* typeDefinitionIn, int indirectionIn) { baseType = typeIn; indirection = indirectionIn; typeDefinition = typeDefinitionIn; + templateDefinition = NULL; } +Type::Type(ValueType typeIn, NodeTree* templateDefinitionIn) { + indirection = 0; + baseType = typeIn; + typeDefinition = NULL; + templateDefinition = templateDefinitionIn; +} + Type::~Type() { } const bool Type::operator==(const Type &other) const { - return( baseType == other.baseType && indirection == other.indirection && typeDefinition == other.typeDefinition); + return( baseType == other.baseType && indirection == other.indirection && typeDefinition == other.typeDefinition && templateDefinition == other.templateDefinition); } const bool Type::operator!=(const Type &other) const { @@ -55,6 +68,8 @@ std::string Type::toString() { else typeString = "none"; break; + case template_type: + typeString = "template: " + templateDefinition->getDataRef()->toString(); case void_type: typeString = "void"; break; From 2a4edf9afd6990f968bb08c016b7b6414e382eb8 Mon Sep 17 00:00:00 2001 From: Nathan Braswell Date: Sat, 10 May 2014 19:28:36 -0400 Subject: [PATCH 09/37] Simple Templates work! Even Templates in other files work. Happy day --- CMakeLists.txt | 8 +++++++- include/ASTTransformation.h | 1 + include/CGenerator.h | 2 +- src/ASTTransformation.cpp | 12 +++++++++--- src/CGenerator.cpp | 28 ++++++++++++++++------------ 5 files changed, 34 insertions(+), 17 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 12ef013..48b80aa 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -8,9 +8,15 @@ set( MY_INCLUDES ${PROJECT_SOURCE_DIR}/include) set( MY_SOURCES main.cpp src/Parser.cpp src/LALRParser.cpp src/GraphStructuredStack.cpp src/RNGLRParser.cpp src/ParseAction.cpp src/ParseRule.cpp src/Symbol.cpp src/StringReader.cpp src/State.cpp src/util.cpp src/Lexer.cpp src/RegEx.cpp src/RegExState.cpp src/Table.cpp src/ASTData.cpp src/ASTTransformation.cpp src/CGenerator.cpp src/Type.cpp src/Importer.cpp ) +add_custom_target(STDLibCopy ALL) +add_custom_command(TARGET STDLibCopy POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy_directory + "${PROJECT_SOURCE_DIR}/stdlib" + "${PROJECT_BINARY_DIR}/stdlib") + include_directories( ${MY_INCLUDES} ) add_executable(kraken ${MY_SOURCES}) -file(COPY stdlib DESTINATION .) + diff --git a/include/ASTTransformation.h b/include/ASTTransformation.h index 0766b94..4ae3e41 100644 --- a/include/ASTTransformation.h +++ b/include/ASTTransformation.h @@ -26,6 +26,7 @@ class ASTTransformation: public NodeTransformation { private: Importer * importer; std::map*>> languageLevelScope; + NodeTree* topScope; //maintained for templates that need to add themselves to the top scope no matter where they are instantiated }; #endif diff --git a/include/CGenerator.h b/include/CGenerator.h index fe8e8b8..d7e4e03 100644 --- a/include/CGenerator.h +++ b/include/CGenerator.h @@ -20,7 +20,7 @@ class CGenerator { std::string generate(NodeTree* from, NodeTree* enclosingObject = NULL); static std::string ValueTypeToCType(Type *type); static std::string ValueTypeToCTypeDecoration(Type *type); - static std::string CifyFunctionName(std::string name); + static std::string CifyName(std::string name); std::string generateObjectMethod(NodeTree* enclosingObject, NodeTree* from); std::string generatorString; diff --git a/src/ASTTransformation.cpp b/src/ASTTransformation.cpp index 2411fbc..84215d0 100644 --- a/src/ASTTransformation.cpp +++ b/src/ASTTransformation.cpp @@ -2,6 +2,7 @@ ASTTransformation::ASTTransformation(Importer *importerIn) { importer = importerIn; + topScope = NULL; //Set up language level special scope. (the final scope checked) //Note the NULL type languageLevelScope["+"].push_back( new NodeTree("function", ASTData(function, Symbol("+", true), NULL))); @@ -45,6 +46,7 @@ NodeTree* ASTTransformation::transform(NodeTree* from, NodeTree 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 } else if (name == "interpreter_directive") { newNode = new NodeTree(name, ASTData(interpreter_directive)); } else if (name == "import" && !current.isTerminal()) { @@ -536,8 +538,7 @@ Type* ASTTransformation::typeFromTypeNode(NodeTree* typeNode, NodeTreeindirection += indirection; return templateTypeReplacement; } - //If not, we better instantiate it and then add it to the scope - //Note that this means the template instantiation is scoped, which is inefficient, though it has a nice correctness about it + //If not, we better instantiate it and then add it to the highest (not current) scope if (typeDefinition == NULL && typeNode->getChildren().size() > 1 && typeNode->getChildren()[1]->getData().getName() == "template_inst") { std::cout << "Template type: " << edited << " not yet instantiated" << std::endl; //Look up this template's plain definition. It's type has the syntax tree that we need to parse @@ -560,7 +561,12 @@ Type* ASTTransformation::typeFromTypeNode(NodeTree* typeNode, NodeTree("type_def", ASTData(type_def, Symbol(fullyInstantiatedName, true, fullyInstantiatedName))); typeDefinition->getDataRef()->valueType = new Type(typeDefinition);; //Type is self-referential since this is the definition - scope->getDataRef()->scope[fullyInstantiatedName].push_back(typeDefinition); + //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 + topScope->getDataRef()->scope[fullyInstantiatedName].push_back(typeDefinition); + topScope->addChild(typeDefinition); //Add this object the the highest scope's + + //Note that the instantiated template's scope is the template's definition. typeDefinition->getDataRef()->scope["~enclosing_scope"].push_back(templateDefinition); diff --git a/src/CGenerator.cpp b/src/CGenerator.cpp index 3a856f6..bf146ae 100644 --- a/src/CGenerator.cpp +++ b/src/CGenerator.cpp @@ -70,7 +70,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 += CifyFunctionName(declarationData.symbol.getName()) + nameDecoration + "(" + parameters + "); /*func*/\n"; + output += CifyName(declarationData.symbol.getName()) + nameDecoration + "(" + parameters + "); /*func*/\n"; break; } case type_def: @@ -104,13 +104,15 @@ std::string CGenerator::generate(NodeTree* from, NodeTree* enc if (false) for (int j = 0; j < children.size()-1; j++) preName += ValueTypeToCType(children[j]->getData().valueType) + "_"; - return preName + CifyFunctionName(data.symbol.getName()); //Cifying does nothing if not an operator overload + return preName + CifyName(data.symbol.getName()); //Cifying does nothing if not an operator overload } case type_def: - if (children.size() == 0) { + if (data.valueType->baseType == template_type) { + return "/* non instantiated template " + data.symbol.getName() + " */"; + } else if (children.size() == 0) { return "typedef " + ValueTypeToCType(data.valueType) + " " + data.symbol.getName() + ";"; } else { - std::string objectString = "typedef struct __struct_dummy_" + data.symbol.getName() + "__ {\n"; + std::string objectString = "typedef struct __struct_dummy_" + CifyName(data.symbol.getName()) + "__ {\n"; std::string postString; //The functions have to be outside the struct definition for (int i = 0; i < children.size(); i++) { std::cout << children[i]->getName() << std::endl; @@ -119,7 +121,7 @@ std::string CGenerator::generate(NodeTree* from, NodeTree* enc else objectString += generate(children[i], enclosingObject) + "\n"; } - objectString += "} " + data.symbol.getName() + ";"; + objectString += "} " + CifyName(data.symbol.getName()) + ";"; return objectString + postString; //Functions come after the declaration of the struct } case function: @@ -132,7 +134,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 += CifyFunctionName(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: @@ -220,7 +222,7 @@ 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 possibleObjectType->getDataRef()->symbol.getName() +"__" + CifyFunctionName(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 } else { @@ -242,7 +244,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 += CifyFunctionName(name) + nameDecoration + "("; +/*HERE*/ output += CifyName(name) + nameDecoration + "("; if (isSelfObjectMethod) output += children.size() > 1 ? "self," : "self"; } @@ -286,8 +288,8 @@ std::string CGenerator::generateObjectMethod(NodeTree* enclosingObject, parameters += ", " + ValueTypeToCType(children[i]->getData().valueType) + " " + generate(children[i]); nameDecoration += "_" + ValueTypeToCTypeDecoration(children[i]->getData().valueType); } - output += "\n" + ValueTypeToCType(data.valueType) + " " + enclosingObject->getDataRef()->symbol.getName() +"__" - + CifyFunctionName(data.symbol.getName()) + nameDecoration + "(" + ValueTypeToCType(&enclosingObjectType) + output += "\n" + ValueTypeToCType(data.valueType) + " " + CifyName(enclosingObject->getDataRef()->symbol.getName()) +"__" + + CifyName(data.symbol.getName()) + nameDecoration + "(" + ValueTypeToCType(&enclosingObjectType) + " self" + parameters + ")\n" + generate(children[children.size()-1], enclosingObject); //Pass in the object so we can properly handle access to member stuff return output; } @@ -297,7 +299,7 @@ std::string CGenerator::ValueTypeToCType(Type *type) { switch (type->baseType) { case none: if (type->typeDefinition) - return_type = type->typeDefinition->getDataRef()->symbol.getName(); + return_type = CifyName(type->typeDefinition->getDataRef()->symbol.getName()); else return_type = "none"; break; @@ -364,7 +366,7 @@ std::string CGenerator::ValueTypeToCTypeDecoration(Type *type) { return return_type; } -std::string CGenerator::CifyFunctionName(std::string name) { +std::string CGenerator::CifyName(std::string name) { std::string operatorsToReplace[] = { "+", "plus", "-", "minus", "*", "star", @@ -394,6 +396,8 @@ std::string CGenerator::CifyFunctionName(std::string name) { "|=", "pipeequals", "*=", "starequals", "<<=", "doublerightequals", + "<", "lessthan", + ">", "greaterthan", ">>=", "doubleleftequals", "->", "arrow" }; int length = sizeof(operatorsToReplace)/sizeof(std::string); From b2c61b00f253b23900c2b0629156fa39148c560e Mon Sep 17 00:00:00 2001 From: Nathan Braswell Date: Thu, 15 May 2014 17:58:41 -0400 Subject: [PATCH 10/37] Function templates working\! --- include/ASTTransformation.h | 1 + krakenGrammer.kgm | 8 ++-- src/ASTTransformation.cpp | 76 +++++++++++++++++++++++++++++++++---- src/CGenerator.cpp | 2 + 4 files changed, 75 insertions(+), 12 deletions(-) diff --git a/include/ASTTransformation.h b/include/ASTTransformation.h index 4ae3e41..759ad67 100644 --- a/include/ASTTransformation.h +++ b/include/ASTTransformation.h @@ -23,6 +23,7 @@ class ASTTransformation: public NodeTransformation { NodeTree* doFunction(NodeTree* scope, std::string lookup, std::vector*> nodes, std::map templateTypeReplacements); NodeTree* scopeLookup(NodeTree* scope, std::string lookup, std::vector types = std::vector()); Type* typeFromTypeNode(NodeTree* typeNode, NodeTree* scope, std::map templateTypeReplacements); + NodeTree* findOrInstantiateFunctionTemplate(std::vector*> children, NodeTree* scope, std::vector types, std::map templateTypeReplacements); private: Importer * importer; std::map*>> languageLevelScope; diff --git a/krakenGrammer.kgm b/krakenGrammer.kgm index 66bc097..4cc0d2a 100644 --- a/krakenGrammer.kgm +++ b/krakenGrammer.kgm @@ -32,7 +32,7 @@ identifier = alpha | alpha alphanumeric ; overloadable_operator = "\+" | "-" | "\*" | "/" | "%" | "^" | "&" | "\|" | "~" | "\!" | "," | "=" | "\+\+" | "--" | "<<" | ">>" | "==" | "!=" | "&&" | "\|\|" | "\+=" | "-=" | "/=" | "%=" | "^=" | "&=" | "\|=" | "\*=" | "<<=" | ">>=" | "->" ; func_identifier = identifier | identifier overloadable_operator ; -function = type WS func_identifier WS "\(" WS opt_typed_parameter_list WS "\)" WS code_block ; +function = template_dec WS type WS func_identifier WS "\(" WS opt_typed_parameter_list WS "\)" WS code_block | type WS func_identifier WS "\(" WS opt_typed_parameter_list WS "\)" WS code_block ; opt_typed_parameter_list = typed_parameter_list | ; typed_parameter_list = typed_parameter_list WS "," WS typed_parameter | typed_parameter ; @@ -42,8 +42,8 @@ opt_parameter_list = parameter_list | ; 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 template_dec WS identifier WS "{" WS declaration_block WS "}" ; -template_dec = "template" WS "<" WS identifier WS ">" | ; +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 "}" ; +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 ; @@ -71,7 +71,7 @@ expression = expression WS "<<" WS term | expression WS ">>" WS shiftand | shift shiftand = shiftand WS "-" WS term | shiftand WS "\+" WS term | term ; term = term WS forward_slash WS factor | term WS "\*" WS factor | term WS "%" WS factor | factor ; factor = "\+\+" WS unarad | unarad WS "\+\+" | "--" WS unarad | unarad WS "--" | "\+" WS unarad | "-" WS unarad | "!" WS unarad | "~" WS unarad | "\(" WS type WS "\)" WS unarad | "\*" WS unarad | "&" WS unarad | unarad WS "[" WS expression WS "]" | unarad ; -unarad = number | identifier | function_call | bool | string | character | "\(" WS boolean_expression WS "\)" | access_operation ; +unarad = number | identifier | identifier WS template_inst | function_call | bool | string | character | "\(" WS boolean_expression WS "\)" | access_operation ; number = integer | float | double ; access_operation = unarad "." identifier | unarad "->" identifier ; diff --git a/src/ASTTransformation.cpp b/src/ASTTransformation.cpp index 84215d0..00f4605 100644 --- a/src/ASTTransformation.cpp +++ b/src/ASTTransformation.cpp @@ -110,7 +110,16 @@ NodeTree* ASTTransformation::transform(NodeTree* from, NodeTree scope = newNode; //return newNode; } else if (name == "function") { - std::string functionName = concatSymbolTree(children[1]); + std::string functionName; + //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))); + scope->getDataRef()->scope[functionName].push_back(newNode); + newNode->getDataRef()->scope["~enclosing_scope"].push_back(scope); + return newNode; + } + functionName = concatSymbolTree(children[1]); newNode = new NodeTree(name, ASTData(function, Symbol(functionName, true), typeFromTypeNode(children[0], scope, templateTypeReplacements))); skipChildren.insert(0); skipChildren.insert(1); @@ -126,7 +135,7 @@ NodeTree* ASTTransformation::transform(NodeTree* from, NodeTree // newNode->addChildren(transChildren); // return newNode; - std::cout << "finished function " << functionName << std::endl; + std::cout << "finished function (kinda, not children) " << functionName << std::endl; } else if (name == "code_block") { newNode = new NodeTree(name, ASTData(code_block)); newNode->getDataRef()->scope["~enclosing_scope"].push_back(scope); @@ -134,10 +143,12 @@ NodeTree* ASTTransformation::transform(NodeTree* from, NodeTree } else if (name == "typed_parameter") { //newNode = transform(children[1]); //Transform to get the identifier 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))); scope->getDataRef()->scope[parameterName].push_back(newNode); newNode->getDataRef()->scope["~enclosing_scope"].push_back(scope); + std::cout << "Done doing typed_parameter " << parameterName << std::endl; return newNode; } else if (name == "boolean_expression" || name == "and_boolean_expression" || name == "bool_exp") { //If this is an actual part of an expression, not just a premoted term @@ -201,6 +212,9 @@ NodeTree* ASTTransformation::transform(NodeTree* from, NodeTree std::cout << "function call to " << functionCallName << " - " << function->getName() << " is now " << newNode->getDataRef()->valueType << std::endl; return newNode; //skipChildren.insert(1); + } else if (children.size() == 2) { + //Is template instantiation + return findOrInstantiateFunctionTemplate(children, scope, types, templateTypeReplacements); } else { return transform(children[0], scope, types, templateTypeReplacements); //Just a promoted child, so do it instead } @@ -294,10 +308,7 @@ NodeTree* ASTTransformation::transform(NodeTree* from, NodeTree } else if (name == "function_call") { std::string functionCallName = concatSymbolTree(children[0]); newNode = new NodeTree(functionCallName, ASTData(function_call, Symbol(functionCallName, true))); - // if (function == NULL) { - // std::cout << "scope lookup error! Could not find " << functionCallName << " in function_call " << std::endl; - // throw "LOOKUP ERROR: " + functionCallName; - // } + skipChildren.insert(0); std::vector*> transformedChildren = transformChildren(children, skipChildren, scope, types, templateTypeReplacements); std::cout << "scope lookup from function_call: " << functionCallName << std::endl; @@ -533,10 +544,16 @@ Type* ASTTransformation::typeFromTypeNode(NodeTree* typeNode, NodeTreeclone(); templateTypeReplacement->indirection += indirection; return templateTypeReplacement; + } else { + std::cout << edited << " was not found in templateTypeReplacements" << std::endl; + std::cout << "templateTypeReplacements consists of : "; + for (auto i : templateTypeReplacements) + std::cout << i.first << " "; + std::cout << std::endl; } //If not, we better instantiate it and then add it to the highest (not current) scope if (typeDefinition == NULL && typeNode->getChildren().size() > 1 && typeNode->getChildren()[1]->getData().getName() == "template_inst") { @@ -576,10 +593,53 @@ Type* ASTTransformation::typeFromTypeNode(NodeTree* typeNode, NodeTreeaddChildren(transformChildren(templateSyntaxTree->getChildren(), skipChildren, typeDefinition, std::vector(), newTemplateTypeReplacement)); std::cout << "Done instantating " << fullyInstantiatedName << " that had template parameter " << templateParameterName << " with " << replacementType->toString() << std::endl; } else { - std::cout << "Type: " << edited << " already instantiated!" << std::endl; + std::cout << "Type: " << edited << " already instantiated with " << typeDefinition << ", will be " << Type(baseType, typeDefinition, indirection).toString() << std::endl; } } Type* toReturn = new Type(baseType, typeDefinition, indirection); std::cout << "Returning type " << toReturn->toString() << std::endl; return toReturn; } + +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::string functionName = concatSymbolTree(children[0]); + std::string fullyInstantiatedName = functionName + concatSymbolTree(children[1]); + std::cout << "Looking for " << fullyInstantiatedName << std::endl; + NodeTree* instantiatedFunction = scopeLookup(scope, fullyInstantiatedName); + //If it already exists, return it + if (instantiatedFunction) + return instantiatedFunction; + + //Otherwise, we're going to instantiate it + //Find the template definition + NodeTree* templateDefinition = scopeLookup(scope,functionName); + NodeTree* templateSyntaxTree = templateDefinition->getDataRef()->valueType->templateDefinition; + std::string templateParameterName = concatSymbolTree(templateSyntaxTree->getChildren()[0]->getChildren()[1]); + std::map newTemplateTypeReplacement; + newTemplateTypeReplacement[templateParameterName] = typeFromTypeNode(children[1]->getChildren()[1], scope, templateTypeReplacements); + + std::vector*> templateChildren = templateSyntaxTree->getChildren(); + for (int i = 0; i < templateChildren.size(); i++) + 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))); + std::set skipChildren; + skipChildren.insert(0); + skipChildren.insert(1); + skipChildren.insert(2); + 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)); + + topScope->getDataRef()->scope[fullyInstantiatedName].push_back(instantiatedFunction); + topScope->addChild(instantiatedFunction); //Add this object the the highest scope's + + std::cout << "Fully Instantiated function " << functionName << " to " << fullyInstantiatedName << std::endl; + + return instantiatedFunction; +} + diff --git a/src/CGenerator.cpp b/src/CGenerator.cpp index bf146ae..e4ec64f 100644 --- a/src/CGenerator.cpp +++ b/src/CGenerator.cpp @@ -126,6 +126,8 @@ std::string CGenerator::generate(NodeTree* from, NodeTree* enc } case function: { + if (data.valueType->baseType == template_type) + return "/* template function: " + data.symbol.getName() + " */"; output += "\n" + ValueTypeToCType(data.valueType) + " "; std::string nameDecoration, parameters; for (int j = 0; j < children.size()-1; j++) { From 39f945940d9f0292f6e2318847179efcac5fc624 Mon Sep 17 00:00:00 2001 From: Nathan Braswell Date: Mon, 19 May 2014 20:00:35 -0400 Subject: [PATCH 11/37] Fixed a ton of stuff with function templates. Works well now. Next up: multiple template types and fixing object definition ordering (both where templates should go and objects with other pointers) --- include/Type.h | 14 +++++- krakenGrammer.kgm | 2 +- src/ASTTransformation.cpp | 83 ++++++++++++++++++++++++----------- src/CGenerator.cpp | 40 +++++++++-------- src/Importer.cpp | 9 +++- src/Type.cpp | 32 ++++++++++++++ stdlib/mem.krak | 32 ++++++++++++++ stdlib/trivial_container.krak | 9 ++++ 8 files changed, 174 insertions(+), 47 deletions(-) create mode 100644 stdlib/trivial_container.krak diff --git a/include/Type.h b/include/Type.h index ba5891f..f5aacdc 100644 --- a/include/Type.h +++ b/include/Type.h @@ -5,6 +5,10 @@ #define NULL ((void*)0) #endif +#ifndef SEGFAULT +#define SEGFAULT (*((char*)0)), std::cout << "\t\t\t\tNEGATIVE*************************************************************************" << std::endl; +#endif + #include #include @@ -13,7 +17,7 @@ class ASTData; #include "ASTData.h" #include "util.h" -enum ValueType {none, template_type, void_type, boolean, integer, floating, double_percision, character }; +enum ValueType {none, template_type, template_type_type, void_type, boolean, integer, floating, double_percision, character }; class Type { @@ -30,11 +34,17 @@ class Type { bool const operator!=(const Type &other)const; Type* clone(); std::string toString(); + int getIndirection(); + void setIndirection(int indirectionIn); + void increaseIndirection(); + void decreaseIndirection(); + void modifyIndirection(int mod); + void check(); ValueType baseType; NodeTree* typeDefinition; - int indirection; NodeTree* templateDefinition; private: + int indirection; }; #endif \ No newline at end of file diff --git a/krakenGrammer.kgm b/krakenGrammer.kgm index 4cc0d2a..bc0d40b 100644 --- a/krakenGrammer.kgm +++ b/krakenGrammer.kgm @@ -42,7 +42,7 @@ opt_parameter_list = parameter_list | ; 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 "}" ; +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 ; diff --git a/src/ASTTransformation.cpp b/src/ASTTransformation.cpp index 00f4605..eca685e 100644 --- a/src/ASTTransformation.cpp +++ b/src/ASTTransformation.cpp @@ -8,6 +8,8 @@ ASTTransformation::ASTTransformation(Importer *importerIn) { languageLevelScope["+"].push_back( new NodeTree("function", ASTData(function, Symbol("+", true), NULL))); languageLevelScope["-"].push_back(new NodeTree("function", ASTData(function, Symbol("-", true), NULL))); languageLevelScope["*"].push_back(new NodeTree("function", ASTData(function, Symbol("*", true), NULL))); + languageLevelScope["/"].push_back(new NodeTree("function", ASTData(function, Symbol("/", true), NULL))); + languageLevelScope["%"].push_back(new NodeTree("function", ASTData(function, Symbol("%", true), NULL))); languageLevelScope["&"].push_back(new NodeTree("function", ASTData(function, Symbol("&", true), NULL))); languageLevelScope["--"].push_back(new NodeTree("function", ASTData(function, Symbol("--", true), NULL))); languageLevelScope["++"].push_back(new NodeTree("function", ASTData(function, Symbol("++", true), NULL))); @@ -117,6 +119,18 @@ NodeTree* ASTTransformation::transform(NodeTree* from, NodeTree newNode = new NodeTree(name, ASTData(function, Symbol(functionName, true), new Type(template_type, from))); scope->getDataRef()->scope[functionName].push_back(newNode); 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 + + 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() << "|| "; + std::cout << "??||" << std::endl; + newNode->addChildren(transChildren); + + std::cout << "Finished Non-Instantiated Template function " << functionName << std::endl; return newNode; } functionName = concatSymbolTree(children[1]); @@ -188,28 +202,18 @@ NodeTree* ASTTransformation::transform(NodeTree* from, NodeTree std::string functionCallName = concatSymbolTree(children[1]); //std::cout << "scope lookup from expression or similar" << std::endl; std::vector*> transformedChildren; transformedChildren.push_back(lhs); transformedChildren.push_back(rhs); - NodeTree* function = doFunction(scope, functionCallName, transformedChildren, templateTypeReplacements); - if (function == NULL) { + newNode = doFunction(scope, functionCallName, transformedChildren, templateTypeReplacements); + if (newNode == NULL) { std::cout << "scope lookup error! Could not find " << functionCallName << " in expression " << std::endl; throw "LOOKUP ERROR: " + functionCallName; } - newNode = function; - // newNode = new NodeTree(functionCallName, ASTData(function_call, Symbol(functionCallName, true))); - // newNode->addChild(function); // First child of function call is a link to the function definition - // newNode->addChild(lhs); - // newNode->addChild(rhs); - // if (name == "access_operation") - // std::cout << "Access Operation: " << lhs->getDataRef()->symbol.getName() << " : " << rhs->getDataRef()->symbol.getName() << std::endl; - // std::cout << functionCallName << " - " << function->getName() << " has value type " << function->getDataRef()->valueType << " and rhs " << rhs->getDataRef()->valueType << std::endl; // //Set the value of this function call - if (function->getDataRef()->valueType) - newNode->getDataRef()->valueType = function->getDataRef()->valueType; - else if (rhs->getDataRef()->valueType) + if (newNode->getDataRef()->valueType == NULL && rhs->getDataRef()->valueType) newNode->getDataRef()->valueType = rhs->getDataRef()->valueType; else newNode->getDataRef()->valueType = NULL; - std::cout << "function call to " << functionCallName << " - " << function->getName() << " is now " << newNode->getDataRef()->valueType << std::endl; + std::cout << "function call to " << functionCallName << " - " << newNode->getName() << " is now " << newNode->getDataRef()->valueType << std::endl; return newNode; //skipChildren.insert(1); } else if (children.size() == 2) { @@ -444,9 +448,13 @@ NodeTree* ASTTransformation::doFunction(NodeTree* scope, std:: std::cout< oldTypes = mapNodesToTypes(nodes); - if (lookup == "*" || lookup == "&" || lookup == "[]") { + if ((nodes.size() != 2 && lookup == "*") || lookup == "&" || lookup == "[]") { Type* newType = oldTypes[0].clone(); - lookup == "*" || lookup == "[]" ? newType->indirection-- : newType->indirection++; + if (lookup == "*" || lookup == "[]") + newType->increaseIndirection(); + else + newType->decreaseIndirection(); + newNode->getDataRef()->valueType = newType, std::cout << "Operator " + lookup << " is altering indirection "<< std::endl; } else { newNode->getDataRef()->valueType = function->getDataRef()->valueType, std::cout << "Some other ||" << lookup << "||" << std::endl; @@ -475,7 +483,9 @@ NodeTree* ASTTransformation::scopeLookup(NodeTree* scope, std: return *i; std::vector*> children = (*i)->getChildren(); - if (types.size() != ((children.size() > 0) ? children.size()-1 : 0)) { + //We subtract one from the children to get the type size only if there is at least one child AND this function is not a + //non-instantiated template (which would not have a body node, which is why we subtract one) + if (types.size() != ((children.size() > 0 && (*i)->getDataRef()->valueType->baseType != template_type ) ? children.size()-1 : children.size())) { std::cout << "Type sizes do not match between two " << lookup << "(" << types.size() << "," << ((children.size() > 0) ? children.size()-1 : 0) << "), types are: "; for (auto j : types) std::cout << j.toString() << " "; @@ -484,9 +494,12 @@ NodeTree* ASTTransformation::scopeLookup(NodeTree* scope, std: } bool typesMatch = true; for (int j = 0; j < types.size(); j++) { - if (types[j] != *(children[j]->getDataRef()->valueType)) { + Type* tmpType = children[j]->getDataRef()->valueType; + //Don't worry if types don't match if it's a template type + if (types[j] != *tmpType && tmpType->baseType != template_type_type) { typesMatch = false; - std::cout << "Types do not match between two " << lookup << " " << types[j].toString() << " vs " << children[j]->getDataRef()->valueType->toString() << std::endl; + std::cout << "Types do not match between two " << lookup << " " << types[j].toString(); + std::cout << " vs " << children[j]->getDataRef()->valueType->toString() << std::endl; break; } } @@ -546,7 +559,7 @@ Type* ASTTransformation::typeFromTypeNode(NodeTree* typeNode, NodeTreeclone(); - templateTypeReplacement->indirection += indirection; + templateTypeReplacement->modifyIndirection(indirection); return templateTypeReplacement; } else { std::cout << edited << " was not found in templateTypeReplacements" << std::endl; @@ -592,6 +605,9 @@ Type* ASTTransformation::typeFromTypeNode(NodeTree* typeNode, NodeTreeaddChildren(transformChildren(templateSyntaxTree->getChildren(), skipChildren, typeDefinition, std::vector(), newTemplateTypeReplacement)); 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; + return NULL; } else { std::cout << "Type: " << edited << " already instantiated with " << typeDefinition << ", will be " << Type(baseType, typeDefinition, indirection).toString() << std::endl; } @@ -605,20 +621,37 @@ NodeTree* ASTTransformation::findOrInstantiateFunctionTemplate(std::vec //First look to see if we can find this already instantiated std::cout << "Finding or instantiating templated function" << std::endl; std::string functionName = concatSymbolTree(children[0]); - std::string fullyInstantiatedName = functionName + concatSymbolTree(children[1]); + Type* templateActualType = typeFromTypeNode(children[1]->getChildren()[1], scope, templateTypeReplacements); + std::string fullyInstantiatedName = functionName + "<" + templateActualType->toString() + ">"; std::cout << "Looking for " << fullyInstantiatedName << std::endl; - NodeTree* instantiatedFunction = scopeLookup(scope, fullyInstantiatedName); + + std::cout << "Types are : "; + for (auto i : types) + std::cout << " " << i.toString(); + std::cout << std::endl; + + NodeTree* instantiatedFunction = scopeLookup(scope, fullyInstantiatedName,types); //If it already exists, return it - if (instantiatedFunction) + if (instantiatedFunction) { + std::cout << fullyInstantiatedName << " already exists! Returning" << std::endl; return instantiatedFunction; + } else { + std::cout << fullyInstantiatedName << " does NOT exist" << std::endl; + } //Otherwise, we're going to instantiate it //Find the template definition - NodeTree* templateDefinition = scopeLookup(scope,functionName); + NodeTree* templateDefinition = scopeLookup(scope,functionName,types); + if (templateDefinition == NULL) { + std::cout << functionName << " search turned up null, returing null" << std::endl; + return NULL; + } + NodeTree* templateSyntaxTree = templateDefinition->getDataRef()->valueType->templateDefinition; std::string templateParameterName = concatSymbolTree(templateSyntaxTree->getChildren()[0]->getChildren()[1]); + std::map newTemplateTypeReplacement; - newTemplateTypeReplacement[templateParameterName] = typeFromTypeNode(children[1]->getChildren()[1], scope, templateTypeReplacements); + newTemplateTypeReplacement[templateParameterName] = templateActualType; std::vector*> templateChildren = templateSyntaxTree->getChildren(); for (int i = 0; i < templateChildren.size(); i++) diff --git a/src/CGenerator.cpp b/src/CGenerator.cpp index e4ec64f..c34fe4e 100644 --- a/src/CGenerator.cpp +++ b/src/CGenerator.cpp @@ -58,21 +58,23 @@ std::string CGenerator::generate(NodeTree* from, NodeTree* enc break; case function: { - if (decChildren.size() == 0) { //Not a real function, must be a built in passthrough { - output += "/* built in function: " + declarationData.toString() + " */\n"; - break; + 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"; + else { + output += "\n" + ValueTypeToCType(declarationData.valueType) + " "; + std::string nameDecoration, parameters; + for (int j = 0; j < decChildren.size()-1; j++) { + if (j > 0) + parameters += ", "; + 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 += "\n" + ValueTypeToCType(declarationData.valueType) + " "; - std::string nameDecoration, parameters; - for (int j = 0; j < decChildren.size()-1; j++) { - if (j > 0) - parameters += ", "; - 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"; - break; } + break; case type_def: //type output += "/*typedef " + declarationData.symbol.getName() + " */\n"; @@ -114,13 +116,15 @@ std::string CGenerator::generate(NodeTree* from, NodeTree* enc } else { std::string objectString = "typedef struct __struct_dummy_" + CifyName(data.symbol.getName()) + "__ {\n"; std::string postString; //The functions have to be outside the struct definition + tabLevel++; for (int i = 0; i < children.size(); i++) { std::cout << children[i]->getName() << std::endl; if (children[i]->getName() == "function") //If object method postString += generateObjectMethod(from, children[i]) + "\n"; else - objectString += generate(children[i], enclosingObject) + "\n"; + objectString += tabs() + generate(children[i], enclosingObject) + "\n"; } + tabLevel--; objectString += "} " + CifyName(data.symbol.getName()) + ";"; return objectString + postString; //Functions come after the declaration of the struct } @@ -202,7 +206,7 @@ std::string CGenerator::generate(NodeTree* from, NodeTree* enc if (funcType == function) { if (name == "++" || name == "--") return generate(children[1], enclosingObject) + name; - if (name == "*" || name == "&" && children.size() == 2) //Is dereference, not multiplication, or address-of + if ( (name == "*" || name == "&") && children.size() == 2) //Is dereference, not multiplication, or address-of return name + "(" + generate(children[1], enclosingObject) + ")"; if (name == "[]") return "(" + generate(children[1], enclosingObject) + ")[" +generate(children[2],enclosingObject) + "]"; @@ -283,7 +287,7 @@ std::string CGenerator::generateObjectMethod(NodeTree* enclosingObject, std::string output; ASTData data = from->getData(); Type enclosingObjectType = *(enclosingObject->getDataRef()->valueType); //Copy a new type so we can turn it into a pointer if we need to - enclosingObjectType.indirection++; + enclosingObjectType.increaseIndirection(); std::vector*> children = from->getChildren(); std::string nameDecoration, parameters; for (int i = 0; i < children.size()-1; i++) { @@ -327,7 +331,7 @@ std::string CGenerator::ValueTypeToCType(Type *type) { return_type = "unknown_ValueType"; break; } - for (int i = 0; i < type->indirection; i++) + for (int i = 0; i < type->getIndirection(); i++) return_type += "*"; return return_type; } @@ -363,7 +367,7 @@ std::string CGenerator::ValueTypeToCTypeDecoration(Type *type) { return_type = "unknown_ValueType"; break; } - for (int i = 0; i < type->indirection; i++) + for (int i = 0; i < type->getIndirection(); i++) return_type += "_P__"; return return_type; } diff --git a/src/Importer.cpp b/src/Importer.cpp index db04e72..5539516 100644 --- a/src/Importer.cpp +++ b/src/Importer.cpp @@ -40,9 +40,14 @@ Importer::~Importer() { } NodeTree* Importer::import(std::string fileName) { + + std::cout << "\n\nImporting " << fileName << " "; //Check to see if we've already done it - if (imported.find(fileName) != imported.end()) + if (imported.find(fileName) != imported.end()) { + std::cout << "Already Imported!" << std::endl; return imported[fileName]; + } + std::cout << "Not yet imported" << std::endl; std::ifstream programInFile; std::ofstream outFile, outFileTransformed, outFileAST; @@ -126,6 +131,8 @@ NodeTree* Importer::import(std::string fileName) { imported[fileName] = AST; + std::cout << "Done importing " << fileName << "\n\n" << std::endl; + return AST; } diff --git a/src/Type.cpp b/src/Type.cpp index a87aa03..1114777 100644 --- a/src/Type.cpp +++ b/src/Type.cpp @@ -19,6 +19,7 @@ Type::Type(ValueType typeIn, int indirectionIn) { baseType = typeIn; typeDefinition = NULL; templateDefinition = NULL; + if (indirection < 0) SEGFAULT } Type::Type(NodeTree* typeDefinitionIn) { @@ -32,6 +33,7 @@ Type::Type(NodeTree* typeDefinitionIn, int indirectionIn) { baseType = none; typeDefinition = typeDefinitionIn; templateDefinition = NULL; + if (indirection < 0) SEGFAULT } Type::Type(ValueType typeIn, NodeTree* typeDefinitionIn, int indirectionIn) { @@ -39,6 +41,7 @@ Type::Type(ValueType typeIn, NodeTree* typeDefinitionIn, int indirectio indirection = indirectionIn; typeDefinition = typeDefinitionIn; templateDefinition = NULL; + if (indirection < 0) SEGFAULT } Type::Type(ValueType typeIn, NodeTree* templateDefinitionIn) { indirection = 0; @@ -70,6 +73,10 @@ std::string Type::toString() { break; case template_type: typeString = "template: " + templateDefinition->getDataRef()->toString(); + break; + case template_type_type: + typeString = "template_type_type"; + break; case void_type: typeString = "void"; break; @@ -96,9 +103,34 @@ std::string Type::toString() { } for (int i = 0; i < indirection; i++) typeString += "*"; + //std::cout << "Extra components of " << typeString << " are " << indirection << " " << typeDefinition << " " << templateDefinition << std::endl; return typeString; } Type* Type::clone() { return new Type(baseType, typeDefinition, indirection); } + +void Type::check() { + if (indirection < 0) SEGFAULT +} + +int Type::getIndirection() { + return indirection; +} + +void Type::setIndirection(int indirectionIn) { + indirection = indirectionIn; + check(); +} + +void Type::increaseIndirection() { + setIndirection(indirection+1); +} +void Type::decreaseIndirection() { + setIndirection(indirection-1); +} + +void Type::modifyIndirection(int mod) { + setIndirection(indirection + mod); +} diff --git a/stdlib/mem.krak b/stdlib/mem.krak index e4dafa2..0e9bef1 100644 --- a/stdlib/mem.krak +++ b/stdlib/mem.krak @@ -21,3 +21,35 @@ void free(char* memPtr) { """ } } + +template void free(T* memPtr) { + __if_comp__ __C__ { + __simple_passthrough__ """ + free(memPtr); + """ + } +} + +template int sizeof() { + int result = 0; + T testObj; + __if_comp__ __C__ { + __simple_passthrough__ """ + result = sizeof(testObj); + """ + } + return result; +} + + +template T* new(int count) { + return malloc( sizeof() * count ); +} + +template T* new() { + return new(1); +} + +template void delete(T* toDelete) { + free(toDelete); +} diff --git a/stdlib/trivial_container.krak b/stdlib/trivial_container.krak new file mode 100644 index 0000000..341c4d2 --- /dev/null +++ b/stdlib/trivial_container.krak @@ -0,0 +1,9 @@ +import io; + +typedef template trivialContainer { + T data; + void print() { + print(data); + } +}; + From 2566cbb67c15dea3f03401aff1d7f6099142c942 Mon Sep 17 00:00:00 2001 From: Nathan Braswell Date: Tue, 20 May 2014 22:21:07 -0400 Subject: [PATCH 12/37] Added testing! call kraken like so ./kraken --test ../path/to/test/name_of_test_without_extention This will make kraken compile and run name_of_test_without_extention.krak and compare the output it generates on stdout to name_of_test_without_extention.expected_results. If they pass, then it records the pass, if not, it records the failure and saves the intermediate files generated. It has revealed some bugs which I will fix in upcoming commits. --- CMakeLists.txt | 2 +- include/Tester.h | 31 +++++++++ include/util.h | 5 ++ main.cpp | 20 +++++- src/Tester.cpp | 69 ++++++++++++++++++++ src/util.cpp | 9 +++ tests/OperatorOverloadTest.expected_results | 5 ++ tests/OperatorOverloadTest.krak | 64 ++++++++++++++++++ tests/RecursiveTest.expected_results | 1 + tests/RecursiveTest.krak | 14 ++++ tests/functionTemplateTest.expected_results | 1 + tests/functionTemplateTest.krak | 14 ++++ tests/memTest.expected_results | 3 + tests/memTest.krak | 27 ++++++++ tests/moreComplexObjectTest.expected_results | 2 + tests/moreComplexObjectTest.krak | 29 ++++++++ tests/objectOrderingTest.expected_results | 1 + tests/objectOrderingTest.krak | 27 ++++++++ tests/simpleFunctionTest.expected_results | 1 + tests/simpleFunctionTest.krak | 14 ++++ tests/simpleObjectTest.expected_results | 1 + tests/simpleObjectTest.krak | 18 +++++ tests/templateTest.expected_results | 8 +++ tests/templateTest.krak | 52 +++++++++++++++ tests/testArrayNotation.expected_results | 1 + tests/testArrayNotation.krak | 13 ++++ 26 files changed, 430 insertions(+), 2 deletions(-) create mode 100644 include/Tester.h create mode 100644 src/Tester.cpp create mode 100644 tests/OperatorOverloadTest.expected_results create mode 100644 tests/OperatorOverloadTest.krak create mode 100644 tests/RecursiveTest.expected_results create mode 100644 tests/RecursiveTest.krak create mode 100644 tests/functionTemplateTest.expected_results create mode 100644 tests/functionTemplateTest.krak create mode 100644 tests/memTest.expected_results create mode 100644 tests/memTest.krak create mode 100644 tests/moreComplexObjectTest.expected_results create mode 100644 tests/moreComplexObjectTest.krak create mode 100644 tests/objectOrderingTest.expected_results create mode 100644 tests/objectOrderingTest.krak create mode 100644 tests/simpleFunctionTest.expected_results create mode 100644 tests/simpleFunctionTest.krak create mode 100644 tests/simpleObjectTest.expected_results create mode 100644 tests/simpleObjectTest.krak create mode 100644 tests/templateTest.expected_results create mode 100644 tests/templateTest.krak create mode 100644 tests/testArrayNotation.expected_results create mode 100644 tests/testArrayNotation.krak diff --git a/CMakeLists.txt b/CMakeLists.txt index 48b80aa..ab50798 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,7 +6,7 @@ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") set( MY_INCLUDES ${PROJECT_SOURCE_DIR}/include) -set( MY_SOURCES main.cpp src/Parser.cpp src/LALRParser.cpp src/GraphStructuredStack.cpp src/RNGLRParser.cpp src/ParseAction.cpp src/ParseRule.cpp src/Symbol.cpp src/StringReader.cpp src/State.cpp src/util.cpp src/Lexer.cpp src/RegEx.cpp src/RegExState.cpp src/Table.cpp src/ASTData.cpp src/ASTTransformation.cpp src/CGenerator.cpp src/Type.cpp src/Importer.cpp ) +set( MY_SOURCES main.cpp src/Parser.cpp src/LALRParser.cpp src/GraphStructuredStack.cpp src/RNGLRParser.cpp src/ParseAction.cpp src/ParseRule.cpp src/Symbol.cpp src/StringReader.cpp src/State.cpp src/util.cpp src/Lexer.cpp src/RegEx.cpp src/RegExState.cpp src/Table.cpp src/ASTData.cpp src/ASTTransformation.cpp src/CGenerator.cpp src/Type.cpp src/Importer.cpp src/Tester.cpp ) add_custom_target(STDLibCopy ALL) add_custom_command(TARGET STDLibCopy POST_BUILD diff --git a/include/Tester.h b/include/Tester.h new file mode 100644 index 0000000..7bf1815 --- /dev/null +++ b/include/Tester.h @@ -0,0 +1,31 @@ +#include +#include + +#include + +#include "util.h" + +#ifndef TESTER_H +#define TESTER_H + +class Tester { + public: + Tester(std::string krakenInvocation, std::string krakenGrammerLocation); + ~Tester(); + int ssystem(std::string command); + bool run(std::string fileName); + bool compareFiles(std::string file1Path, std::string file2Path); + void cleanExtras(std::string fileName); + + private: + std::string krakenInvocation; + std::string krakenGrammerLocation; + std::string removeCmd; + std::string resultsExtention; + std::string expectedExtention; + std::string krakenExtention; + std::string shell; + std::string changePermissions; + std::string redirect; +}; +#endif diff --git a/include/util.h b/include/util.h index 7f17f51..87edef2 100644 --- a/include/util.h +++ b/include/util.h @@ -9,6 +9,8 @@ #include #include #include +#include +#include std::string intToString(int theInt); std::string replaceExEscape(std::string first, std::string search, std::string replace); @@ -16,6 +18,9 @@ std::string strSlice(std::string str, int begin, int end); int findPerenEnd(std::string str, int i); std::vector split(const std::string &str, char delim); std::string join(const std::vector &strVec, std::string joinStr); +std::string readFile(std::istream &file); + + template bool contains(std::vector vec, T item) { for (auto i : vec) diff --git a/main.cpp b/main.cpp index 06d6e61..ace2966 100644 --- a/main.cpp +++ b/main.cpp @@ -16,16 +16,34 @@ #include "CGenerator.h" #include "util.h" +#include "Tester.h" int main(int argc, char* argv[]) { std::vector includePaths; includePaths.push_back(""); //Local - if (argc == 2 && std::string(argv[1]) == "--test") { + if (argc >= 2 && std::string(argv[1]) == "--test") { StringReader::test(); RegEx::test(); Lexer::test(); //std::cout << strSlice("123", 0, -1) << std::endl; + if (argc >= 3) { + std::string testResults, line; + int passed = 0, failed = 0; + Tester test(argv[0], "../krakenGrammer.kgm"); + for (int i = 2; i < argc; i++) { + bool result = test.run(argv[i]); + if (result) + line = std::string(argv[i]) + "\t\tpassed!\n", passed++; + else + line = std::string(argv[i]) + "\t\tFAILED!\n", failed++; + std::cout << line << std::endl; + testResults += line; + } + std::cout << "===========Done Testing===========" << std::endl; + std::cout << testResults << std::endl; + std::cout << "Test results: " << passed << "/" << passed+failed << std::endl; + } return 0; } std::string krakenDir = argv[0]; diff --git a/src/Tester.cpp b/src/Tester.cpp new file mode 100644 index 0000000..3f4cbdf --- /dev/null +++ b/src/Tester.cpp @@ -0,0 +1,69 @@ +#include "Tester.h" + +Tester::Tester(std::string krakenInvocation, std::string krakenGrammerLocation) : krakenInvocation(krakenInvocation), krakenGrammerLocation(krakenGrammerLocation) { + //initlization list + removeCmd = "rm"; + resultsExtention = ".results"; + expectedExtention = ".expected_results"; + krakenExtention = ".krak"; + changePermissions = "chmod 755"; + shell = "sh"; + redirect = ">"; +} + +Tester::~Tester() { + //Nothing +} + +int Tester::ssystem(std::string command) { + return system(command.c_str()); +} + +void Tester::cleanExtras(std::string fileName) { + ssystem(removeCmd + " " + fileName); + ssystem(removeCmd + " " + fileName + krakenExtention + "out*"); + ssystem(removeCmd + " " + fileName + krakenExtention + ".c"); + ssystem(removeCmd + " " + fileName + ".sh"); + ssystem(removeCmd + " " + fileName + resultsExtention); +} + +bool Tester::run(std::string fileName) { + std::cout << "Testing: " << fileName << " with " << krakenInvocation << " and " << krakenGrammerLocation << std::endl; + + cleanExtras(fileName); + + ssystem(changePermissions + " " + fileName); + ssystem(krakenInvocation + " " + fileName + krakenExtention + " " + krakenGrammerLocation + " " + fileName); + ssystem(shell + " " + fileName + ".sh"); + ssystem(fileName + " " + redirect + " " + fileName + resultsExtention); + + bool result = compareFiles(fileName + expectedExtention, fileName + resultsExtention); + + //If the test was succesful, we don't need all the extra files + if (result) + cleanExtras(fileName); + + return result; +} + +bool Tester::compareFiles(std::string file1Path, std::string file2Path) { + std::ifstream file1, file2; + file1.open(file1Path); + if (!file1.is_open()) { + std::cout << file1Path << " could not be opened!" << std::endl; + return false; + } + file2.open(file2Path); + if (!file2.is_open()) { + std::cout << file2Path << " could not be opened!" << std::endl; + return false; + } + + std::string file1contents = readFile(file1); + std::string file2contents = readFile(file2); + + // std::cout << "file1: " << file1contents << std::endl; + // std::cout << "file2: " << file2contents << std::endl; + // std::cout << "comp: " << file1contents.compare(file2contents) << std::endl; + return file1contents.compare(file2contents) == 0; +} diff --git a/src/util.cpp b/src/util.cpp index a3c7802..296807e 100644 --- a/src/util.cpp +++ b/src/util.cpp @@ -71,4 +71,13 @@ std::string join(const std::vector &strVec, std::string joinStr) { return joinedStr; } +std::string readFile(std::istream &file) { + std::string line, contents; + while(file.good()) { + getline(file, line); + contents.append(line+"\n"); + } + return contents; +} + diff --git a/tests/OperatorOverloadTest.expected_results b/tests/OperatorOverloadTest.expected_results new file mode 100644 index 0000000..78b0a52 --- /dev/null +++ b/tests/OperatorOverloadTest.expected_results @@ -0,0 +1,5 @@ +3 9 +6 18 +Subtraction +3 9 +-97 -61 diff --git a/tests/OperatorOverloadTest.krak b/tests/OperatorOverloadTest.krak new file mode 100644 index 0000000..2362187 --- /dev/null +++ b/tests/OperatorOverloadTest.krak @@ -0,0 +1,64 @@ +import io; + +typedef Vec2 { + int x; + int y; + + void print() { + print(x); + print(" "); + print(y); + } + + Vec2 add(Vec2 other) { + Vec2 toReturn; + toReturn.x = x + other.x; + toReturn.y = y + other.y; + print(); + return toReturn; + } + + Vec2 subtract(Vec2 other) { + Vec2 toReturn; + toReturn.x = x - other.x; + toReturn.y = y - other.y; + print(); + return toReturn; + } + + Vec2 operator+(Vec2 other) { + return add(other); + } + +}; + +Vec2 operator-(Vec2 lhs, Vec2 rhs) { + return lhs.subtract(rhs); +} + +int main() { + Vec2 vector1; + Vec2 vector2; + vector1.x = 3; + vector1.y = 9; + vector2 = vector1; + /* NOTE COMMENT + Vec2 vector3; + vector3.x = vector1.x + vector2.x; + vector3.y = vector1.y + vector2.y; + vector2.print(); + */ + Vec2 addition = vector1 + vector2; + print("\n"); + addition.print(); + print("\nSubtraction\n"); + vector2.x = 100; + vector2.y = 70; + Vec2 subtraction = vector1 - vector2; + print("\n"); + print(subtraction.x); print(" "); print(subtraction.y); + + print("\n"); + + return 0; +} diff --git a/tests/RecursiveTest.expected_results b/tests/RecursiveTest.expected_results new file mode 100644 index 0000000..7ed6ff8 --- /dev/null +++ b/tests/RecursiveTest.expected_results @@ -0,0 +1 @@ +5 diff --git a/tests/RecursiveTest.krak b/tests/RecursiveTest.krak new file mode 100644 index 0000000..4e61ccc --- /dev/null +++ b/tests/RecursiveTest.krak @@ -0,0 +1,14 @@ +import io; + +int fibanacci(int num) { + if (num < 2) + return 1; + return fibanacci(num-1) + fibanacci(num-2); +} + +int main() { + print(fibanacci(4)); + print("\n"); + return 0; +} + diff --git a/tests/functionTemplateTest.expected_results b/tests/functionTemplateTest.expected_results new file mode 100644 index 0000000..2bd5a0a --- /dev/null +++ b/tests/functionTemplateTest.expected_results @@ -0,0 +1 @@ +22 diff --git a/tests/functionTemplateTest.krak b/tests/functionTemplateTest.krak new file mode 100644 index 0000000..dd51c3d --- /dev/null +++ b/tests/functionTemplateTest.krak @@ -0,0 +1,14 @@ +import io; + +template T addAndPrint(T a, T b) { + print(a+b); + return a+b; +} + +int main() { + + addAndPrint(10,12); + print("\n"); + + return 0; +} \ No newline at end of file diff --git a/tests/memTest.expected_results b/tests/memTest.expected_results new file mode 100644 index 0000000..abd8421 --- /dev/null +++ b/tests/memTest.expected_results @@ -0,0 +1,3 @@ +11 +Hello decent memory! Quite a nice feeling + diff --git a/tests/memTest.krak b/tests/memTest.krak new file mode 100644 index 0000000..44acd40 --- /dev/null +++ b/tests/memTest.krak @@ -0,0 +1,27 @@ +import mem; +import io; + +typedef AnObject { + int a; + int b; + char* c; + + void print() { + print(a+b); + print("\n"); + print(c); + print("\n"); + } +}; + + +int main() { + AnObject* ptr = new(); + ptr->a = 4; + ptr->b = 7; + ptr->c = "Hello decent memory! Quite a nice feeling\n"; + ptr->print(); + delete(ptr); + + return 0; +} \ No newline at end of file diff --git a/tests/moreComplexObjectTest.expected_results b/tests/moreComplexObjectTest.expected_results new file mode 100644 index 0000000..8b751d2 --- /dev/null +++ b/tests/moreComplexObjectTest.expected_results @@ -0,0 +1,2 @@ +742 +1337 diff --git a/tests/moreComplexObjectTest.krak b/tests/moreComplexObjectTest.krak new file mode 100644 index 0000000..8da7762 --- /dev/null +++ b/tests/moreComplexObjectTest.krak @@ -0,0 +1,29 @@ +import io; + +typedef firstObject { + int objectNum; + int other; + void print() { + print(other); + } + void printInd() { + print(); + } +}; + +typedef Int int; + +Int aliasNum; + +int main() { + firstObject wooObject; + wooObject.objectNum = 7; + print(wooObject.objectNum); + firstObject* objPtr = &wooObject; + objPtr->objectNum = 42; + print(objPtr->objectNum); + print("\n"); + objPtr->other = 1337; + objPtr->printInd(); + print("\n"); +} diff --git a/tests/objectOrderingTest.expected_results b/tests/objectOrderingTest.expected_results new file mode 100644 index 0000000..48082f7 --- /dev/null +++ b/tests/objectOrderingTest.expected_results @@ -0,0 +1 @@ +12 diff --git a/tests/objectOrderingTest.krak b/tests/objectOrderingTest.krak new file mode 100644 index 0000000..80a96cb --- /dev/null +++ b/tests/objectOrderingTest.krak @@ -0,0 +1,27 @@ +import io; + +typedef objectA { + int a; +}; + +typedef BigObject { + objectA a; + objectB b; + int add() { + return a.a + b.b; + } +}; + +typedef objectB { + int b; +}; + + +int main() { + BigObject c; + c.a.a = 4; + c.b.b = 8; + print(c.add()); + print("\n"); + return 0; +} diff --git a/tests/simpleFunctionTest.expected_results b/tests/simpleFunctionTest.expected_results new file mode 100644 index 0000000..635328e --- /dev/null +++ b/tests/simpleFunctionTest.expected_results @@ -0,0 +1 @@ +1919 diff --git a/tests/simpleFunctionTest.krak b/tests/simpleFunctionTest.krak new file mode 100644 index 0000000..c78e629 --- /dev/null +++ b/tests/simpleFunctionTest.krak @@ -0,0 +1,14 @@ +import io; + +int addAndPrintInt(int a, int b) { + print(a+b); + return a+b; +} + +int main() { + + print(addAndPrintInt(7,12)); + print("\n"); + + return 0; +} \ No newline at end of file diff --git a/tests/simpleObjectTest.expected_results b/tests/simpleObjectTest.expected_results new file mode 100644 index 0000000..e1617e8 --- /dev/null +++ b/tests/simpleObjectTest.expected_results @@ -0,0 +1 @@ +57 diff --git a/tests/simpleObjectTest.krak b/tests/simpleObjectTest.krak new file mode 100644 index 0000000..9a96ac5 --- /dev/null +++ b/tests/simpleObjectTest.krak @@ -0,0 +1,18 @@ + +import io; + +typedef FirstObject { + int objectNum; + void PrintSelf(int a) { + print(objectNum); + print(a); + } +}; + +int main() { + FirstObject wooObject; + wooObject.objectNum = 5; + wooObject.PrintSelf(7); + print("\n"); + return 0; +} diff --git a/tests/templateTest.expected_results b/tests/templateTest.expected_results new file mode 100644 index 0000000..15fa1a4 --- /dev/null +++ b/tests/templateTest.expected_results @@ -0,0 +1,8 @@ +a: 5 +b: 7 +1337 +a: 9 +b: Hello Templates! +Woooo nesting! +From another file! Whoh! +1919 diff --git a/tests/templateTest.krak b/tests/templateTest.krak new file mode 100644 index 0000000..a755ce2 --- /dev/null +++ b/tests/templateTest.krak @@ -0,0 +1,52 @@ +import io; +import trivial_container; + +typedef template TemplateTest { + int a; + T b; + trivialContainer c; + void print() { + print("a: "); + print(a); + print("\n"); + print("b: "); + print(b); + print("\n"); + c.print(); + print("\n"); + } +}; + +typedef MyInt int; + +MyInt c; + + +template T addAndPrint(T a, T b) { + print(a+b); + return a+b; +} + +int main() { + TemplateTest test; + TemplateTest test2; + test.a = 5; + test.b = 7; + test.c.data = 1337; + test2.a = 9; + test2.b = "Hello Templates!"; + test2.c.data = "Woooo nesting!"; + + test.print(); + test2.print(); + + trivialContainer testImport; + testImport.data = "From another file! Whoh!"; + testImport.print(); + print("\n"); + + print(addAndPrint(7,12)); + print("\n"); + + return 0; +} \ No newline at end of file diff --git a/tests/testArrayNotation.expected_results b/tests/testArrayNotation.expected_results new file mode 100644 index 0000000..6e68a0f --- /dev/null +++ b/tests/testArrayNotation.expected_results @@ -0,0 +1 @@ +777 diff --git a/tests/testArrayNotation.krak b/tests/testArrayNotation.krak new file mode 100644 index 0000000..9d4a0d9 --- /dev/null +++ b/tests/testArrayNotation.krak @@ -0,0 +1,13 @@ +import io; +import mem; + +int main() { + int b; + int* a = &b; + a [ 0 ] = 7; + print(a [ 0 ] ); + print(*a); + print(b); + print("\n"); + return 0; +} From 17b80d4102b7d3df92b97f5fe711d1a500eecbca Mon Sep 17 00:00:00 2001 From: Nathan Braswell Date: Tue, 20 May 2014 23:53:19 -0400 Subject: [PATCH 13/37] Fixed a typo that caused indirection operators to do the reverse on types. Also cleaned up some comments. One more test working. --- main.cpp | 41 +++++---------------------------------- src/ASTTransformation.cpp | 11 ++--------- 2 files changed, 7 insertions(+), 45 deletions(-) diff --git a/main.cpp b/main.cpp index ace2966..4f6f8b7 100644 --- a/main.cpp +++ b/main.cpp @@ -48,13 +48,13 @@ int main(int argc, char* argv[]) { } std::string krakenDir = argv[0]; krakenDir = strSlice(krakenDir, 0, -(std::string("kraken").length()+1)); - includePaths.push_back(krakenDir + "stdlib/"); + includePaths.push_back(krakenDir + "stdlib/"); //Add the stdlib directory that exists in the same directory as the kraken executable to the path std::string programName = argv[1]; std::string grammerFileString = argv[2]; std::string outputName = argv[3]; std::ifstream grammerInFile, compiledGrammerInFile; - std::ofstream /*outFileC,*/ compiledGrammerOutFile; + std::ofstream compiledGrammerOutFile; grammerInFile.open(grammerFileString); if (!grammerInFile.is_open()) { @@ -63,17 +63,9 @@ int main(int argc, char* argv[]) { } compiledGrammerInFile.open(grammerFileString + ".comp", std::ios::binary | std::ios::ate); - if (!compiledGrammerInFile.is_open()) { + if (!compiledGrammerInFile.is_open()) std::cout << "Problem opening compiledGrammerInFile " << grammerFileString + ".comp" << "\n"; - //return(1); - } -/* - outFileC.open((outputName + ".c").c_str()); - if (!outFileC.is_open()) { - std::cout << "Probelm opening third output file " << outputName + ".c" << "\n"; - return(1); - } - */ + //Read the input file into a string std::string grammerInputFileString; std::string line; @@ -86,8 +78,6 @@ int main(int argc, char* argv[]) { //LALRParser parser; RNGLRParser parser; parser.loadGrammer(grammerInputFileString); - //std::cout << "Creating State Set from Main" << std::endl; - //std::cout << "\nState Set" << std::endl; //Start binary stuff bool compGramGood = false; @@ -111,7 +101,6 @@ int main(int argc, char* argv[]) { } else { compGramGood = true; std::cout << "Grammer file is up to date." << std::endl; - //int tableLength = *((int*)(binaryTablePointer + 4 + sizeof(int) + gramStringLength)); parser.importTable(binaryTablePointer + 4 + sizeof(int) + gramStringLength); //Load table starting at the table section } } else { @@ -141,43 +130,23 @@ int main(int argc, char* argv[]) { } //End binary stuff - //std::cout << "finished State Set from Main" << std::endl; - //std::cout << "Doing stateSetToString from Main" << std::endl; - // std::cout << "\n\n\n\n\n\n\n\n\n\nState Set toString" << std::endl; - // std::cout << parser.stateSetToString() << std::endl; - // std::cout << "finished stateSetToString from Main" << std::endl; - // std::cout << "\n\n\n\n\n\n\n\n\n\nTable" << std::endl; - // std::cout << parser.tableToString() << std::endl; - // std::cout << "\n\n\n\n\n\n\n\n\n\nGrammer Input File" << std::endl; - // std::cout << grammerInputFileString << std::endl; - // std::cout << "\n\n\n\n\n\n\n\n\n\nGrammer toString" << std::endl; - // std::cout << parser.grammerToString() << std::endl; - //std::cout << parser.grammerToDOT() << std::endl; - - //outFile << parser.grammerToDOT() << std::endl; std::cout << "\nParsing" << std::endl; Importer importer(&parser, includePaths); - /*NodeTree* AST =*/ for (auto i : includePaths) std::cout << i << std::endl; importer.import(programName); std::map*> ASTs = importer.getASTMap(); - //Do optomization, etc. here. + //Do optimization, etc. here. //None at this time, instead going straight to C in this first (more naive) version //Code generation //For right now, just C CGenerator().generateCompSet(ASTs, outputName); - /* - std::string c_code = CGenerator().generate(AST); - outFileC << c_code << std::endl; - outFileC.close(); -*/ return(0); } diff --git a/src/ASTTransformation.cpp b/src/ASTTransformation.cpp index eca685e..a97d7dc 100644 --- a/src/ASTTransformation.cpp +++ b/src/ASTTransformation.cpp @@ -70,11 +70,7 @@ NodeTree* ASTTransformation::transform(NodeTree* from, NodeTree if (newNode == NULL) { std::cout << "scope lookup error! Could not find " << lookupName << " in identifier " << std::endl; throw "LOOKUP ERROR: " + lookupName; - } else if (newNode->getDataRef()->symbol.getName() !=lookupName) { - //This happens when the lookup name denotes a member of an object, i.e. obj.foo - //The newNode points to obj, not foo. } - //newNode = new NodeTree(name, ASTData(identifier, Symbol(concatSymbolTree(children[0]), true))); } else if (name == "type_def") { //If it is an alisis of a type std::string typeAlias; @@ -93,8 +89,6 @@ NodeTree* ASTTransformation::transform(NodeTree* from, NodeTree //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); - // skipChildren.insert(0); //Don't try to transform the template - // skipChildren.insert(1); //Identifier lookup will be ourselves, as we just added ourselves to the scope } else { typeAlias = concatSymbolTree(children[0]); newNode = new NodeTree(name, ASTData(type_def, Symbol(typeAlias, true, typeAlias))); @@ -110,7 +104,6 @@ NodeTree* ASTTransformation::transform(NodeTree* from, NodeTree if (children[0]->getData().getName() == "template_dec") return newNode; scope = newNode; - //return newNode; } else if (name == "function") { std::string functionName; //If this is a function template @@ -451,9 +444,9 @@ NodeTree* ASTTransformation::doFunction(NodeTree* scope, std:: if ((nodes.size() != 2 && lookup == "*") || lookup == "&" || lookup == "[]") { Type* newType = oldTypes[0].clone(); if (lookup == "*" || lookup == "[]") - newType->increaseIndirection(); - else newType->decreaseIndirection(); + else + newType->increaseIndirection(); newNode->getDataRef()->valueType = newType, std::cout << "Operator " + lookup << " is altering indirection "<< std::endl; } else { From 6350f93f243f8c8f69135b9aa9e6df0855192c94 Mon Sep 17 00:00:00 2001 From: Nathan Braswell Date: Wed, 21 May 2014 01:20:39 -0400 Subject: [PATCH 14/37] Fixed the recursion bug. 8/10 tests pass now, remaining need to fix define order and CGenerator order --- src/ASTTransformation.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/ASTTransformation.cpp b/src/ASTTransformation.cpp index a97d7dc..94ac037 100644 --- a/src/ASTTransformation.cpp +++ b/src/ASTTransformation.cpp @@ -476,9 +476,10 @@ NodeTree* ASTTransformation::scopeLookup(NodeTree* scope, std: return *i; 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 this function is not a - //non-instantiated template (which would not have a body node, which is why we subtract one) - if (types.size() != ((children.size() > 0 && (*i)->getDataRef()->valueType->baseType != template_type ) ? children.size()-1 : children.size())) { + //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 + //and this function is recursive or if this is a non-instantiated template function + if (types.size() != ((children.size() > 0 && children[children.size()-1]->getDataRef()->type == code_block) ? children.size()-1 : children.size())) { std::cout << "Type sizes do not match between two " << lookup << "(" << types.size() << "," << ((children.size() > 0) ? children.size()-1 : 0) << "), types are: "; for (auto j : types) std::cout << j.toString() << " "; From d37a07201abfd552cc9a44c714ae78a2d6812f09 Mon Sep 17 00:00:00 2001 From: Nathan Braswell Date: Wed, 21 May 2014 12:01:45 -0400 Subject: [PATCH 15/37] Created a Poset template class. It can store the relationships of a partially ordered set, then generate a topological ordering. It will be used to order the type_def declarations in the CGenerator, as they depend on each other in a poset fashion. --- include/Poset.h | 118 ++++++++++++++++++++++++++++ main.cpp | 3 + src/ASTTransformation.cpp | 2 +- src/CGenerator.cpp | 2 + true_triple_quoted_string_regex.txt | 9 --- 5 files changed, 124 insertions(+), 10 deletions(-) create mode 100644 include/Poset.h delete mode 100644 true_triple_quoted_string_regex.txt diff --git a/include/Poset.h b/include/Poset.h new file mode 100644 index 0000000..29fea05 --- /dev/null +++ b/include/Poset.h @@ -0,0 +1,118 @@ + +#ifndef POSET_H +#define POSET_H + +#include +#include +#include +#include + +#include + +#include "util.h" + +template +class Poset { + public: + Poset(); + ~Poset(); + void addRelationship(T first, T second); + bool zeroDependencies(T vertex); + std::set getDependsOn(T dependency); + std::vector getTopoSort(); + static void test(); + private: + //backing data structures + std::map> adjMatrix; + std::set verticies; +}; + +template +Poset::Poset() { + //Nothing needed +} + +template +Poset::~Poset() { + //Ditto +} + + +template +void Poset::addRelationship(T first, T second) { + verticies.insert(first); + verticies.insert(second); + adjMatrix[first][second] = true; +} + +template +bool Poset::zeroDependencies(T vertex) { + auto depMapItr = adjMatrix.find(vertex); + if (depMapItr == adjMatrix.end()) + return true; + for (auto i : depMapItr->second) + if (i.second == true) + return false; + return true; +} + +template +std::set Poset::getDependsOn(T dependency) { + std::set vertsThatDependOn; + for (auto i : adjMatrix) { + auto depItr = i.second.find(dependency); + if (depItr != i.second.end() && depItr->second) + vertsThatDependOn.insert(i.first); + } + return vertsThatDependOn; +} + +template +std::vector Poset::getTopoSort() { + std::vector sorted; + std::queue toDo; + for (auto i : verticies) + if (zeroDependencies(i)) + toDo.push(i); + while(!toDo.empty()) { + T current = toDo.front(); toDo.pop(); + sorted.push_back(current); + for (T depOnCurrent : getDependsOn(current)) { + adjMatrix[depOnCurrent][current] = false; //Remove the edge to current, since current's now been taken care of + if (zeroDependencies(depOnCurrent)) + toDo.push(depOnCurrent); + } + } + return sorted; +} + + +//int specilization just for testing +template<> +void Poset::test() { + std::string result; + { + Poset poset; + for (int i = 0; i < 20; i++) + poset.addRelationship(i,i+1); + result = ""; + for (int i : poset.getTopoSort()) + result += intToString(i) + " "; + //std::cout << result << std::endl; + assert(result == "20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 "); + } + { + Poset poset; + for (int i = 0; i < 20; i+=2) + poset.addRelationship(i,i+1); + result = ""; + for (int i : poset.getTopoSort()) + result += intToString(i) + " "; + //std::cout << result << std::endl; + assert(result == "1 3 5 7 9 11 13 15 17 19 0 2 4 6 8 10 12 14 16 18 "); + } + + std::cout << "Poset tests passed" << std::endl; +} + +#endif \ No newline at end of file diff --git a/main.cpp b/main.cpp index 4f6f8b7..c5639ab 100644 --- a/main.cpp +++ b/main.cpp @@ -14,6 +14,7 @@ #include "Importer.h" #include "ASTData.h" #include "CGenerator.h" +#include "Poset.h" #include "util.h" #include "Tester.h" @@ -27,6 +28,8 @@ int main(int argc, char* argv[]) { RegEx::test(); Lexer::test(); //std::cout << strSlice("123", 0, -1) << std::endl; + Poset::test(); //int specilization just for testing. test() is actually only in the int specilization + if (argc >= 3) { std::string testResults, line; int passed = 0, failed = 0; diff --git a/src/ASTTransformation.cpp b/src/ASTTransformation.cpp index 94ac037..6d0d863 100644 --- a/src/ASTTransformation.cpp +++ b/src/ASTTransformation.cpp @@ -480,7 +480,7 @@ NodeTree* ASTTransformation::scopeLookup(NodeTree* scope, std: // the last node is actually a body node, as it may not have been generated yet if we're in the body //and this function is recursive or if this is a non-instantiated template function if (types.size() != ((children.size() > 0 && children[children.size()-1]->getDataRef()->type == code_block) ? children.size()-1 : children.size())) { - std::cout << "Type sizes do not match between two " << lookup << "(" << types.size() << "," << ((children.size() > 0) ? children.size()-1 : 0) << "), types are: "; + std::cout << "Type sizes do not match between two " << lookup << "(" << types.size() << "," << ((children.size() > 0 && children[children.size()-1]->getDataRef()->type == code_block) ? children.size()-1 : children.size()) << "), types are: "; for (auto j : types) std::cout << j.toString() << " "; std::cout << std::endl; diff --git a/src/CGenerator.cpp b/src/CGenerator.cpp index c34fe4e..b2d09bd 100644 --- a/src/CGenerator.cpp +++ b/src/CGenerator.cpp @@ -43,6 +43,8 @@ std::string CGenerator::generate(NodeTree* from, NodeTree* enc switch (data.type) { case translation_unit: //Do here because we may need the typedefs before the declarations of variables + //Note that we need to be careful of the order, though, as some declarations depend on others. + //What is this then? It's a poset! Wooo posets! for (int i = 0; i < children.size(); i++) if (children[i]->getDataRef()->type == type_def) output += generate(children[i], enclosingObject) + "\n"; diff --git a/true_triple_quoted_string_regex.txt b/true_triple_quoted_string_regex.txt deleted file mode 100644 index a14076b..0000000 --- a/true_triple_quoted_string_regex.txt +++ /dev/null @@ -1,9 +0,0 @@ -This is the true regex for triple quoted strings, but it segfaults my regex code.... - -triple_quoted_string = "\"\"\"((\"\"(`|1|2|3|4|5|6|7|8|9|0|-|=| |q|w|e|r|t|y|u|i|o|p|[|]|\\|a|s|d|f|g|h|j|k|l|;|'| -|z|x|c|v|b|n|m|,|.|/|~|!|@|#|$|%|^|&|\*|\(|\)|_|\+|Q|W|E|R|T|Y|U|I|O|P|{|}|\||A|S|D|F|G|H|J|K|L|:|Z|X|C|V|B|N|M|<|>|\?| )+)|(\"(`|1|2|3|4|5|6|7|8|9|0|-|=| |q|w|e|r|t|y|u|i|o|p|[|]|\\|a|s|d|f|g|h|j|k|l|;|'| -|z|x|c|v|b|n|m|,|.|/|~|!|@|#|$|%|^|&|\*|\(|\)|_|\+|Q|W|E|R|T|Y|U|I|O|P|{|}|\||A|S|D|F|G|H|J|K|L|:|Z|X|C|V|B|N|M|<|>|\?| )+))*(`|1|2|3|4|5|6|7|8|9|0|-|=| |q|w|e|r|t|y|u|i|o|p|[|]|\\|a|s|d|f|g|h|j|k|l|;|'| -|z|x|c|v|b|n|m|,|.|/|~|!|@|#|$|%|^|&|\*|\(|\)|_|\+|Q|W|E|R|T|Y|U|I|O|P|{|}|\||A|S|D|F|G|H|J|K|L|:|Z|X|C|V|B|N|M|<|>|\?| )*(((`|1|2|3|4|5|6|7|8|9|0|-|=| |q|w|e|r|t|y|u|i|o|p|[|]|\\|a|s|d|f|g|h|j|k|l|;|'| -|z|x|c|v|b|n|m|,|.|/|~|!|@|#|$|%|^|&|\*|\(|\)|_|\+|Q|W|E|R|T|Y|U|I|O|P|{|}|\||A|S|D|F|G|H|J|K|L|:|Z|X|C|V|B|N|M|<|>|\?| )+\")|((`|1|2|3|4|5|6|7|8|9|0|-|=| |q|w|e|r|t|y|u|i|o|p|[|]|\\|a|s|d|f|g|h|j|k|l|;|'| -|z|x|c|v|b|n|m|,|.|/|~|!|@|#|$|%|^|&|\*|\(|\)|_|\+|Q|W|E|R|T|Y|U|I|O|P|{|}|\||A|S|D|F|G|H|J|K|L|:|Z|X|C|V|B|N|M|<|>|\?| )+\"\")|((`|1|2|3|4|5|6|7|8|9|0|-|=| |q|w|e|r|t|y|u|i|o|p|[|]|\\|a|s|d|f|g|h|j|k|l|;|'| -|z|x|c|v|b|n|m|,|.|/|~|!|@|#|$|%|^|&|\*|\(|\)|_|\+|Q|W|E|R|T|Y|U|I|O|P|{|}|\||A|S|D|F|G|H|J|K|L|:|Z|X|C|V|B|N|M|<|>|\?| )+))*\"\"\"" ; \ No newline at end of file From 0f6b6c0c675c75688e6cc98d5d692b4ca7d15057 Mon Sep 17 00:00:00 2001 From: Nathan Braswell Date: Wed, 21 May 2014 13:14:16 -0400 Subject: [PATCH 16/37] Posets now integrated into the CGenerator, so the CGenerator now chooses a valid order for the object definitions based on their dependence on each other. Another test now passing --- include/CGenerator.h | 1 + include/Poset.h | 16 ++++++++++++---- main.cpp | 2 +- src/CGenerator.cpp | 29 ++++++++++++++++++++++++++--- 4 files changed, 40 insertions(+), 8 deletions(-) diff --git a/include/CGenerator.h b/include/CGenerator.h index d7e4e03..41e55f4 100644 --- a/include/CGenerator.h +++ b/include/CGenerator.h @@ -10,6 +10,7 @@ #include "Type.h" #include "util.h" +#include "Poset.h" class CGenerator { diff --git a/include/Poset.h b/include/Poset.h index 29fea05..f29d350 100644 --- a/include/Poset.h +++ b/include/Poset.h @@ -17,6 +17,7 @@ class Poset { Poset(); ~Poset(); void addRelationship(T first, T second); + void addVertex(T vertex); bool zeroDependencies(T vertex); std::set getDependsOn(T dependency); std::vector getTopoSort(); @@ -45,6 +46,11 @@ void Poset::addRelationship(T first, T second) { adjMatrix[first][second] = true; } +template +void Poset::addVertex(T vertex) { + verticies.insert(vertex); +} + template bool Poset::zeroDependencies(T vertex) { auto depMapItr = adjMatrix.find(vertex); @@ -87,19 +93,21 @@ std::vector Poset::getTopoSort() { } -//int specilization just for testing -template<> -void Poset::test() { +//would make it just an int specilization, but then we get multiple definition complaints.... +template +void Poset::test() { std::string result; { Poset poset; + poset.addVertex(1000); for (int i = 0; i < 20; i++) poset.addRelationship(i,i+1); result = ""; for (int i : poset.getTopoSort()) result += intToString(i) + " "; //std::cout << result << std::endl; - assert(result == "20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 "); + assert(result == "20 1000 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 "); //Note that sets do not have a set order, so this could change + //This is why the 1000 is in an odd, yet valid, position } { Poset poset; diff --git a/main.cpp b/main.cpp index c5639ab..3654f6f 100644 --- a/main.cpp +++ b/main.cpp @@ -28,7 +28,7 @@ int main(int argc, char* argv[]) { RegEx::test(); Lexer::test(); //std::cout << strSlice("123", 0, -1) << std::endl; - Poset::test(); //int specilization just for testing. test() is actually only in the int specilization + Poset::test(); if (argc >= 3) { std::string testResults, line; diff --git a/src/CGenerator.cpp b/src/CGenerator.cpp index b2d09bd..f47ac6a 100644 --- a/src/CGenerator.cpp +++ b/src/CGenerator.cpp @@ -45,9 +45,31 @@ std::string CGenerator::generate(NodeTree* from, NodeTree* enc //Do here because we may need the typedefs before the declarations of variables //Note that we need to be careful of the order, though, as some declarations depend on others. //What is this then? It's a poset! Wooo posets! - for (int i = 0; i < children.size(); i++) - if (children[i]->getDataRef()->type == type_def) - output += generate(children[i], enclosingObject) + "\n"; + { + Poset*> typedefPoset; + for (int i = 0; i < children.size(); i++) { + if (children[i]->getDataRef()->type == type_def) { + typedefPoset.addVertex(children[i]); //We add this definition by itself just in case there are no dependencies. + //If it has dependencies, there's no harm in adding it here + //Go through every child in the class looking for declaration statements. For each of these that is not a primitive type + //we will add a dependency from this definition to that definition in the poset. + std::vector*> classChildren = children[i]->getChildren(); + for (auto j : classChildren) { + if (j->getDataRef()->type == declaration_statement) { + Type* decType = j->getChildren()[0]->getDataRef()->valueType; //Type of the declaration + if (decType->typeDefinition && decType->getIndirection() == 0) //If this is a custom type and not a pointer + typedefPoset.addRelationship(children[i], decType->typeDefinition); //Add a dependency + } + } + //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"; + } + } + //Now generate the typedef's in the correct, topological order + for (NodeTree* i : typedefPoset.getTopoSort()) + output += generate(i, enclosingObject) + "\n"; + //Declare everything in translation unit scope here. (allows stuff from other files, automatic forward declarations) for (auto i = data.scope.begin(); i != data.scope.end(); i++) { for (auto overloadedMembers : i->second) { @@ -92,6 +114,7 @@ std::string CGenerator::generate(NodeTree* from, NodeTree* enc if (children[i]->getDataRef()->type != type_def) output += generate(children[i], enclosingObject) + "\n"; return output; + } break; case interpreter_directive: //Do nothing From ae9e652f1ed49986f8bfcb423419cac1218959c1 Mon Sep 17 00:00:00 2001 From: Nathan Braswell Date: Sat, 24 May 2014 14:04:32 -0400 Subject: [PATCH 17/37] 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; +} From 9bfbc7cdf6c52134b30c007ddb5f6c3b2d587bfa Mon Sep 17 00:00:00 2001 From: Nathan Braswell Date: Mon, 2 Jun 2014 00:19:44 -0700 Subject: [PATCH 18/37] Script to run all tests added. Prep work on new computer before fixing the remaining major template class bug. --- tests/runTests.sh | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100755 tests/runTests.sh diff --git a/tests/runTests.sh b/tests/runTests.sh new file mode 100755 index 0000000..bd16b15 --- /dev/null +++ b/tests/runTests.sh @@ -0,0 +1,14 @@ +#!/bin/bash + +krakenPath="../build/kraken" +testDir=${1:-"../tests"} +ext=${2:-"krak"} + +fileList="" +for dir in `find ${testDir} -type f -name "*.${ext}"`; do + filename=$(basename ${dir}) + filename="${filename%.*}" + fileList+=\ \.\/$filename +done + +${krakenPath} "--test" ${fileList} \ No newline at end of file From 812d40c6dba0a84744c3fb7c59533aa3760f3dfd Mon Sep 17 00:00:00 2001 From: Nathan Braswell Date: Mon, 9 Jun 2014 00:21:38 -0700 Subject: [PATCH 19/37] Work on fixing class templates instantiated outside of functions. Groundwork done, but it doesn't work. Doesn't break anything else either. Bedtime. --- include/.ASTTransformation.h.swp | Bin 0 -> 12288 bytes include/ASTTransformation.h | 14 +-- include/Type.h | 6 +- src/.ASTTransformation.cpp.swp | Bin 0 -> 143360 bytes src/ASTTransformation.cpp | 175 ++++++++++++++++--------------- tests/runTests.sh | 4 +- 6 files changed, 107 insertions(+), 92 deletions(-) create mode 100644 include/.ASTTransformation.h.swp create mode 100644 src/.ASTTransformation.cpp.swp diff --git a/include/.ASTTransformation.h.swp b/include/.ASTTransformation.h.swp new file mode 100644 index 0000000000000000000000000000000000000000..1fab7b148dd4f05a36fa08044d738a452de02109 GIT binary patch literal 12288 zcmYc?2=nw+FxN9-U|?VnU|`@#m>SG0a*V-CjDaC9u_Plg4ng56N|DW(PFr46LU^vdtz_5d#fng;-1H%e_28L<; z3=EC@3=E0<3=H1<3=CfU3=CHM3=Ee13=CiR7#LpjF)$q9V_;ap$H1_hkAWeFkAXpw zkAXpgkAYz-F9U-wF9X9Z9tH+i9tMWZ+zbqxxEUCtxEUA>xEUDqxfvKfaWOEg;$mRn z&8Om6d@(mz9AbiG_h7 zf`x&>k%fWb3o`>lIx_=93Nr&kGBea~LojYeoji0xKp7iI%}dElV_>MYX5i%X%TGxS zDN0SXaSRS|Ni0dU(^4qOF9=S~FG#gk(AUpR%*-oE%*;zoQAo=#QYcByEyzhMNi9|= z$w(|w$V*L4Q7Fk*NK8plD9K38El$lT1Iguscp!5Wia`b`7Acfxq!y)u zWGfXCi&7Ob^NLFn^GY%kOHxx9I5~?;Qmm|U6ANs>jN+1_%)E3R1u&;9HMu0e$OhB7 zc6JImiFxUziRr06sb#4-5T`S6a(d<#Hz_~IPRmXqIU_SCr6@H|M*-8NkibCoPe^4!s+~ef zWkG5&R06~MASGIM@Sq2AgHj7}5|dMNQ}arSHLV#Gpa3ML1vbpBC_fj(135wiM1Z3h z=1i~>kSIY{lIj>8g{1ua9OP()1suqo*uxy0M11n|vr7vQPDP|furxGmASps22do$> z22B_s-$DaY!4@USfMql^HF2c&lzdnmQ(!wNFu_3#cekBFUVaKCkqXTXP%kIv=OrhW zKq3%i5yGtyF*_}VqWt_4uqTm|DA@A~xrqfJ7Z!))gZRbR6EV8eG0XxP0kRuWRM;t$ zz*fjPLlZuBvtf=z&LCiC7N?fjWagFFDHLaC7QoCPm@F~l9GV!Yn_jV(jxZl%iGsAE z{M^Cg__EBRlG4N+Y$Xvq+HiP6)0%;Sld~*86IAS%7L{ZKBo-HA<`Y=7D&X{Z8npa$ zNlha&ionSbGwCT5rzR$6fD3!K{34jsTvF2zK7uD`SiuW71@7*G#G+zw^+$>0(1Hn@ z0}_i%kkSRF^xX2dDx~Fu!dsyrvA9?vEi*5(I3u-Kp|n6DsZt>&KQk{~Au%UM z0T!$ZN%<+6sm1WfD#^$!N&&?c4oAT4$t+5NSW%RklAl@(HWX4z7K18u2oqFKE99k? zBdjYZ$}hHY6WnrDTW7+OTKeXVsWu&UU6nhYB9n+h@b=oJ0crF zi$J&sVSx#$15;AdV1+3-9MCMoW;~HeG#Kn+NZLtBP0P$nEmlZLEJ*~_`I#xH3i(M{ zsmUe9ItuxvB_OXTq##0Bp|~Wm1k!5J0jD2$GKQq9g38ol1&!j&yyR4c@>GS4#IjUy zQzbqnHLX}7FTY$9l+fW`Mg&b-W>IkoIN3ug6>!5*AuTf})h{tOm6)981~LKFSD<_b z3Ui3<8c>gc-JO`3lUbZv40cW(#yW8gaFAmP!y2TB_NZqbNNGW7Qch;F6+<#80VrVT zvr>R4fR^LPE7ENsv91FP3599~s3|bJtQi=Tp$pm-lwg8-8A?c^knlt{7F8Z { //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); + void secondPassDoClassInsides(NodeTree* typeDef, std::vector*> typedefChildren); 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); + 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); 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* scopeLookup(NodeTree* scope, std::string lookup, std::vector types = std::vector()); - Type* typeFromTypeNode(NodeTree* typeNode, NodeTree* scope, std::map templateTypeReplacements); + + Type* typeFromTypeNode(NodeTree* typeNode, NodeTree* scope, std::map templateTypeReplacements, bool instantiateTemplates); NodeTree* findOrInstantiateFunctionTemplate(std::vector*> children, NodeTree* scope, std::vector types, std::map templateTypeReplacements); private: Importer * importer; diff --git a/include/Type.h b/include/Type.h index f5aacdc..5b31c6c 100644 --- a/include/Type.h +++ b/include/Type.h @@ -40,11 +40,13 @@ class Type { void decreaseIndirection(); void modifyIndirection(int mod); void check(); - ValueType baseType; + + ValueType baseType; NodeTree* typeDefinition; NodeTree* templateDefinition; + std::map templateTypeReplacement; private: int indirection; }; -#endif \ No newline at end of file +#endif diff --git a/src/.ASTTransformation.cpp.swp b/src/.ASTTransformation.cpp.swp new file mode 100644 index 0000000000000000000000000000000000000000..237ab0d7fd233cc749d248dfab61a525ed4b1951 GIT binary patch literal 143360 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 aD3Cu9D|X?&0gaC2r=+6iMfj!wYX$&fxqK4< literal 0 HcmV?d00001 diff --git a/src/ASTTransformation.cpp b/src/ASTTransformation.cpp index 8663aec..a5c8570 100644 --- a/src/ASTTransformation.cpp +++ b/src/ASTTransformation.cpp @@ -98,21 +98,12 @@ 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()); //No templates, we're in the traslation unit +/*HERE*/ typeDef->getDataRef()->valueType = typeFromTypeNode(typedefChildren[1], ast, std::map(), false); //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())); - } - } - + secondPassDoClassInsides(typeDef, typedefChildren); } else if (i->getDataRef()->getName() == "function") { //Do prototypes of functions ast->addChild(secondPassFunction(i, ast, std::map())); @@ -123,11 +114,24 @@ void ASTTransformation::secondPass(NodeTree* ast, NodeTree* par } } +void ASTTransformation::secondPassDoClassInsides(NodeTree* typeDef, std::vector*> typedefChildren) { + //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())); + } else if (j->getDataRef()->getName() == "function") { + //do member method + typeDef->addChild(secondPassFunction(j, typeDef, 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); +/*HERE*/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); @@ -152,7 +156,7 @@ NodeTree* ASTTransformation::secondPassFunction(NodeTree* from, //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); +/*HERE*/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() << "|| "; @@ -163,12 +167,12 @@ 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))); +/*HERE*/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); - +/*HERE*/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) // std::cout << "||" << i->getDataRef()->toString() << "|| "; @@ -179,6 +183,8 @@ NodeTree* ASTTransformation::secondPassFunction(NodeTree* from, 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(); @@ -244,7 +250,7 @@ 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); + Type type = *typeFromTypeNode(children[i]->getChildren()[0], scope, templateTypeReplacements, true); std::cout << "Type made: " << type.toString() << std::endl; types.push_back(type); } @@ -259,16 +265,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)); + functionDef->addChild(transform(codeBlock, functionDef, std::vector(), templateTypeReplacements, true)); } - NodeTree* ASTTransformation::transform(NodeTree* from) { //Set up top scope - return transform(from, NULL, std::vector(), std::map()); + return transform(from, NULL, std::vector(), std::map(), false); } -NodeTree* ASTTransformation::transform(NodeTree* from, NodeTree* scope, std::vector types, std::map templateTypeReplacements) { +NodeTree* ASTTransformation::transform(NodeTree* from, NodeTree* scope, std::vector types, std::map templateTypeReplacements, bool instantiateTemplates) { Symbol current = from->getData(); std::string name = current.getName(); NodeTree* newNode = NULL; @@ -279,7 +284,7 @@ NodeTree* ASTTransformation::transform(NodeTree* from, NodeTree 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) { @@ -313,7 +318,7 @@ NodeTree* ASTTransformation::transform(NodeTree* from, NodeTree newNode = scopeLookup(scope, lookupName, types); if (newNode == NULL) { std::cout << "scope lookup error! Could not find " << lookupName << " in identifier " << std::endl; - throw "LOOKUP ERROR: " + lookupName; + throw "LOOKUP ERROR: " + lookupName; } } else if (name == "type_def") { //If it is an alisis of a type @@ -323,9 +328,9 @@ NodeTree* ASTTransformation::transform(NodeTree* from, NodeTree typeAlias = concatSymbolTree(children[0]); 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); + newNode->getDataRef()->valueType = typeFromTypeNode(children[1], scope, templateTypeReplacements, instantiateTemplates); skipChildren.insert(0); //Don't want any children, it's unnecessary for ailising skipChildren.insert(1); } else { //Is a struct or class @@ -346,7 +351,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))); objectType = new Type(newNode); skipChildren.insert(0); //Identifier lookup will be ourselves, as we just added ourselves to the scope @@ -372,7 +377,7 @@ NodeTree* ASTTransformation::transform(NodeTree* from, NodeTree //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 - auto transChildren = transformChildren(slice(children,3,-2), std::set(), newNode, types, yetToBeInstantiatedTemplateTypes); + 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() << "|| "; @@ -383,13 +388,13 @@ 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))); + newNode = new NodeTree(name, ASTData(function, Symbol(functionName, true), typeFromTypeNode(children[0], scope, templateTypeReplacements, instantiateTemplates))); skipChildren.insert(0); skipChildren.insert(1); scope->getDataRef()->scope[functionName].push_back(newNode); newNode->getDataRef()->scope["~enclosing_scope"].push_back(scope); scope = newNode; - + // auto transChildren = transformChildren(children, skipChildren, scope, types); // std::cout << functionName << " "; // for (auto i : transChildren) @@ -397,7 +402,7 @@ NodeTree* ASTTransformation::transform(NodeTree* from, NodeTree // std::cout << "??||" << std::endl; // newNode->addChildren(transChildren); // return newNode; - + std::cout << "finished function (kinda, not children) " << functionName << std::endl; } else if (name == "code_block") { newNode = new NodeTree(name, ASTData(code_block)); @@ -408,7 +413,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))); + newNode = new NodeTree("identifier", ASTData(identifier, Symbol(parameterName, true), typeFromTypeNode(children[0], scope, templateTypeReplacements, instantiateTemplates))); scope->getDataRef()->scope[parameterName].push_back(newNode); newNode->getDataRef()->scope["~enclosing_scope"].push_back(scope); std::cout << "Done doing typed_parameter " << parameterName << std::endl; @@ -418,12 +423,12 @@ 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); + std::vector*> transformedChildren = transformChildren(children, skipChildren, scope, types, templateTypeReplacements, instantiateTemplates); std::string functionCallString = concatSymbolTree(children[1]); NodeTree* function = doFunction(scope, functionCallString, transformedChildren, templateTypeReplacements); if (function == NULL) { std::cout << "scope lookup error! Could not find " << functionCallString << " in boolean stuff " << std::endl; - throw "LOOKUP ERROR: " + functionCallString; + throw "LOOKUP ERROR: " + functionCallString; } newNode = function; // newNode = new NodeTree(functionCallString, ASTData(function_call, function->getDataRef()->valueType)); @@ -433,20 +438,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); //Just a promoted term, so do child + return transform(children[0], scope, types, templateTypeReplacements, instantiateTemplates); //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") { //unarad can ride through, it should always just be a promoted child //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); //LHS does not inherit types + NodeTree* lhs = transform(children[0], scope, std::vector(), templateTypeReplacements, instantiateTemplates); //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); //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, instantiateTemplates); //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); + rhs = transform(children[2], scope, types, templateTypeReplacements, instantiateTemplates); std::string functionCallName = concatSymbolTree(children[1]); //std::cout << "scope lookup from expression or similar" << std::endl; @@ -454,7 +459,7 @@ NodeTree* ASTTransformation::transform(NodeTree* from, NodeTree newNode = doFunction(scope, functionCallName, transformedChildren, templateTypeReplacements); if (newNode == NULL) { std::cout << "scope lookup error! Could not find " << functionCallName << " in expression " << std::endl; - throw "LOOKUP ERROR: " + functionCallName; + throw "LOOKUP ERROR: " + functionCallName; } // //Set the value of this function call @@ -469,7 +474,7 @@ NodeTree* ASTTransformation::transform(NodeTree* from, NodeTree //Is template instantiation return findOrInstantiateFunctionTemplate(children, scope, types, templateTypeReplacements); } else { - return transform(children[0], scope, types, templateTypeReplacements); //Just a promoted child, so do it instead + return transform(children[0], scope, types, templateTypeReplacements, instantiateTemplates); //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 @@ -479,32 +484,32 @@ 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); + param = transform(children[1], scope, types, templateTypeReplacements, instantiateTemplates); else - funcName = concatSymbolTree(children[1]), param = transform(children[0], scope, types, templateTypeReplacements); + funcName = concatSymbolTree(children[1]), param = transform(children[0], scope, types, templateTypeReplacements, instantiateTemplates); //std::cout << "scope lookup from factor" << std::endl; std::vector*> transformedChildren; transformedChildren.push_back(param); NodeTree* function = doFunction(scope, funcName, transformedChildren, templateTypeReplacements); if (function == NULL) { std::cout << "scope lookup error! Could not find " << funcName << " in factor " << std::endl; - throw "LOOKUP ERROR: " + funcName; + throw "LOOKUP ERROR: " + funcName; } return function; } else if (children.size() >= 4) { //Array brackets [] funcName = "[]"; std::vector*> transformedChildren; - transformedChildren.push_back(transform(children[0], scope, types, templateTypeReplacements)); - transformedChildren.push_back(transform(children[2], scope, types, templateTypeReplacements)); + transformedChildren.push_back(transform(children[0], scope, types, templateTypeReplacements, instantiateTemplates)); + transformedChildren.push_back(transform(children[2], scope, types, templateTypeReplacements, instantiateTemplates)); NodeTree* function = doFunction(scope, funcName, transformedChildren, templateTypeReplacements); if (function == NULL) { std::cout << "scope lookup error! Could not find " << funcName << " in factor " << std::endl; - throw "LOOKUP ERROR: " + funcName; + throw "LOOKUP ERROR: " + funcName; } return function; } else { - return transform(children[0], scope, types, templateTypeReplacements); //Just a promoted child, so do it instead + return transform(children[0], scope, types, templateTypeReplacements, instantiateTemplates); //Just a promoted child, so do it instead } } else if (name == "statement") { newNode = new NodeTree(name, ASTData(statement)); @@ -520,18 +525,18 @@ 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)); - newNode->addChild(transform(children[2], scope, types, templateTypeReplacements)); + newNode->addChild(transform(children[0], scope, types, templateTypeReplacements, instantiateTemplates)); + newNode->addChild(transform(children[2], scope, types, templateTypeReplacements, instantiateTemplates)); } else { //For assignments like += or *=, expand the syntatic sugar. - NodeTree* lhs = transform(children[0], scope, types, templateTypeReplacements); - NodeTree* rhs = transform(children[2], scope, types, templateTypeReplacements); + NodeTree* lhs = transform(children[0], scope, types, templateTypeReplacements, instantiateTemplates); + NodeTree* rhs = transform(children[2], scope, types, templateTypeReplacements, instantiateTemplates); 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); if (operatorCall == NULL) { std::cout << "scope lookup error! Could not find " << functionName << " in assignment_statement " << std::endl; - throw "LOOKUP ERROR: " + functionName; + throw "LOOKUP ERROR: " + functionName; } newNode->addChild(lhs); newNode->addChild(operatorCall); @@ -543,7 +548,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); + Type* identifierType = typeFromTypeNode(children[0], scope, templateTypeReplacements, instantiateTemplates); 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); @@ -563,12 +568,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); + std::vector*> transformedChildren = transformChildren(children, skipChildren, scope, types, templateTypeReplacements, instantiateTemplates); 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); + NodeTree* function = transform(children[0], scope, mapNodesToTypes(transformedChildren), templateTypeReplacements, instantiateTemplates); std::cout << "The thing: " << function << " : " << function->getName() << std::endl; for (auto i : function->getChildren()) std::cout << i->getName() << " "; @@ -578,12 +583,12 @@ NodeTree* ASTTransformation::transform(NodeTree* from, NodeTree newNode->addChildren(transformedChildren); return newNode; } else if (name == "parameter") { - return transform(children[0], scope, types, templateTypeReplacements); //Don't need a parameter node, just the value + return transform(children[0], scope, types, templateTypeReplacements, instantiateTemplates); //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))); + newNode = new NodeTree(name, ASTData(value, Symbol(theConcat, true), typeFromTypeNode(from, scope, templateTypeReplacements, instantiateTemplates))); } else if (name == "number") { - return transform(children[0], scope, types, templateTypeReplacements); + return transform(children[0], scope, types, templateTypeReplacements, instantiateTemplates); } else if (name == "integer") { newNode = new NodeTree(name, ASTData(value, Symbol(concatSymbolTree(from), true), new Type(integer))); } else if (name == "float") { @@ -603,7 +608,7 @@ NodeTree* ASTTransformation::transform(NodeTree* from, NodeTree //Do all children but the ones we skip for (int i = 0; i < children.size(); i++) { if (skipChildren.find(i) == skipChildren.end()) { - NodeTree* transChild = transform(children[i], scope, types, templateTypeReplacements); + NodeTree* transChild = transform(children[i], scope, types, templateTypeReplacements, instantiateTemplates); if (transChild->getDataRef()->type) //Only add the children that have a real ASTData::ASTType, that is, legit ASTData. newNode->addChild(transChild); else @@ -614,12 +619,12 @@ NodeTree* ASTTransformation::transform(NodeTree* from, NodeTree } //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) { +std::vector*> ASTTransformation::transformChildren(std::vector*> children, std::set skipChildren, NodeTree* scope, std::vector types, std::map templateTypeReplacements, bool instantiateTemplates) { 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); + NodeTree* transChild = transform(children[i], scope, types, templateTypeReplacements, instantiateTemplates); if (transChild->getDataRef()->type) //Only add the children that have a real ASTData::ASTType, that is, legit ASTData. transformedChildren.push_back(transChild); else @@ -647,7 +652,7 @@ std::string ASTTransformation::concatSymbolTree(NodeTree* root) { concatString += ourValue; std::vector*> children = root->getChildren(); for (int i = 0; i < children.size(); i++) { - concatString += concatSymbolTree(children[i]); + concatString += concatSymbolTree(children[i]); } return concatString; } @@ -666,7 +671,7 @@ NodeTree* ASTTransformation::doFunction(NodeTree* scope, std:: if (nodes[0]->getDataRef()->valueType && nodes[0]->getDataRef()->valueType->typeDefinition) operatorMethod = scopeLookup(nodes[0]->getDataRef()->valueType->typeDefinition, lookupOp, mapNodesToTypes(slice(nodes,1,-1))); if (operatorMethod) { - //Ok, so we construct + //Ok, so we construct std::cout << "Early method level operator was found" << std::endl; //return operatorMethod; NodeTree* newNode = new NodeTree(lookupOp, ASTData(function_call, Symbol(lookupOp, true))); @@ -684,7 +689,7 @@ NodeTree* ASTTransformation::doFunction(NodeTree* scope, std:: } std::cout << "Early method level operator was NOT found" << std::endl; } - + newNode = new NodeTree(lookup, ASTData(function_call, Symbol(lookup, true))); NodeTree* function = scopeLookup(scope, lookup, mapNodesToTypes(nodes)); newNode->addChild(function); @@ -785,9 +790,8 @@ NodeTree* ASTTransformation::scopeLookup(NodeTree* scope, std: } //Create a type from a syntax tree. This can get complicated with templates -Type* ASTTransformation::typeFromTypeNode(NodeTree* typeNode, NodeTree* scope, std::map templateTypeReplacements) { - std::string typeIn; - typeIn = concatSymbolTree(typeNode); +Type* ASTTransformation::typeFromTypeNode(NodeTree* typeNode, NodeTree* scope, std::map templateTypeReplacements, bool instantiateTemplates) { + std::string typeIn = concatSymbolTree(typeNode); int indirection = 0; ValueType baseType; @@ -838,32 +842,39 @@ Type* ASTTransformation::typeFromTypeNode(NodeTree* typeNode, NodeTree newTemplateTypeReplacement; std::string templateParameterName = concatSymbolTree(templateSyntaxTree->getChildren()[0]->getChildren()[1]); - Type* replacementType = typeFromTypeNode(typeNode->getChildren()[1]->getChildren()[1], scope, templateTypeReplacements); + 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() + ">"; typeDefinition = new NodeTree("type_def", ASTData(type_def, Symbol(fullyInstantiatedName, true, fullyInstantiatedName))); - typeDefinition->getDataRef()->valueType = new Type(typeDefinition);; //Type is self-referential since this is the definition + Type* selfType = new Type(typeDefinition); //Type is self-referential since this is the definition + typeDefinition->getDataRef()->valueType = selfType; - //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 + //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 topScope->getDataRef()->scope[fullyInstantiatedName].push_back(typeDefinition); - topScope->addChild(typeDefinition); //Add this object the the highest scope's + topScope->addChild(typeDefinition); //Add this object the the highest scope's //Note that the instantiated template's scope is the template's definition. typeDefinition->getDataRef()->scope["~enclosing_scope"].push_back(templateDefinition); - 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)); - 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; - return NULL; + if (!instantiateTemplates) { + selfType->templateTypeReplacement = newTemplateTypeReplacement; //Save the types for use when this is fully instantiated in pass 4 + secondPassDoClassInsides(typeDefinition, templateSyntaxTree->getChildren()); + } 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)); + 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; + return NULL; } else { std::cout << "Type: " << edited << " already instantiated with " << typeDefinition << ", will be " << Type(baseType, typeDefinition, indirection).toString() << std::endl; } @@ -877,7 +888,7 @@ NodeTree* ASTTransformation::findOrInstantiateFunctionTemplate(std::vec //First look to see if we can find this already instantiated std::cout << "Finding or instantiating templated function" << std::endl; std::string functionName = concatSymbolTree(children[0]); - Type* templateActualType = typeFromTypeNode(children[1]->getChildren()[1], scope, templateTypeReplacements); + Type* templateActualType = typeFromTypeNode(children[1]->getChildren()[1], scope, templateTypeReplacements, true); std::string fullyInstantiatedName = functionName + "<" + templateActualType->toString() + ">"; std::cout << "Looking for " << fullyInstantiatedName << std::endl; @@ -914,7 +925,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))); + instantiatedFunction = new NodeTree("function", ASTData(function, Symbol(fullyInstantiatedName, true), typeFromTypeNode(templateChildren[1], scope, newTemplateTypeReplacement, true))); std::set skipChildren; skipChildren.insert(0); skipChildren.insert(1); @@ -922,7 +933,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)); + instantiatedFunction->addChildren(transformChildren(templateSyntaxTree->getChildren(), skipChildren, instantiatedFunction, std::vector(), newTemplateTypeReplacement, true)); topScope->getDataRef()->scope[fullyInstantiatedName].push_back(instantiatedFunction); topScope->addChild(instantiatedFunction); //Add this object the the highest scope's diff --git a/tests/runTests.sh b/tests/runTests.sh index bd16b15..f86e0bf 100755 --- a/tests/runTests.sh +++ b/tests/runTests.sh @@ -8,7 +8,7 @@ fileList="" for dir in `find ${testDir} -type f -name "*.${ext}"`; do filename=$(basename ${dir}) filename="${filename%.*}" - fileList+=\ \.\/$filename + fileList+=\ $testDir\/$filename done -${krakenPath} "--test" ${fileList} \ No newline at end of file +${krakenPath} "--test" ${fileList} From 366bbb6432efd0be1181e3cfe2b0d40b41bba2e6 Mon Sep 17 00:00:00 2001 From: Nathan Braswell Date: Mon, 9 Jun 2014 00:40:12 -0700 Subject: [PATCH 20/37] I didn't save the file. Now most (all) class template tests fail. Bedtime. --- include/.ASTTransformation.h.swp | Bin 12288 -> 0 bytes src/.ASTTransformation.cpp.swp | Bin 143360 -> 0 bytes src/ASTTransformation.cpp | 12 ++++++++++++ 3 files changed, 12 insertions(+) delete mode 100644 include/.ASTTransformation.h.swp delete mode 100644 src/.ASTTransformation.cpp.swp diff --git a/include/.ASTTransformation.h.swp b/include/.ASTTransformation.h.swp deleted file mode 100644 index 1fab7b148dd4f05a36fa08044d738a452de02109..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 12288 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 aD3Cu9D|X?&0gaC2r=+6iMfj!wYX$&fxqK4< diff --git a/src/ASTTransformation.cpp b/src/ASTTransformation.cpp index a5c8570..cdc2c3c 100644 --- a/src/ASTTransformation.cpp +++ b/src/ASTTransformation.cpp @@ -212,6 +212,18 @@ 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->baseType == template_type) + classTemplates.push_back(i.second[0]); + for (auto i : classTemplates) { + Type* classTemplateType = i->getDataRef()->valueType; + 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) { From 7dbfd8ca38059b14d811c45235d4ba1465fae1cb Mon Sep 17 00:00:00 2001 From: Nathan Braswell Date: Tue, 10 Jun 2014 00:53:30 -0700 Subject: [PATCH 21/37] 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 +} From e7a631240f2df21f4126fb9a58eda0c1fe70a484 Mon Sep 17 00:00:00 2001 From: Nathan Braswell Date: Tue, 10 Jun 2014 23:59:39 -0700 Subject: [PATCH 22/37] Fixed the remaining problems\! All the tests pass now. --- include/CGenerator.h | 4 ++-- src/ASTTransformation.cpp | 4 ++-- src/CGenerator.cpp | 46 +++++++++++++++++++++++++-------------- 3 files changed, 34 insertions(+), 20 deletions(-) diff --git a/include/CGenerator.h b/include/CGenerator.h index 41e55f4..84fba11 100644 --- a/include/CGenerator.h +++ b/include/CGenerator.h @@ -23,10 +23,10 @@ class CGenerator { static std::string ValueTypeToCTypeDecoration(Type *type); static std::string CifyName(std::string name); std::string generateObjectMethod(NodeTree* enclosingObject, NodeTree* from); - + NodeTree* getMethodsObjectType(NodeTree* scope, std::string functionName); std::string generatorString; private: std::string tabs(); int tabLevel; }; -#endif \ No newline at end of file +#endif diff --git a/src/ASTTransformation.cpp b/src/ASTTransformation.cpp index 61b7f69..b08fc3c 100644 --- a/src/ASTTransformation.cpp +++ b/src/ASTTransformation.cpp @@ -101,8 +101,8 @@ void ASTTransformation::secondPass(NodeTree* ast, NodeTree* par 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; + // 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 diff --git a/src/CGenerator.cpp b/src/CGenerator.cpp index 854f646..5a117ed 100644 --- a/src/CGenerator.cpp +++ b/src/CGenerator.cpp @@ -64,9 +64,12 @@ 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 - } + else { + Type *aliasType = children[i]->getDataRef()->valueType; + if (aliasType->typeDefinition && aliasType->typeDefinition != children[i] && !aliasType->templateDefinition) //Isn't uninstantiated template or 0 parameter class, so must be alias. if typeDefinition isn't null, then it's an alias of a custom, not a primitive, type. + 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 for (NodeTree* i : typedefPoset.getTopoSort()) @@ -249,18 +252,24 @@ std::string CGenerator::generate(NodeTree* from, NodeTree* enc std::string functionName = children[2]->getDataRef()->symbol.getName(); NodeTree* possibleObjectType = children[1]->getDataRef()->valueType->typeDefinition; //If is an object method, generate it like one. Needs extension/modification for inheritence - if (possibleObjectType && possibleObjectType->getDataRef()->scope.find(functionName) != possibleObjectType->getDataRef()->scope.end()) { - std::string nameDecoration; - std::vector*> functionDefChildren = children[2]->getChildren(); //The function def is the rhs of the access operation - 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) + ","; - //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 - } else { - std::cout << "Is not in scope or not type" << std::endl; - return "((" + generate(children[1], enclosingObject) + ")" + name + functionName + ")"; + if (possibleObjectType) { + NodeTree* unaliasedTypeDef = getMethodsObjectType(possibleObjectType, functionName); + if (unaliasedTypeDef) { //Test to see if the function's a member of this type_def, or if this is an alias, of the original type. Get this original type if it exists. + std::string nameDecoration; + std::vector*> functionDefChildren = children[2]->getChildren(); //The function def is the rhs of the access operation + 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(unaliasedTypeDef->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 + } else { + std::cout << "Is not in scope or not type" << std::endl; + return "((" + generate(children[1], enclosingObject) + ")" + name + functionName + ")"; + } + } else { + std::cout << "Is not in scope or not type" << std::endl; + return "((" + generate(children[1], enclosingObject) + ")" + name + functionName + ")"; } } else { //return "((" + generate(children[1], enclosingObject) + ")" + name + generate(children[2], enclosingObject) + ")"; @@ -309,7 +318,12 @@ std::string CGenerator::generate(NodeTree* from, NodeTree* enc return output; } - +NodeTree* CGenerator::getMethodsObjectType(NodeTree* scope, std::string functionName) { + //check the thing + while (scope != scope->getDataRef()->valueType->typeDefinition) //type is an alias, follow it to the definition + scope = scope->getDataRef()->valueType->typeDefinition; + return (scope->getDataRef()->scope.find(functionName) != scope->getDataRef()->scope.end()) ? scope : NULL; +} std::string CGenerator::generateObjectMethod(NodeTree* enclosingObject, NodeTree* from) { std::string output; ASTData data = from->getData(); From 82d8a15de03f6e7d98e65e8aae59d9f950487ae0 Mon Sep 17 00:00:00 2001 From: Nathan Braswell Date: Tue, 17 Jun 2014 00:10:57 -0700 Subject: [PATCH 23/37] Added (then fixed) templates with multiple parameters for both classes and functions! --- CMakeLists.txt | 1 + include/util.h | 15 +++- krakenGrammer.kgm | 9 ++- src/ASTTransformation.cpp | 70 ++++++++++++------- src/Importer.cpp | 8 ++- ...ctionMultipleTemplateTest.expected_results | 1 + tests/functionMultipleTemplateTest.krak | 13 ++++ tests/functionTemplateTest.krak | 2 +- ...bjectMultipleTemplateTest.expected_results | 4 ++ tests/simpleObjectMultipleTemplateTest.krak | 30 ++++++++ 10 files changed, 117 insertions(+), 36 deletions(-) create mode 100644 tests/functionMultipleTemplateTest.expected_results create mode 100644 tests/functionMultipleTemplateTest.krak create mode 100644 tests/simpleObjectMultipleTemplateTest.expected_results create mode 100644 tests/simpleObjectMultipleTemplateTest.krak 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; +} From 63d9ec66e18b499487adeb691e78ff69f4625dae Mon Sep 17 00:00:00 2001 From: Nathan Braswell Date: Thu, 26 Jun 2014 01:45:44 -0700 Subject: [PATCH 24/37] Added "Init Position Call" (takes the place of implicit constructors) and the this keyword! This was the structure needed for more sensable memory management. At least delete will need some updating before it becomes very usable, though. (Figuring out the types for function template instantiation) Anyway, good progress here! --- include/ASTTransformation.h | 3 +- krakenGrammer.kgm | 2 +- src/ASTTransformation.cpp | 109 +++++++++++++++--------- src/CGenerator.cpp | 23 +++-- stdlib/io.krak | 18 +++- tests/declarationsTest.expected_results | 3 + tests/declarationsTest.krak | 26 ++++++ 7 files changed, 134 insertions(+), 50 deletions(-) create mode 100644 tests/declarationsTest.expected_results create mode 100644 tests/declarationsTest.krak diff --git a/include/ASTTransformation.h b/include/ASTTransformation.h index dfaa553..955ccca 100644 --- a/include/ASTTransformation.h +++ b/include/ASTTransformation.h @@ -45,7 +45,8 @@ class ASTTransformation: public NodeTransformation { NodeTree* findOrInstantiateFunctionTemplate(std::vector*> children, NodeTree* scope, std::vector types, std::map templateTypeReplacements); private: Importer * importer; - std::map*>> languageLevelScope; + std::map*>> languageLevelReservedWords; + std::map*>> languageLevelOperators; NodeTree* topScope; //maintained for templates that need to add themselves to the top scope no matter where they are instantiated }; diff --git a/krakenGrammer.kgm b/krakenGrammer.kgm index 8fdfba6..85406ee 100644 --- a/krakenGrammer.kgm +++ b/krakenGrammer.kgm @@ -81,7 +81,7 @@ number = integer | float | double ; access_operation = unarad "." identifier | unarad "->" identifier ; assignment_statement = factor WS "=" WS boolean_expression | factor WS "\+=" WS boolean_expression | factor WS "-=" WS boolean_expression | factor WS "\*=" WS boolean_expression | factor WS "/=" WS boolean_expression ; -declaration_statement = type WS identifier WS "=" WS boolean_expression | type WS identifier ; +declaration_statement = type WS identifier WS "=" WS boolean_expression | type WS identifier | type WS identifier WS "." WS identifier WS "\(" WS opt_parameter_list WS "\)" ; alphanumeric = alphanumeric numeric | alphanumeric alpha | numeric | alpha ; hexadecimal = "0x(1|2|3|4|5|6|7|8|9|a|b|c|d|e|f)+" ; diff --git a/src/ASTTransformation.cpp b/src/ASTTransformation.cpp index bb7a322..160e14c 100644 --- a/src/ASTTransformation.cpp +++ b/src/ASTTransformation.cpp @@ -3,30 +3,34 @@ ASTTransformation::ASTTransformation(Importer *importerIn) { importer = importerIn; topScope = NULL; - //Set up language level special scope. (the final scope checked) + + //Set up language level reserved identifier scope (only this, right now) + languageLevelReservedWords["this"].push_back(new NodeTree("identifier", ASTData(identifier, Symbol("this", true), NULL))); + + //Set up language level special scope. (the final scope checked) //Note the NULL type - languageLevelScope["+"].push_back( new NodeTree("function", ASTData(function, Symbol("+", true), NULL))); - languageLevelScope["-"].push_back(new NodeTree("function", ASTData(function, Symbol("-", true), NULL))); - languageLevelScope["*"].push_back(new NodeTree("function", ASTData(function, Symbol("*", true), NULL))); - languageLevelScope["/"].push_back(new NodeTree("function", ASTData(function, Symbol("/", true), NULL))); - languageLevelScope["%"].push_back(new NodeTree("function", ASTData(function, Symbol("%", true), NULL))); - languageLevelScope["&"].push_back(new NodeTree("function", ASTData(function, Symbol("&", true), NULL))); - languageLevelScope["--"].push_back(new NodeTree("function", ASTData(function, Symbol("--", true), NULL))); - languageLevelScope["++"].push_back(new NodeTree("function", ASTData(function, Symbol("++", true), NULL))); - languageLevelScope["=="].push_back(new NodeTree("function", ASTData(function, Symbol("==", true), NULL))); - languageLevelScope["<="].push_back(new NodeTree("function", ASTData(function, Symbol("<=", true), NULL))); - languageLevelScope[">="].push_back(new NodeTree("function", ASTData(function, Symbol(">=", true), NULL))); - languageLevelScope["<"].push_back(new NodeTree("function", ASTData(function, Symbol("<", true), NULL))); - languageLevelScope[">"].push_back(new NodeTree("function", ASTData(function, Symbol(">", true), NULL))); - languageLevelScope["&&"].push_back(new NodeTree("function", ASTData(function, Symbol("&&", true), NULL))); - languageLevelScope["||"].push_back(new NodeTree("function", ASTData(function, Symbol("||", true), NULL))); - languageLevelScope["!"].push_back(new NodeTree("function", ASTData(function, Symbol("!", true), NULL))); - languageLevelScope["*="].push_back(new NodeTree("function", ASTData(function, Symbol("*=", true), NULL))); - languageLevelScope["+="].push_back(new NodeTree("function", ASTData(function, Symbol("+=", true), NULL))); - languageLevelScope["-="].push_back(new NodeTree("function", ASTData(function, Symbol("-=", true), NULL))); - languageLevelScope["."].push_back(new NodeTree("function", ASTData(function, Symbol(".", true), NULL))); - languageLevelScope["->"].push_back(new NodeTree("function", ASTData(function, Symbol("->", true), NULL))); - languageLevelScope["[]"].push_back(new NodeTree("function", ASTData(function, Symbol("[]", true), NULL))); + languageLevelOperators["+"].push_back(new NodeTree("function", ASTData(function, Symbol("+", true), NULL))); + languageLevelOperators["-"].push_back(new NodeTree("function", ASTData(function, Symbol("-", true), NULL))); + languageLevelOperators["*"].push_back(new NodeTree("function", ASTData(function, Symbol("*", true), NULL))); + languageLevelOperators["/"].push_back(new NodeTree("function", ASTData(function, Symbol("/", true), NULL))); + languageLevelOperators["%"].push_back(new NodeTree("function", ASTData(function, Symbol("%", true), NULL))); + languageLevelOperators["&"].push_back(new NodeTree("function", ASTData(function, Symbol("&", true), NULL))); + languageLevelOperators["--"].push_back(new NodeTree("function", ASTData(function, Symbol("--", true), NULL))); + languageLevelOperators["++"].push_back(new NodeTree("function", ASTData(function, Symbol("++", true), NULL))); + languageLevelOperators["=="].push_back(new NodeTree("function", ASTData(function, Symbol("==", true), NULL))); + languageLevelOperators["<="].push_back(new NodeTree("function", ASTData(function, Symbol("<=", true), NULL))); + languageLevelOperators[">="].push_back(new NodeTree("function", ASTData(function, Symbol(">=", true), NULL))); + languageLevelOperators["<"].push_back(new NodeTree("function", ASTData(function, Symbol("<", true), NULL))); + languageLevelOperators[">"].push_back(new NodeTree("function", ASTData(function, Symbol(">", true), NULL))); + languageLevelOperators["&&"].push_back(new NodeTree("function", ASTData(function, Symbol("&&", true), NULL))); + languageLevelOperators["||"].push_back(new NodeTree("function", ASTData(function, Symbol("||", true), NULL))); + languageLevelOperators["!"].push_back(new NodeTree("function", ASTData(function, Symbol("!", true), NULL))); + languageLevelOperators["*="].push_back(new NodeTree("function", ASTData(function, Symbol("*=", true), NULL))); + languageLevelOperators["+="].push_back(new NodeTree("function", ASTData(function, Symbol("+=", true), NULL))); + languageLevelOperators["-="].push_back(new NodeTree("function", ASTData(function, Symbol("-=", true), NULL))); + languageLevelOperators["."].push_back(new NodeTree("function", ASTData(function, Symbol(".", true), NULL))); + languageLevelOperators["->"].push_back(new NodeTree("function", ASTData(function, Symbol("->", true), NULL))); + languageLevelOperators["[]"].push_back(new NodeTree("function", ASTData(function, Symbol("[]", true), NULL))); } ASTTransformation::~ASTTransformation() { @@ -132,7 +136,8 @@ void ASTTransformation::secondPassDoClassInsides(NodeTree* typeDef, std //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)); + //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); std::cout << "Declaring an identifier " << newIdentifierStr << " to be of type " << identifierType->toString() << std::endl; @@ -576,9 +581,33 @@ NodeTree* ASTTransformation::transform(NodeTree* from, NodeTree newNode->getDataRef()->scope["~enclosing_scope"].push_back(scope); newNode->addChild(newIdentifier); + if (children.size() > 2 && concatSymbolTree(children[2]) == ".") { + //A bit of a special case for declarations - if there's anything after just the normal 1 node declaration, it's either + //an expression that is assigned to the declaration (int a = 4;) or a member call (Object a.constructAThing()) + //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*> transformedChildren; transformedChildren.push_back(newIdentifier); transformedChildren.push_back(rhs); + NodeTree* accessFuncCall = doFunction(scope, ".", transformedChildren, templateTypeReplacements); + accessFuncCall->getDataRef()->valueType = rhs->getDataRef()->valueType; + //Now we borrow a bit of code from function_call below to actually use our new accessFuncCall to setup a "initPosition" function call + //that will follow the identifier in this declaration node + std::string initPosFuncName = newIdentifierStr + "." + concatSymbolTree(children[3]); + NodeTree* initPositionFuncCall = new NodeTree(initPosFuncName, ASTData(function_call, Symbol(initPosFuncName, true))); + initPositionFuncCall->addChild(accessFuncCall); + initPositionFuncCall->getDataRef()->valueType = accessFuncCall->getDataRef()->valueType; + initPositionFuncCall->addChildren(initPositionFuncParams); + newNode->addChild(initPositionFuncCall); + return newNode; + } + skipChildren.insert(0); //These, the type and the identifier, have been taken care of. skipChildren.insert(1); - } else if (name == "if_comp") { + newNode->addChildren(transformChildren(children, skipChildren, scope, types, templateTypeReplacements, instantiateTemplates)); + return newNode; + } else if (name == "if_comp") { newNode = new NodeTree(name, ASTData(if_comp)); newNode->addChild(new NodeTree("identifier", ASTData(identifier, Symbol(concatSymbolTree(children[0]),true)))); skipChildren.insert(0); //Don't do the identifier. The identifier lookup will fail. That's why we do it here. @@ -627,15 +656,7 @@ NodeTree* ASTTransformation::transform(NodeTree* from, NodeTree } //Do all children but the ones we skip - for (int i = 0; i < children.size(); i++) { - if (skipChildren.find(i) == skipChildren.end()) { - NodeTree* transChild = transform(children[i], scope, types, templateTypeReplacements, instantiateTemplates); - if (transChild->getDataRef()->type) //Only add the children that have a real ASTData::ASTType, that is, legit ASTData. - newNode->addChild(transChild); - else - delete transChild; - } - } + newNode->addChildren(transformChildren(children, skipChildren, scope, types, templateTypeReplacements, instantiateTemplates)); return newNode; } @@ -680,9 +701,9 @@ std::string ASTTransformation::concatSymbolTree(NodeTree* root) { //We pass in the actual children (parameters) to allow us to handle overloaded operator methods (where a parameter is actually the scope of the method) NodeTree* ASTTransformation::doFunction(NodeTree* scope, std::string lookup, std::vector*> nodes, std::map templateTypeReplacements) { - auto LLElementIterator = languageLevelScope.find(lookup); + auto LLElementIterator = languageLevelOperators.find(lookup); NodeTree* newNode; - if (LLElementIterator != languageLevelScope.end()) { + if (LLElementIterator != languageLevelOperators.end()) { std::cout << "Checking for early method level operator overload" << std::endl; std::string lookupOp = "operator" + lookup; for (auto i : nodes) @@ -697,7 +718,7 @@ NodeTree* ASTTransformation::doFunction(NodeTree* scope, std:: //return operatorMethod; NodeTree* newNode = new NodeTree(lookupOp, ASTData(function_call, Symbol(lookupOp, true))); NodeTree* dotFunctionCall = new NodeTree(".", ASTData(function_call, Symbol(".", true))); - dotFunctionCall->addChild(languageLevelScope["."][0]); //function definition + dotFunctionCall->addChild(languageLevelOperators["."][0]); //function definition dotFunctionCall->addChild(nodes[0]); // The object whose method we're calling dotFunctionCall->addChild(operatorMethod); //The method we're calling newNode->addChild(dotFunctionCall); // First child of function call is a link to the function definition @@ -740,9 +761,15 @@ NodeTree* ASTTransformation::doFunction(NodeTree* scope, std:: //Search recursively through levels of scope (each ASTData, that is, every node, has its own scope) //We pass in types so that if we're searching for a function we can find the right overloaded one NodeTree* ASTTransformation::scopeLookup(NodeTree* scope, std::string lookup, std::vector types) { - //We first search the languageLevelScope to see if it's an operator. If so, we modifiy the lookup with a preceding "operator" - auto LLElementIterator = languageLevelScope.find(lookup); - if (LLElementIterator != languageLevelScope.end()) + //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()) { + std::cout << "found it at language level as reserved word." << std::endl; + return LLElementIterator->second[0]; + } + //We search the languageLevelOperators to see if it's an operator. If so, we modifiy the lookup with a preceding "operator" + LLElementIterator = languageLevelOperators.find(lookup); + if (LLElementIterator != languageLevelOperators.end()) lookup = "operator" + lookup; //Search the map auto scopeMap = scope->getDataRef()->scope; @@ -802,7 +829,7 @@ NodeTree* ASTTransformation::scopeLookup(NodeTree* scope, std: std::cout << "could not find " << lookup << " in standard scope, checking for operator" << std::endl; //Note that we don't check for types. At some point we should, as we don't know how to add objects/structs without overloaded operators, etc //Also, we've already searched for the element because this is also how we keep track of operator overloading - if (LLElementIterator != languageLevelScope.end()) { + if (LLElementIterator != languageLevelOperators.end()) { std::cout << "found it at language level as operator." << std::endl; return LLElementIterator->second[0]; } diff --git a/src/CGenerator.cpp b/src/CGenerator.cpp index 5a117ed..44472b3 100644 --- a/src/CGenerator.cpp +++ b/src/CGenerator.cpp @@ -49,7 +49,7 @@ std::string CGenerator::generate(NodeTree* from, NodeTree* enc Poset*> typedefPoset; for (int i = 0; i < children.size(); i++) { if (children[i]->getDataRef()->type == type_def) { - typedefPoset.addVertex(children[i]); //We add this definition by itself just in case there are no dependencies. + typedefPoset.addVertex(children[i]); //We add this definition by itthis just in case there are no dependencies. //If it has dependencies, there's no harm in adding it here //Go through every child in the class looking for declaration statements. For each of these that is not a primitive type //we will add a dependency from this definition to that definition in the poset. @@ -129,10 +129,16 @@ std::string CGenerator::generate(NodeTree* from, NodeTree* enc //return "#include <" + data.symbol.getName() + ">\n"; case identifier: { - //If we're in an object method, and our enclosing scope is that object, we're a member of the object and should use the self reference. + //but first, if we're this, we should just emit. (assuming enclosing object) (note that technically this would fall through, but for errors) + if (data.symbol.getName() == "this") + if (enclosingObject) + return "this"; + else + std::cout << "Error: this used in non-object scope" << std::endl; + //If we're in an object method, and our enclosing scope is that object, we're a member of the object and should use the this reference. std::string preName; if (enclosingObject && enclosingObject->getDataRef()->scope.find(data.symbol.getName()) != enclosingObject->getDataRef()->scope.end()) - preName += "self->"; + preName += "this->"; if (false) for (int j = 0; j < children.size()-1; j++) preName += ValueTypeToCType(children[j]->getData().valueType) + "_"; @@ -213,7 +219,12 @@ std::string CGenerator::generate(NodeTree* from, NodeTree* enc case declaration_statement: if (children.size() == 1) return ValueTypeToCType(children[0]->getData().valueType) + " " + generate(children[0], enclosingObject) + ";"; - else + else if (children[1]->getChildren().size() && children[1]->getChildren()[0]->getChildren().size() > 1 + && children[1]->getChildren()[0]->getChildren()[1] == children[0]) { + //That is, if we're a declaration with an init position call (Object a.construct()) + //We can tell if our function call (children[1])'s access operation([0])'s lhs ([1]) is the thing we just declared (children[0]) + return ValueTypeToCType(children[0]->getData().valueType) + " " + generate(children[0], enclosingObject) + "; " + generate(children[1]) + "/*Init Position Call*/"; + } else return ValueTypeToCType(children[0]->getData().valueType) + " " + generate(children[0], enclosingObject) + " = " + generate(children[1], enclosingObject) + ";"; case if_comp: if (generate(children[0], enclosingObject) == generatorString) @@ -288,7 +299,7 @@ std::string CGenerator::generate(NodeTree* from, NodeTree* enc output += enclosingObject->getDataRef()->symbol.getName() +"__"; /*HERE*/ output += CifyName(name + nameDecoration) + "("; if (isSelfObjectMethod) - output += children.size() > 1 ? "self," : "self"; + output += children.size() > 1 ? "this," : "this"; } } else { //This part handles cases where our definition isn't the function definition (that is, it is probabally the return from another function) @@ -337,7 +348,7 @@ std::string CGenerator::generateObjectMethod(NodeTree* enclosingObject, } output += "\n" + ValueTypeToCType(data.valueType) + " " + CifyName(enclosingObject->getDataRef()->symbol.getName()) +"__" + CifyName(data.symbol.getName()) + nameDecoration + "(" + ValueTypeToCType(&enclosingObjectType) - + " self" + parameters + ")\n" + generate(children[children.size()-1], enclosingObject); //Pass in the object so we can properly handle access to member stuff + + " this" + parameters + ")\n" + generate(children[children.size()-1], enclosingObject); //Pass in the object so we can properly handle access to member stuff return output; } diff --git a/stdlib/io.krak b/stdlib/io.krak index 44c72a2..1d079b7 100644 --- a/stdlib/io.krak +++ b/stdlib/io.krak @@ -11,6 +11,11 @@ void print(char* toPrint) { return; } +void println(char* toPrint) { + print(toPrint); + print("\n"); +} + void print(int toPrint) { __if_comp__ __C__ { __simple_passthrough__ """ @@ -20,6 +25,11 @@ void print(int toPrint) { return; } +void println(int toPrint) { + print(toPrint); + print("\n"); +} + void print(float toPrint) { __if_comp__ __C__ { __simple_passthrough__ """ @@ -27,4 +37,10 @@ void print(float toPrint) { """ } return; -} \ No newline at end of file +} + +void println(float toPrint) { + print(toPrint); + print("\n"); +} + diff --git a/tests/declarationsTest.expected_results b/tests/declarationsTest.expected_results new file mode 100644 index 0000000..e26fda4 --- /dev/null +++ b/tests/declarationsTest.expected_results @@ -0,0 +1,3 @@ +4 +8 +11 diff --git a/tests/declarationsTest.krak b/tests/declarationsTest.krak new file mode 100644 index 0000000..9bfe547 --- /dev/null +++ b/tests/declarationsTest.krak @@ -0,0 +1,26 @@ +import io; +import mem; + +typedef ClassWithConstructor { + int data; + ClassWithConstructor* construct(int inData) { + data = inData; + return this; + } + void printData() { + println(data); + } +}; + +int main() { + ClassWithConstructor object.construct(4); + //ClassWithConstructor object; + //object.construct(4); + object.printData(); + int a = 8; + println(a); + ClassWithConstructor* objPtr = new()->construct(11); + objPtr->printData(); + delete(objPtr); + return 0; +} From 12f57f8ce88d545815bc667a1728e02bac4c3c55 Mon Sep 17 00:00:00 2001 From: Nathan Braswell Date: Sat, 28 Jun 2014 08:31:33 -0700 Subject: [PATCH 25/37] Added support for destructors! This is done by making a void, parameterless member method called destruct which is called when a stack object falls out of scope, if it exists. This is implemented by the generator, in this case CGenerator. --- krakenGrammer.kgm | 2 +- src/CGenerator.cpp | 22 +++++++++++++---- tests/destructorTest.expected_results | 1 + tests/destructorTest.krak | 28 ++++++++++++++++++++++ tests/emptyBracesFunction.expected_results | 1 + tests/emptyBracesFunction.krak | 9 +++++++ 6 files changed, 58 insertions(+), 5 deletions(-) create mode 100644 tests/destructorTest.expected_results create mode 100644 tests/destructorTest.krak create mode 100644 tests/emptyBracesFunction.expected_results create mode 100644 tests/emptyBracesFunction.krak diff --git a/krakenGrammer.kgm b/krakenGrammer.kgm index 85406ee..da9c8c5 100644 --- a/krakenGrammer.kgm +++ b/krakenGrammer.kgm @@ -61,7 +61,7 @@ for_loop = "for" WS "\(" WS statement WS boolean_expression WS ";" WS statement return_statement = "return" | "return" WS boolean_expression ; -code_block = "{" WS statement_list WS "}" ; +code_block = "{" WS statement_list WS "}" | "{" WS "}" ; statement_list = statement_list WS statement | statement ; statement = if_statement | while_loop | for_loop | return_statement WS ";" | boolean_expression WS ";" | assignment_statement WS ";" | declaration_statement WS ";" | code_block | if_comp | simple_passthrough ; diff --git a/src/CGenerator.cpp b/src/CGenerator.cpp index 44472b3..29cb6ff 100644 --- a/src/CGenerator.cpp +++ b/src/CGenerator.cpp @@ -180,18 +180,32 @@ std::string CGenerator::generate(NodeTree* from, NodeTree* enc return output; } case code_block: + { output += "{\n"; - tabLevel++; + std::string destructorString = ""; + tabLevel++; for (int i = 0; i < children.size(); i++) { //std::cout << "Line " << i << std::endl; std::string line = generate(children[i], enclosingObject); //std::cout << line << std::endl; output += line; - } - tabLevel--; + if (children[i]->getChildren().size() && children[i]->getChildren()[0]->getDataRef()->type == declaration_statement) { + NodeTree *identifier = children[i]->getChildren()[0]->getChildren()[0]; + NodeTree *typeDefinition = identifier->getDataRef()->valueType->typeDefinition; + if (!typeDefinition) + continue; + if (typeDefinition->getDataRef()->scope.find("destruct") == typeDefinition->getDataRef()->scope.end()) + continue; + destructorString += tabs() + CifyName(typeDefinition->getDataRef()->symbol.getName()) + + "__" + "destruct" + "(&" + generate(identifier, enclosingObject) + ");\n";//Call the destructor + } + } + output += destructorString; + tabLevel--; output += tabs() + "}"; return output; - case expression: + } + case expression: output += " " + data.symbol.getName() + ", "; case boolean_expression: output += " " + data.symbol.getName() + " "; diff --git a/tests/destructorTest.expected_results b/tests/destructorTest.expected_results new file mode 100644 index 0000000..b96d8a0 --- /dev/null +++ b/tests/destructorTest.expected_results @@ -0,0 +1 @@ +Hello Destructors! diff --git a/tests/destructorTest.krak b/tests/destructorTest.krak new file mode 100644 index 0000000..21a2619 --- /dev/null +++ b/tests/destructorTest.krak @@ -0,0 +1,28 @@ +import io; + +typedef DestructorPrint { + char* myStr; + DestructorPrint* construct(char* str) { + myStr = str; + return this; + } + void destruct() { + println(myStr); + } +}; + +typedef NoDistruction { + int a; + void dummyFunc() {} +}; + +void indirPrint() { + DestructorPrint testObj.construct("Hello Destructors!"); + NoDistruction dummy; +} + +int main() { + indirPrint(); + return 0; +} + diff --git a/tests/emptyBracesFunction.expected_results b/tests/emptyBracesFunction.expected_results new file mode 100644 index 0000000..1621dff --- /dev/null +++ b/tests/emptyBracesFunction.expected_results @@ -0,0 +1 @@ +It was nothing diff --git a/tests/emptyBracesFunction.krak b/tests/emptyBracesFunction.krak new file mode 100644 index 0000000..0fbe029 --- /dev/null +++ b/tests/emptyBracesFunction.krak @@ -0,0 +1,9 @@ +import io; + +void nothing() {} + +int main() { + nothing(); + println("It was nothing"); + return 0; +} From 03770028ad25acbe94f5138eab73623137dd6dcc Mon Sep 17 00:00:00 2001 From: Nathan Braswell Date: Mon, 30 Jun 2014 01:57:50 -0700 Subject: [PATCH 26/37] Fixed some bugs in Parser::firstSet and added a bit of caching. It still doesn't work quite right, though, there's some problem with nullable left recursion. However, it's better than it was, and I need to go to bed. More work later. --- include/GraphStructuredStack.h | 1 + include/ParseAction.h | 12 +++-- include/ParseRule.h | 12 ++--- include/Parser.h | 12 +++-- include/RNGLRParser.h | 3 ++ include/Table.h | 6 ++- src/GraphStructuredStack.cpp | 7 +++ src/Importer.cpp | 7 ++- src/ParseAction.cpp | 29 +++++++--- src/ParseRule.cpp | 26 +++++++-- src/Parser.cpp | 88 ++++++++++++++++++------------- src/RNGLRParser.cpp | 36 ++++++++++--- src/Table.cpp | 15 +++++- stdlib/io.krak | 10 ++-- stdlib/mem.krak | 6 +++ stdlib/util.krak | 12 +++++ stdlib/vector.krak | 52 ++++++++++++++++++ tests/vectorTest.expected_results | 2 + tests/vectorTest.krak | 15 ++++++ 19 files changed, 273 insertions(+), 78 deletions(-) create mode 100644 stdlib/util.krak create mode 100644 stdlib/vector.krak create mode 100644 tests/vectorTest.expected_results create mode 100644 tests/vectorTest.krak diff --git a/include/GraphStructuredStack.h b/include/GraphStructuredStack.h index e79a8fe..7d07443 100644 --- a/include/GraphStructuredStack.h +++ b/include/GraphStructuredStack.h @@ -27,6 +27,7 @@ class GraphStructuredStack { void addEdge(NodeTree* start, NodeTree* end, NodeTree* edge); void clear(); + std::vector getFrontier(int frontier); std::string toString(); private: std::vector*>*> gss; diff --git a/include/ParseAction.h b/include/ParseAction.h index 175dd61..a15aca0 100644 --- a/include/ParseAction.h +++ b/include/ParseAction.h @@ -11,6 +11,7 @@ #include #include + class ParseAction { public: enum ActionType { INVALID, REDUCE, SHIFT, ACCEPT, REJECT }; @@ -18,10 +19,11 @@ class ParseAction { ParseAction(ActionType action, ParseRule* reduceRule); ParseAction(ActionType action, int shiftState); ~ParseAction(); - bool const equalsExceptLookahead(const ParseAction &other); - bool const operator==(const ParseAction &other); - bool const operator!=(const ParseAction &other); - std::string toString(); + bool const equalsExceptLookahead(const ParseAction &other) const; + bool const operator==(const ParseAction &other) const; + bool const operator!=(const ParseAction &other) const; + bool const operator<(const ParseAction &other) const; + std::string toString(bool printRuleLookahead = true); static std::string actionToString(ActionType action); ActionType action; @@ -31,4 +33,4 @@ class ParseAction { }; -#endif \ No newline at end of file +#endif diff --git a/include/ParseRule.h b/include/ParseRule.h index dd3ac37..94d602a 100644 --- a/include/ParseRule.h +++ b/include/ParseRule.h @@ -16,10 +16,10 @@ class ParseRule { ParseRule(); ParseRule(Symbol leftHandle, int pointerIndex, std::vector &rightSide, std::vector* lookahead); ~ParseRule(); - const bool equalsExceptLookahead(const ParseRule &other); - bool const operator==(const ParseRule &other); - bool const operator!=(const ParseRule &other); - + const bool equalsExceptLookahead(const ParseRule &other) const; + bool const operator==(const ParseRule &other) const; + bool const operator!=(const ParseRule &other) const; + bool const operator<(const ParseRule &other) const; //Used for ordering so we can put ParseRule's in sets, and also so that ParseActions will have an ordering ParseRule* clone(); void setLeftHandle(Symbol leftHandle); @@ -40,7 +40,7 @@ class ParseRule { void addLookahead(std::vector* lookahead); std::vector* getLookahead(); - std::string toString(); + std::string toString(bool printLookahead = true); std::string toDOT(); private: @@ -51,4 +51,4 @@ class ParseRule { }; -#endif \ No newline at end of file +#endif diff --git a/include/Parser.h b/include/Parser.h index 6f1cc49..25daf02 100644 --- a/include/Parser.h +++ b/include/Parser.h @@ -12,6 +12,7 @@ #include "Table.h" #include +#include #include #include #include @@ -36,8 +37,13 @@ class Parser { void importTable(char* tableData); protected: - std::vector* firstSet(Symbol token); - std::vector* firstSet(Symbol token, std::vector avoidList); + std::vector firstSet(Symbol token, std::vector avoidList = std::vector(), bool addNewTokens = true); + bool isNullable(Symbol token); + bool isNullableHelper(Symbol token, std::set done); + + std::map> tokenFirstSet; + std::map tokenNullable; + std::vector* incrementiveFollowSet(ParseRule* rule); virtual void closure(State* state); virtual void addStates(std::vector< State* >* stateSets, State* state, std::queue* toDo); @@ -65,4 +71,4 @@ class Parser { NodeTree* reduceTreeCombine(Symbol newSymbol, std::vector &symbols); }; -#endif \ No newline at end of file +#endif diff --git a/include/RNGLRParser.h b/include/RNGLRParser.h index 6b285e7..74c47ef 100644 --- a/include/RNGLRParser.h +++ b/include/RNGLRParser.h @@ -5,6 +5,8 @@ #include #include #include +#include +#include #include #include "Parser.h" #include "Symbol.h" @@ -16,6 +18,7 @@ class RNGLRParser: public Parser { RNGLRParser(); ~RNGLRParser(); NodeTree* parseInput(std::string inputString); + void printReconstructedFrontier(int frontier); private: void reducer(int i); diff --git a/include/Table.h b/include/Table.h index 6b8ce88..ca2ace9 100644 --- a/include/Table.h +++ b/include/Table.h @@ -1,5 +1,8 @@ #include +#include +#include + #include "util.h" #include "ParseRule.h" #include "ParseAction.h" @@ -20,7 +23,8 @@ class Table { void remove(int stateNum, Symbol tranSymbol); std::vector* get(int state, Symbol token); ParseAction* getShift(int state, Symbol token); - std::string toString(); + std::vector> stateAsParseActionVector(int state); + std::string toString(); private: std::vector< std::vector< std::vector* >* > table; std::vector symbolIndexVec; diff --git a/src/GraphStructuredStack.cpp b/src/GraphStructuredStack.cpp index dcdf2ff..1d117f3 100644 --- a/src/GraphStructuredStack.cpp +++ b/src/GraphStructuredStack.cpp @@ -117,6 +117,13 @@ void GraphStructuredStack::addEdge(NodeTree* start, NodeTree* end, Nod edges[std::make_pair(start, end)] = edge; } +std::vector GraphStructuredStack::getFrontier(int frontier) { + std::vector toReturn; + for (int i = 0; i < gss[frontier]->size(); i++) + toReturn.push_back((*(gss[frontier]))[i]->getData()); + return toReturn; +} + std::string GraphStructuredStack::toString() { std::string tostring = ""; for (std::vector*>*>::size_type i = 0; i < gss.size(); i++) { diff --git a/src/Importer.cpp b/src/Importer.cpp index fb45a03..1706e5b 100644 --- a/src/Importer.cpp +++ b/src/Importer.cpp @@ -66,7 +66,8 @@ NodeTree* Importer::importFirstPass(std::string fileName) { NodeTree* ast = getUnit(fileName); if (ast == NULL) { NodeTree* parseTree = parseAndTrim(fileName); - + if (!parseTree) + return NULL; //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 } @@ -160,7 +161,9 @@ NodeTree* Importer::parseAndTrim(std::string fileName) { outFile << parseTree->DOTGraphString() << std::endl; } else { std::cout << "ParseTree returned from parser for " << fileName << " is NULL!" << std::endl; - } + outFile.close(); outFileTransformed.close(); + return NULL; + } outFile.close(); //Remove Transformations diff --git a/src/ParseAction.cpp b/src/ParseAction.cpp index 64f3e95..1e21714 100644 --- a/src/ParseAction.cpp +++ b/src/ParseAction.cpp @@ -22,18 +22,33 @@ ParseAction::~ParseAction() { } -const bool ParseAction::equalsExceptLookahead(const ParseAction &other) { +const bool ParseAction::equalsExceptLookahead(const ParseAction &other) const { return( action == other.action && ( reduceRule == other.reduceRule || reduceRule->equalsExceptLookahead(*(other.reduceRule)) ) && shiftState == other.shiftState); } -const bool ParseAction::operator==(const ParseAction &other) { +const bool ParseAction::operator==(const ParseAction &other) const { return( action == other.action && ( reduceRule == other.reduceRule || *reduceRule == *(other.reduceRule) ) && shiftState == other.shiftState); } -const bool ParseAction::operator!=(const ParseAction &other) { +const bool ParseAction::operator!=(const ParseAction &other) const { return !(this->operator==(other)); } +//Exists so we can put ParseActions into sets +const bool ParseAction::operator<(const ParseAction &other) const { + if (action != other.action) + return action < other.action; + if (reduceRule != other.reduceRule) { + if (! (reduceRule && other.reduceRule)) { + return reduceRule < other.reduceRule; + } else { + return *reduceRule < *(other.reduceRule); + } + } + + return shiftState < other.shiftState; +} + std::string ParseAction::actionToString(ActionType action) { switch (action) { case REDUCE: @@ -53,12 +68,12 @@ std::string ParseAction::actionToString(ActionType action) { } } -std::string ParseAction::toString() { +std::string ParseAction::toString(bool printRuleLookahead) { std::string outputString = ""; outputString += actionToString(action); if (reduceRule != NULL) - outputString += " " + reduceRule->toString(); + outputString += " " + reduceRule->toString(printRuleLookahead); if (shiftState != -1) - outputString += " " + intToString(shiftState); + outputString += " " + intToString(shiftState); return(outputString); -} \ No newline at end of file +} diff --git a/src/ParseRule.cpp b/src/ParseRule.cpp index e27208a..2b8996c 100644 --- a/src/ParseRule.cpp +++ b/src/ParseRule.cpp @@ -16,18 +16,34 @@ ParseRule::~ParseRule() { } -const bool ParseRule::equalsExceptLookahead(const ParseRule &other) { +const bool ParseRule::equalsExceptLookahead(const ParseRule &other) const { return(leftHandle == other.leftHandle && rightSide == other.rightSide && pointerIndex == other.pointerIndex); } -const bool ParseRule::operator==(const ParseRule &other) { +const bool ParseRule::operator==(const ParseRule &other) const { return(equalsExceptLookahead(other) && (lookahead == NULL ? other.lookahead == NULL : (*lookahead) == *(other.lookahead))); } -const bool ParseRule::operator!=(const ParseRule &other) { +const bool ParseRule::operator!=(const ParseRule &other) const { return !(this->operator==(other)); } +const bool ParseRule::operator<(const ParseRule &other) const { + //Used for ordering so we can put ParseRule's in sets, and also so that ParseActions will have an ordering + if (leftHandle != other.leftHandle) + return leftHandle < other.leftHandle; + if (rightSide != other.rightSide) + return rightSide < other.rightSide; + if (lookahead != other.lookahead) { + if (! (lookahead && other.lookahead)) { + return lookahead < other.lookahead; + } else { + return *lookahead < *(other.lookahead); + } + } + return false; +} + ParseRule* ParseRule::clone() { std::vector* newLookahead = NULL; if (lookahead) { @@ -111,7 +127,7 @@ std::vector* ParseRule::getLookahead() { return lookahead; } -std::string ParseRule::toString() { +std::string ParseRule::toString(bool printLookahead) { std::string concat = leftHandle.toString() + " -> "; for (int i = 0; i < rightSide.size(); i++) { if (i == pointerIndex) @@ -120,7 +136,7 @@ std::string ParseRule::toString() { } if (pointerIndex >= rightSide.size()) concat += "(*)"; - if (lookahead != NULL) { + if (printLookahead && lookahead != NULL) { concat += "**"; for (std::vector::size_type i = 0; i < lookahead->size(); i++) concat += (*lookahead)[i].toString(); diff --git a/src/Parser.cpp b/src/Parser.cpp index 5971829..524b888 100644 --- a/src/Parser.cpp +++ b/src/Parser.cpp @@ -117,59 +117,76 @@ int Parser::stateNum(State* state) { return -1; } -std::vector* Parser::firstSet(Symbol token) { - std::vector avoidList; - return firstSet(token, avoidList); -} - -std::vector* Parser::firstSet(Symbol token, std::vector avoidList) { - //If we've already done this token, don't do it again +std::vector Parser::firstSet(Symbol token, std::vector avoidList, bool addNewTokens) { + if (tokenFirstSet.find(token) != tokenFirstSet.end()) + return tokenFirstSet[token]; + //If we've already done this token, don't do it again for (std::vector::size_type i = 0; i < avoidList.size(); i++) - if (avoidList[i] == token) { - return new std::vector(); - } + if (avoidList[i] == token) + return std::vector(); avoidList.push_back(token); - std::vector* first = new std::vector(); + + std::vector first; //First, if the symbol is a terminal, than it's first set is just itself. if (token.isTerminal()) { - first->push_back(token); + first.push_back(token); return(first); } //Otherwise.... //Ok, to make a first set, go through the grammer, if the token it's left side, add it's production's first token's first set. //If that one includes mull, do the next one too (if it exists). Symbol rightToken; - std::vector* recursiveFirstSet = NULL; + std::vector recursiveFirstSet; for (std::vector::size_type i = 0; i < loadedGrammer.size(); i++) { if (token == loadedGrammer[i]->getLeftSide()) { //Loop through the rule adding first sets for each token if the previous token contained NULL - bool recFirstSetHasNull = false; int j = 0; do { rightToken = loadedGrammer[i]->getRightSide()[j]; //Get token of the right side of this rule if (rightToken.isTerminal()) { - recursiveFirstSet = new std::vector(); - recursiveFirstSet->push_back(rightToken); + recursiveFirstSet.push_back(rightToken); } else { //Add the entire set - recursiveFirstSet = firstSet(rightToken, avoidList); + recursiveFirstSet = firstSet(rightToken, avoidList, false);//Don't add children to cache, as early termination may cause them to be incomplete } - first->insert(first->end(), recursiveFirstSet->begin(), recursiveFirstSet->end()); - //Check to see if the current recursiveFirstSet contains NULL, if so, then go through again with the next token. (if there is one) - recFirstSetHasNull = false; - for (std::vector::size_type k = 0; k < recursiveFirstSet->size(); k++) { - if ((*recursiveFirstSet)[k] == nullSymbol) { - recFirstSetHasNull = true; - } - } - delete recursiveFirstSet; + first.insert(first.end(), recursiveFirstSet.begin(), recursiveFirstSet.end()); j++; - } while (recFirstSetHasNull && loadedGrammer[i]->getRightSide().size() > j); + } while (isNullable(rightToken) && loadedGrammer[i]->getRightSide().size() > j); } } + if (addNewTokens) + tokenFirstSet[token] = first; return(first); } +bool Parser::isNullable(Symbol token) { + if (tokenNullable.find(token) != tokenNullable.end()) + return tokenNullable[token]; + bool nullable = isNullableHelper(token, std::set()); + tokenNullable[token] = nullable; + return nullable; +} +//We use this helper function to recurse because it is possible to wind up with loops, and if so we want +//early termination. However, this means that nullable determinations in the middle of the loop are inaccurate +//(since we terminated early), so we don't want to save them. Thus, for simplicity, only the main method will +//add to the cache. This is somewhat unfortunate for preformance, but the necessary additions to keep track of +//invalidated state are more complicated than it's worth. +bool Parser::isNullableHelper(Symbol token, std::set done) { + if (token.isTerminal()) + return token == nullSymbol; + if (done.find(token) != done.end()) + return false; + done.insert(token); + if (tokenNullable.find(token) != tokenNullable.end()) + return tokenNullable[token]; + //Note that we only have to check the first token on the right side, as we would only get to the other tokens if it is nullable, which is what we're checking + for (std::vector::size_type i = 0; i < loadedGrammer.size(); i++) + if (token == loadedGrammer[i]->getLeftSide()) + if (isNullableHelper(loadedGrammer[i]->getRightSide()[0], done)) + return true; + return false; +} + //Return the correct lookahead. This followSet is built based on the current rule's lookahead if at end, or the next Symbol's first set. std::vector* Parser::incrementiveFollowSet(ParseRule* rule) { //Advance the pointer past the current Symbol (the one we want the followset for) to the next symbol (which might be in our follow set, or might be the end) @@ -178,25 +195,24 @@ std::vector* Parser::incrementiveFollowSet(ParseRule* rule) { //Get the first set of the next Symbol. If it contains nullSymbol, keep doing for the next one std::vector* followSet = new std::vector(); - std::vector* symbolFirstSet; + std::vector symbolFirstSet; bool symbolFirstSetHasNull = true; while (symbolFirstSetHasNull && !rule->isAtEnd()) { symbolFirstSetHasNull = false; symbolFirstSet = firstSet(rule->getAtNextIndex()); - for (std::vector::size_type i = 0; i < symbolFirstSet->size(); i++) { - if ((*symbolFirstSet)[i] == nullSymbol) { + for (std::vector::size_type i = 0; i < symbolFirstSet.size(); i++) { + if (symbolFirstSet[i] == nullSymbol) { symbolFirstSetHasNull = true; - symbolFirstSet->erase(symbolFirstSet->begin()+i); + symbolFirstSet.erase(symbolFirstSet.begin()+i); break; } } - followSet->insert(followSet->end(), symbolFirstSet->begin(), symbolFirstSet->end()); - delete symbolFirstSet; + followSet->insert(followSet->end(), symbolFirstSet.begin(), symbolFirstSet.end()); rule->advancePointer(); } if (rule->isAtEnd()) { - symbolFirstSet = rule->getLookahead(); - followSet->insert(followSet->end(), symbolFirstSet->begin(), symbolFirstSet->end()); + symbolFirstSet = *(rule->getLookahead()); + followSet->insert(followSet->end(), symbolFirstSet.begin(), symbolFirstSet.end()); } std::vector* followSetReturn = new std::vector(); for (std::vector::size_type i = 0; i < followSet->size(); i++) { @@ -261,7 +277,7 @@ void Parser::addStates(std::vector< State* >* stateSets, State* state, std::queu //Clone the current rule ParseRule* advancedRule = (*currStateTotal)[i]->clone(); //Try to advance the pointer, if sucessful see if it is the correct next symbol - if (advancedRule->advancePointer()) { + if (advancedRule->advancePointer()) { //Technically, it should be the set of rules sharing this symbol advanced past in the basis for new state //So search our new states to see if any of them use this advanced symbol as a base. diff --git a/src/RNGLRParser.cpp b/src/RNGLRParser.cpp index cbd111f..8495042 100644 --- a/src/RNGLRParser.cpp +++ b/src/RNGLRParser.cpp @@ -8,6 +8,20 @@ RNGLRParser::~RNGLRParser() { // } +void RNGLRParser::printReconstructedFrontier(int frontier) { + std::vector lastFrontier = gss.getFrontier(frontier); + for (int j = 0; j < lastFrontier.size(); j++) { + std::cout << "State: " << lastFrontier[j] << std::endl; + std::vector> stateParseActions = table.stateAsParseActionVector(lastFrontier[j]); + std::set> noRepeats; + for (auto k : stateParseActions) + noRepeats.insert(k); + for (auto k : noRepeats) + std::cout << k.first << " " << k.second.toString(false) << std::endl; + std::cout << std::endl; + } +} + NodeTree* RNGLRParser::parseInput(std::string inputString) { input.clear(); gss.clear(); @@ -53,7 +67,7 @@ NodeTree* RNGLRParser::parseInput(std::string inputString) { // std::cout << "\nDone with Lexing, length:" << input.size() << std::endl; // std::cout << input[0].toString() << std::endl; - + // for (int i = 0; i < input.size(); i++) // std::cout << "|" << input[i]->toString() << "|"; // std::cout << std::endl; @@ -74,7 +88,6 @@ NodeTree* RNGLRParser::parseInput(std::string inputString) { else if (firstActions[i]->action == ParseAction::REDUCE && fullyReducesToNull(firstActions[i]->reduceRule)) { Reduction newReduction = {v0, firstActions[i]->reduceRule->getLeftSide(), 0, getNullableParts(firstActions[i]->reduceRule), NULL}; toReduce.push(newReduction); - //toReduce.push(std::make_pair(std::make_pair(v0, firstActions[i]->reduceRule->getLeftSide()), 0)); } } @@ -89,14 +102,21 @@ NodeTree* RNGLRParser::parseInput(std::string inputString) { std::cout << "Parsing failed on " << input[i].toString() << std::endl; std::cout << "Problem is on line: " << findLine(i) << std::endl; std::cout << "Nearby is:" << std::endl; - const int range = 10; + int range = 10; for (int j = (i-range >= 0 ? i-range : 0); j < (i+range < input.size() ? i+range : input.size()); j++) if (j == i) std::cout << "||*||*||" << input[j].toString() << "||*||*|| "; else std::cout << input[j].toString() << " "; std::cout << std::endl; - break; + range = 3; + std::cout << "\n\n\nThe states in the GSS at last frontiers:" << std::endl; + for (int j = (i-range >= 0 ? i-range : 0); j < i; j++) { + std::cout << "Frontier:" << j << " (would get): " << input[j].toString() << std::endl; + printReconstructedFrontier(j); + } + std::cout << "\n\n\n\n" << std::endl; + break; } //Clear the vector of SPPF nodes created every step @@ -186,7 +206,7 @@ void RNGLRParser::reducer(int i) { toStateNode = gss.newNode(toState); gss.addToFrontier(i, toStateNode); gss.addEdge(toStateNode, currentReached, newLabel); - + //std::cout << "Adding shifts and reductions for a state that did not exist" << std::endl; std::vector actions = *(table.get(toState, input[i])); for (std::vector::size_type k = 0; k < actions.size(); k++) { @@ -319,7 +339,7 @@ void RNGLRParser::addStates(std::vector< State* >* stateSets, State* state, std: //Clone the current rule ParseRule* advancedRule = (*currStateTotal)[i]->clone(); //Try to advance the pointer, if sucessful see if it is the correct next symbol - if (advancedRule->advancePointer()) { + if (advancedRule->advancePointer()) { //Technically, it should be the set of rules sharing this symbol advanced past in the basis for new state //So search our new states to see if any of them use this advanced symbol as a base. @@ -353,10 +373,10 @@ void RNGLRParser::addStates(std::vector< State* >* stateSets, State* state, std: stateAlreadyInAllStates = true; //If it does exist, we should add it as the shift/goto in the action table //std::cout << "newStates[" << i << "] == stateSets[" << j << "]" << std::endl; - + if (!((*stateSets)[j]->basisEquals(*(newStates[i])))) toDo->push((*stateSets)[j]); - + (*stateSets)[j]->combineStates(*(newStates[i])); //std::cout << j << "\t Hay, doing an inside loop state reductions!" << std::endl; addStateReductionsToTable((*stateSets)[j]); diff --git a/src/Table.cpp b/src/Table.cpp index 5f37e1f..e4cdfd4 100644 --- a/src/Table.cpp +++ b/src/Table.cpp @@ -251,7 +251,7 @@ void Table::add(int stateNum, Symbol tranSymbol, ParseAction* action) { //If this table slot is empty //std::cout << "table[stateNum] is " << table[stateNum] << std::endl; //std::cout << "blank is " << (*(table[stateNum]))[symbolIndex] << std::endl; - + if ( (*(table[stateNum]))[symbolIndex] == NULL ) { //std::cout << "Null, adding " << action->toString() << std::endl; std::vector* actionList = new std::vector(); @@ -262,7 +262,7 @@ void Table::add(int stateNum, Symbol tranSymbol, ParseAction* action) { //else if ( !(*(table[stateNum]))[symbolIndex]->equalsExceptLookahead(*action)) { else { //std::cout << "not Null!" << std::endl; - //std::cout << "State: " << stateNum << " Conflict between old: " << (*(table[stateNum]))[symbolIndex]->toString() << " and new: " << action->toString() << " on " << tranSymbol->toString() << std::endl; + //std::cout << "State: " << stateNum << " Conflict between old: " << (*(table[stateNum]))[symbolIndex]->toString() << " and new: " << action->toString() << " on " << tranSymbol->toString() << std::endl; //Check to see if this action is already in the list @@ -353,6 +353,17 @@ ParseAction* Table::getShift(int state, Symbol token) { return shift; } +std::vector> Table::stateAsParseActionVector(int state) { + std::vector> reconstructedState; + std::vector*>* stateVec = table[state]; + for (int i = 0; i < stateVec->size(); i++) + if (std::vector* forStateAndSymbol = (*stateVec)[i]) + for (int j = 0; j < forStateAndSymbol->size(); j++) + reconstructedState.push_back(std::make_pair(symbolIndexVec[i].toString(),*((*forStateAndSymbol)[j]))); + + return reconstructedState; +} + std::string Table::toString() { std::string concat = ""; for (std::vector::size_type i = 0; i < symbolIndexVec.size(); i++) diff --git a/stdlib/io.krak b/stdlib/io.krak index 1d079b7..9cf6dab 100644 --- a/stdlib/io.krak +++ b/stdlib/io.krak @@ -2,6 +2,10 @@ __if_comp__ __C__ __simple_passthrough__ """ #include """ +void println() { + print("\n"); +} + void print(char* toPrint) { __if_comp__ __C__ { __simple_passthrough__ """ @@ -13,7 +17,7 @@ void print(char* toPrint) { void println(char* toPrint) { print(toPrint); - print("\n"); + println(); } void print(int toPrint) { @@ -27,7 +31,7 @@ void print(int toPrint) { void println(int toPrint) { print(toPrint); - print("\n"); + println(); } void print(float toPrint) { @@ -41,6 +45,6 @@ void print(float toPrint) { void println(float toPrint) { print(toPrint); - print("\n"); + println(); } diff --git a/stdlib/mem.krak b/stdlib/mem.krak index 0e9bef1..13c4b2a 100644 --- a/stdlib/mem.krak +++ b/stdlib/mem.krak @@ -50,6 +50,12 @@ template T* new() { return new(1); } +template void delete(T* toDelete, int itemDestructCount) { + for (int i = 0; i < itemDestructCount; i++) + toDelete[i].destruct(); + delete(toDelete); +} + template void delete(T* toDelete) { free(toDelete); } diff --git a/stdlib/util.krak b/stdlib/util.krak new file mode 100644 index 0000000..02416d6 --- /dev/null +++ b/stdlib/util.krak @@ -0,0 +1,12 @@ + +template T greater(T a, T b) { + if (a > b) + return a; + return b; +} + +template T lesser(T a, T b) { + if (a > b) + return b; + return a; +} diff --git a/stdlib/vector.krak b/stdlib/vector.krak new file mode 100644 index 0000000..a8d8537 --- /dev/null +++ b/stdlib/vector.krak @@ -0,0 +1,52 @@ +import mem; +import util; + +typedef template vector { + T *data; + int size; + int available; + vector *construct() { + size = 0; + available = 8; + data = new(8); + return this; + } + + void destruct() { + //Destruction of contained data should depend on if the stored things are objects or primitives. + delete(data, size); + } + + bool resize(int newSize) { + T* newData = new(newSize); + if (!newData) + return false; + for (int i = 0; i < lesser(size, newSize); i++;) + newData[i] = data[i]; + delete(data, 0); + return true; + } + + T at(int index) { + return get(index); + } + + T get(int index) { + if (index < 0 || index >= size) + return null; + return data[index]; + } + + void set(int index, T dataIn) { + if (index < 0 || index => size) + return; + data[index] = dataIn; + } + void addEnd(T dataIn) { + if (size < available) + size++; + else + resize(size*2); + data[size-1]; + } +}; diff --git a/tests/vectorTest.expected_results b/tests/vectorTest.expected_results new file mode 100644 index 0000000..d472488 --- /dev/null +++ b/tests/vectorTest.expected_results @@ -0,0 +1,2 @@ +1337 + diff --git a/tests/vectorTest.krak b/tests/vectorTest.krak new file mode 100644 index 0000000..b55fe50 --- /dev/null +++ b/tests/vectorTest.krak @@ -0,0 +1,15 @@ +import io; +import vector; + +int main() { + vector intVec.construct(); + intVec.addBack(1); + intVec.addBack(3); + intVec.addBack(3); + intVec.addBack(7); + for (int i = 0; i < intVec.size(); i++;) + print(intVec.at(i)); + + println(); + return 0; +} From 22fbd61360d76054e1ba394f4a9741e58b2f5cc7 Mon Sep 17 00:00:00 2001 From: Nathan Braswell Date: Wed, 2 Jul 2014 01:18:27 -0700 Subject: [PATCH 27/37] Fixed a pretty bad error in isNullable logic, I must have been tired. Also, edited grammer to support a[n].b, which was previously done with wrong operator precedence so that that construction was illegal. vector.krak still doesn't quite parse, but that's because of some error with if (!name) which I will fix later. Bedtime. --- krakenGrammer.kgm | 4 ++-- src/ASTTransformation.cpp | 33 ++++++++++++++++++--------------- src/Parser.cpp | 18 ++++++++++++++---- src/RNGLRParser.cpp | 2 +- stdlib/mem.krak | 4 ++-- 5 files changed, 37 insertions(+), 24 deletions(-) diff --git a/krakenGrammer.kgm b/krakenGrammer.kgm index da9c8c5..755de32 100644 --- a/krakenGrammer.kgm +++ b/krakenGrammer.kgm @@ -75,8 +75,8 @@ comparator = "==" | "<=" | ">=" | "!=" | "<" | ">" ; expression = expression WS "<<" WS term | expression WS ">>" WS shiftand | shiftand ; shiftand = shiftand WS "-" WS term | shiftand WS "\+" WS term | term ; term = term WS forward_slash WS factor | term WS "\*" WS factor | term WS "%" WS factor | factor ; -factor = "\+\+" WS unarad | unarad WS "\+\+" | "--" WS unarad | unarad WS "--" | "\+" WS unarad | "-" WS unarad | "!" WS unarad | "~" WS unarad | "\(" WS type WS "\)" WS unarad | "\*" WS unarad | "&" WS unarad | unarad WS "[" WS expression WS "]" | unarad ; -unarad = number | identifier | identifier WS template_inst | function_call | bool | string | character | "\(" WS boolean_expression WS "\)" | access_operation ; +factor = "\+\+" WS unarad | unarad WS "\+\+" | "--" WS unarad | unarad WS "--" | "\+" WS unarad | "-" WS unarad | "!" WS unarad | "~" WS unarad | "\(" WS type WS "\)" WS unarad | "\*" WS unarad | "&" WS unarad | unarad ; +unarad = number | identifier | identifier WS template_inst | function_call | bool | string | character | "\(" WS boolean_expression WS "\)" | access_operation | unarad WS "[" WS expression WS "]" ; number = integer | float | double ; access_operation = unarad "." identifier | unarad "->" identifier ; diff --git a/src/ASTTransformation.cpp b/src/ASTTransformation.cpp index 160e14c..d50d8dc 100644 --- a/src/ASTTransformation.cpp +++ b/src/ASTTransformation.cpp @@ -467,9 +467,21 @@ NodeTree* ASTTransformation::transform(NodeTree* from, NodeTree return transform(children[0], scope, types, templateTypeReplacements, instantiateTemplates); //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") { //unarad can ride through, it should always just be a promoted child + } 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) { + /* else if (children.size() >= 4) { //Array brackets [] + funcName = "[]"; + std::vector*> transformedChildren; + transformedChildren.push_back(transform(children[0], scope, types, templateTypeReplacements, instantiateTemplates)); + transformedChildren.push_back(transform(children[2], scope, types, templateTypeReplacements, instantiateTemplates)); + NodeTree* function = doFunction(scope, funcName, transformedChildren, templateTypeReplacements); + if (function == NULL) { + std::cout << "scope lookup error! Could not find " << funcName << " in factor " << std::endl; + throw "LOOKUP ERROR: " + funcName; + } + return function; + }*/ NodeTree* lhs = transform(children[0], scope, std::vector(), templateTypeReplacements, instantiateTemplates); //LHS does not inherit types NodeTree* rhs; if (name == "access_operation") { @@ -480,7 +492,9 @@ NodeTree* ASTTransformation::transform(NodeTree* from, NodeTree rhs = transform(children[2], scope, types, templateTypeReplacements, instantiateTemplates); std::string functionCallName = concatSymbolTree(children[1]); - //std::cout << "scope lookup from expression or similar" << std::endl; + if (functionCallName == "[") + functionCallName = "[]"; //fudge the lookup of brackets because only one is at children[1] (the other is at children[3]) + //std::cout << "scope lookup from expression or similar" << std::endl; std::vector*> transformedChildren; transformedChildren.push_back(lhs); transformedChildren.push_back(rhs); newNode = doFunction(scope, functionCallName, transformedChildren, templateTypeReplacements); if (newNode == NULL) { @@ -491,8 +505,8 @@ NodeTree* ASTTransformation::transform(NodeTree* from, NodeTree // //Set the value of this function call if (newNode->getDataRef()->valueType == NULL && rhs->getDataRef()->valueType) newNode->getDataRef()->valueType = rhs->getDataRef()->valueType; - else - newNode->getDataRef()->valueType = NULL; + //else + // newNode->getDataRef()->valueType = NULL; std::cout << "function call to " << functionCallName << " - " << newNode->getName() << " is now " << newNode->getDataRef()->valueType << std::endl; return newNode; //skipChildren.insert(1); @@ -522,17 +536,6 @@ NodeTree* ASTTransformation::transform(NodeTree* from, NodeTree throw "LOOKUP ERROR: " + funcName; } - return function; - } else if (children.size() >= 4) { //Array brackets [] - funcName = "[]"; - std::vector*> transformedChildren; - transformedChildren.push_back(transform(children[0], scope, types, templateTypeReplacements, instantiateTemplates)); - transformedChildren.push_back(transform(children[2], scope, types, templateTypeReplacements, instantiateTemplates)); - NodeTree* function = doFunction(scope, funcName, transformedChildren, templateTypeReplacements); - if (function == NULL) { - std::cout << "scope lookup error! Could not find " << funcName << " in factor " << std::endl; - throw "LOOKUP ERROR: " + funcName; - } return function; } else { return transform(children[0], scope, types, templateTypeReplacements, instantiateTemplates); //Just a promoted child, so do it instead diff --git a/src/Parser.cpp b/src/Parser.cpp index 524b888..4a87119 100644 --- a/src/Parser.cpp +++ b/src/Parser.cpp @@ -179,11 +179,21 @@ bool Parser::isNullableHelper(Symbol token, std::set done) { done.insert(token); if (tokenNullable.find(token) != tokenNullable.end()) return tokenNullable[token]; - //Note that we only have to check the first token on the right side, as we would only get to the other tokens if it is nullable, which is what we're checking - for (std::vector::size_type i = 0; i < loadedGrammer.size(); i++) - if (token == loadedGrammer[i]->getLeftSide()) - if (isNullableHelper(loadedGrammer[i]->getRightSide()[0], done)) + + for (std::vector::size_type i = 0; i < loadedGrammer.size(); i++) { + if (token == loadedGrammer[i]->getLeftSide()) { + auto rightSide = loadedGrammer[i]->getRightSide(); + bool ruleNullable = true; + for (int j = 0; j < rightSide.size(); j++) { + if (!isNullableHelper(rightSide[j], done)) { + ruleNullable = false; + break; + } + } + if (ruleNullable) return true; + } + } return false; } diff --git a/src/RNGLRParser.cpp b/src/RNGLRParser.cpp index 8495042..400b4c4 100644 --- a/src/RNGLRParser.cpp +++ b/src/RNGLRParser.cpp @@ -109,7 +109,7 @@ NodeTree* RNGLRParser::parseInput(std::string inputString) { else std::cout << input[j].toString() << " "; std::cout << std::endl; - range = 3; + range = 1; std::cout << "\n\n\nThe states in the GSS at last frontiers:" << std::endl; for (int j = (i-range >= 0 ? i-range : 0); j < i; j++) { std::cout << "Frontier:" << j << " (would get): " << input[j].toString() << std::endl; diff --git a/stdlib/mem.krak b/stdlib/mem.krak index 13c4b2a..e52a85d 100644 --- a/stdlib/mem.krak +++ b/stdlib/mem.krak @@ -51,9 +51,9 @@ template T* new() { } template void delete(T* toDelete, int itemDestructCount) { - for (int i = 0; i < itemDestructCount; i++) + for (int i = 0; i < itemDestructCount; i++;) toDelete[i].destruct(); - delete(toDelete); + delete(toDelete); } template void delete(T* toDelete) { From 91a68ac2b16b7c7369afde9c1af7c803f05e1e88 Mon Sep 17 00:00:00 2001 From: Nathan Braswell Date: Thu, 3 Jul 2014 01:52:44 -0700 Subject: [PATCH 28/37] Fixed silly not bug - in one location ! was written \!, which made practically no difference to the regex, but made it so that the parser wouldn't match it to !. Also added else to grammer, but this needs work in the ASTTransformation and CGenerator. --- krakenGrammer.kgm | 6 +++--- stdlib/vector.krak | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/krakenGrammer.kgm b/krakenGrammer.kgm index 755de32..02598ac 100644 --- a/krakenGrammer.kgm +++ b/krakenGrammer.kgm @@ -36,7 +36,7 @@ triple_quoted_string = "\"\"\"((\"\"(`|1|2|3|4|5|6|7|8|9|0|-|=| |q|w|e|r|t|y|u|i identifier = alpha | alpha alphanumeric ; -overloadable_operator = "\+" | "-" | "\*" | "/" | "%" | "^" | "&" | "\|" | "~" | "\!" | "," | "=" | "\+\+" | "--" | "<<" | ">>" | "==" | "!=" | "&&" | "\|\|" | "\+=" | "-=" | "/=" | "%=" | "^=" | "&=" | "\|=" | "\*=" | "<<=" | ">>=" | "->" ; +overloadable_operator = "\+" | "-" | "\*" | "/" | "%" | "^" | "&" | "\|" | "~" | "!" | "," | "=" | "\+\+" | "--" | "<<" | ">>" | "==" | "!=" | "&&" | "\|\|" | "\+=" | "-=" | "/=" | "%=" | "^=" | "&=" | "\|=" | "\*=" | "<<=" | ">>=" | "->" ; func_identifier = identifier | identifier overloadable_operator ; function = template_dec WS type WS func_identifier WS "\(" WS opt_typed_parameter_list WS "\)" WS code_block | type WS func_identifier WS "\(" WS opt_typed_parameter_list WS "\)" WS code_block ; @@ -53,7 +53,7 @@ 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 ; -if_statement = "if" WS "\(" WS boolean_expression WS "\)" WS statement ; +if_statement = "if" WS "\(" WS boolean_expression WS "\)" WS statement | "if" WS "\(" WS boolean_expression WS "\)" WS statement WS "else" WS statement ; while_loop = "while" WS boolean_expression WS statement ; @@ -69,7 +69,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 = "!" WS bool_exp | expression WS comparator WS expression | bool | expression ; +bool_exp = expression WS comparator WS expression | bool | expression ; comparator = "==" | "<=" | ">=" | "!=" | "<" | ">" ; expression = expression WS "<<" WS term | expression WS ">>" WS shiftand | shiftand ; diff --git a/stdlib/vector.krak b/stdlib/vector.krak index a8d8537..7ab5cc2 100644 --- a/stdlib/vector.krak +++ b/stdlib/vector.krak @@ -38,7 +38,7 @@ typedef template vector { } void set(int index, T dataIn) { - if (index < 0 || index => size) + if (index < 0 || index >= size) return; data[index] = dataIn; } From 46b9fc8b7f495e954e3a1225db61ab151cc62a49 Mon Sep 17 00:00:00 2001 From: Nathan Braswell Date: Sun, 6 Jul 2014 23:42:25 -0700 Subject: [PATCH 29/37] Added ability to add commits the Kraken grammer file. Started work on class traits and else statements. --- krakenGrammer.kgm | 8 ++++++-- src/ASTTransformation.cpp | 8 +++++--- src/Importer.cpp | 2 +- src/Parser.cpp | 18 +++++++++++++++--- stdlib/mem.krak | 8 +++++++- stdlib/vector.krak | 12 +++++++++--- tests/vectorTest.expected_results | 1 + tests/vectorTest.krak | 14 +++++++++++++- 8 files changed, 57 insertions(+), 14 deletions(-) diff --git a/krakenGrammer.kgm b/krakenGrammer.kgm index 02598ac..7b81fe9 100644 --- a/krakenGrammer.kgm +++ b/krakenGrammer.kgm @@ -7,8 +7,12 @@ type = type WS "\*" | "void" | "int" | "float" | "double" | "char" | identifier 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 ; +#What does that even mean? +#some +# +# +template_dec = "template" WS "<" WS template_param_list WS ">" ; +template_param_list = template_param_list WS "," WS identifier | identifier ; import = "import" WS identifier WS ";" ; diff --git a/src/ASTTransformation.cpp b/src/ASTTransformation.cpp index d50d8dc..63ecabb 100644 --- a/src/ASTTransformation.cpp +++ b/src/ASTTransformation.cpp @@ -503,8 +503,10 @@ NodeTree* ASTTransformation::transform(NodeTree* from, NodeTree } // //Set the value of this function call - if (newNode->getDataRef()->valueType == NULL && rhs->getDataRef()->valueType) - newNode->getDataRef()->valueType = rhs->getDataRef()->valueType; + if (newNode->getDataRef()->valueType == NULL && rhs->getDataRef()->valueType) { + std::cout << "The value type from doFunction was null! (for " << functionCallName << ")" << std::endl; + newNode->getDataRef()->valueType = rhs->getDataRef()->valueType; + } //else // newNode->getDataRef()->valueType = NULL; std::cout << "function call to " << functionCallName << " - " << newNode->getName() << " is now " << newNode->getDataRef()->valueType << std::endl; @@ -754,7 +756,7 @@ NodeTree* ASTTransformation::doFunction(NodeTree* scope, std:: else newType->increaseIndirection(); - newNode->getDataRef()->valueType = newType, std::cout << "Operator " + lookup << " is altering indirection "<< std::endl; + newNode->getDataRef()->valueType = newType, std::cout << "Operator " + lookup << " is altering indirection from " << oldTypes[0].toString() << " to " << newType->toString() << std::endl; } else { newNode->getDataRef()->valueType = function->getDataRef()->valueType, std::cout << "Some other ||" << lookup << "||" << std::endl; } diff --git a/src/Importer.cpp b/src/Importer.cpp index 1706e5b..29eb143 100644 --- a/src/Importer.cpp +++ b/src/Importer.cpp @@ -36,7 +36,7 @@ Importer::Importer(Parser* parserIn, std::vector includePaths) { 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)); + collapseSymbols.push_back(Symbol("template_param_list", false)); } Importer::~Importer() { diff --git a/src/Parser.cpp b/src/Parser.cpp index 4a87119..e32a9cf 100644 --- a/src/Parser.cpp +++ b/src/Parser.cpp @@ -32,10 +32,22 @@ Symbol Parser::getOrAddSymbol(std::string symbolString, bool isTerminal) { void Parser::loadGrammer(std::string grammerInputString) { reader.setString(grammerInputString); - std::string currToken = reader.word(); + std::string currToken = reader.word(false); //Don't truncate so we can find the newline correctly (needed for comments) while(currToken != "") { - //Load the left of the rule + //First, if this starts with a '#', skip this + if (currToken.front() == '#') { + //If this line is more than one token long, eat it + std::cout << "Ate: " << currToken << std::endl; + if (currToken.back() != '\n') + std::cout << "Eating " << reader.line() << " b/c grammer comment" << std::endl; + currToken = reader.word(false); + continue; + } + if (currToken.back() == '\n' || currToken.back() == ' ' || currToken.back() == '\t') + currToken.erase(currToken.size()-1); + + //Load the left of the rule ParseRule* currentRule = new ParseRule(); Symbol leftSide = getOrAddSymbol(currToken, false); //Left handle is never a terminal currentRule->setLeftHandle(leftSide); @@ -76,7 +88,7 @@ void Parser::loadGrammer(std::string grammerInputString) { loadedGrammer.push_back(currentRule); //Get next token - currToken = reader.word(); + currToken = reader.word(false); } //std::cout << "Parsed!\n"; diff --git a/stdlib/mem.krak b/stdlib/mem.krak index e52a85d..c4b30c5 100644 --- a/stdlib/mem.krak +++ b/stdlib/mem.krak @@ -57,5 +57,11 @@ template void delete(T* toDelete, int itemDestructCount) { } template void delete(T* toDelete) { - free(toDelete); + delete(toDelete, true); +} + +template void delete(T* toDelete, bool destruct) { + if (destruct) + toDelete->destruct(); + free(toDelete); } diff --git a/stdlib/vector.krak b/stdlib/vector.krak index 7ab5cc2..ca02a6a 100644 --- a/stdlib/vector.krak +++ b/stdlib/vector.krak @@ -5,7 +5,11 @@ typedef template vector { T *data; int size; int available; - vector *construct() { + bool destroyItems; + + vector *construct(bool destroyItemsIn) { + destroyItems = destroyItemsIn; + return construct(); size = 0; available = 8; data = new(8); @@ -13,8 +17,10 @@ typedef template vector { } void destruct() { - //Destruction of contained data should depend on if the stored things are objects or primitives. - delete(data, size); + if (destroyItems) + delete(data, size); + else + delete(data); } bool resize(int newSize) { diff --git a/tests/vectorTest.expected_results b/tests/vectorTest.expected_results index d472488..2239baa 100644 --- a/tests/vectorTest.expected_results +++ b/tests/vectorTest.expected_results @@ -1,2 +1,3 @@ 1337 +Destroyed! diff --git a/tests/vectorTest.krak b/tests/vectorTest.krak index b55fe50..83d9898 100644 --- a/tests/vectorTest.krak +++ b/tests/vectorTest.krak @@ -1,8 +1,14 @@ import io; import vector; +typedef Destructable { + void destruct() { + println("Destroyed!"); + } +}; + int main() { - vector intVec.construct(); + vector intVec.construct(false); intVec.addBack(1); intVec.addBack(3); intVec.addBack(3); @@ -11,5 +17,11 @@ int main() { print(intVec.at(i)); println(); + + vector* desVec = new>()->construct(true); + Destructable testDestruct; + desVec->addBack(testDestruct); + delete>(desVec); + return 0; } From 64fcb6b0b767475feb29b35b76cd3fbbc5a257e6 Mon Sep 17 00:00:00 2001 From: Nathan Braswell Date: Fri, 18 Jul 2014 08:52:15 -0700 Subject: [PATCH 30/37] Traits for function templates working! Need to finish for objects and specilizations, and I think also else statements. --- include/ASTTransformation.h | 11 +- include/Type.h | 21 +- krakenGrammer.kgm | 29 +- src/ASTTransformation.cpp | 340 +++++++++++++++--------- src/CGenerator.cpp | 13 +- src/Importer.cpp | 1 + src/RNGLRParser.cpp | 4 +- src/Type.cpp | 50 ++-- stdlib/io.krak | 9 + tests/commentFirstTest.expected_results | 1 + tests/commentFirstTest.krak | 7 + tests/functionMultipleTemplateTest.krak | 2 +- tests/traitsTest.expected_results | 5 + tests/traitsTest.krak | 77 ++++++ 14 files changed, 396 insertions(+), 174 deletions(-) create mode 100644 tests/commentFirstTest.expected_results create mode 100644 tests/commentFirstTest.krak create mode 100644 tests/traitsTest.expected_results create mode 100644 tests/traitsTest.krak diff --git a/include/ASTTransformation.h b/include/ASTTransformation.h index 955ccca..18f4e43 100644 --- a/include/ASTTransformation.h +++ b/include/ASTTransformation.h @@ -4,6 +4,9 @@ #include #include +#include +#include + #include "Type.h" #include "ASTData.h" #include "NodeTransformation.h" @@ -18,6 +21,7 @@ class ASTTransformation: public NodeTransformation { //First pass defines all type_defs (objects and ailises) NodeTree* firstPass(std::string fileName, NodeTree* parseTree); + std::set parseTraits(NodeTree* traitsNode); //Second pass defines data inside objects, outside declaration statements, and function prototpyes (since we have type_defs now) void secondPass(NodeTree* ast, NodeTree* parseTree); @@ -39,10 +43,15 @@ class ASTTransformation: public NodeTransformation { 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* scopeLookup(NodeTree* scope, std::string lookup, std::vector types = std::vector()); + + 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); Type* typeFromTypeNode(NodeTree* typeNode, NodeTree* scope, std::map templateTypeReplacements, bool instantiateTemplates); NodeTree* findOrInstantiateFunctionTemplate(std::vector*> children, NodeTree* scope, std::vector types, std::map templateTypeReplacements); + std::map makeTemplateFunctionTypeMap(NodeTree* templateNode, std::vector types); + std::vector>> makeTemplateFunctionNameTraitPairs(NodeTree* templateNode); private: Importer * importer; std::map*>> languageLevelReservedWords; diff --git a/include/Type.h b/include/Type.h index 5b31c6c..a56286e 100644 --- a/include/Type.h +++ b/include/Type.h @@ -5,12 +5,9 @@ #define NULL ((void*)0) #endif -#ifndef SEGFAULT -#define SEGFAULT (*((char*)0)), std::cout << "\t\t\t\tNEGATIVE*************************************************************************" << std::endl; -#endif - #include #include +#include //Circular dependency class ASTData; @@ -23,12 +20,12 @@ enum ValueType {none, template_type, template_type_type, void_type, boolean, int class Type { public: Type(); - Type(ValueType typeIn, int indirectionIn); - Type(ValueType typeIn); - Type(NodeTree* typeDefinitionIn); - Type(NodeTree* typeDefinitionIn, int indirectionIn); - Type(ValueType typeIn, NodeTree* typeDefinitionIn, int indirectionIn); - Type(ValueType typeIn, NodeTree* templateDefinitionIn); + Type(ValueType typeIn, int indirectionIn = 0); + Type(ValueType typeIn, std::set traitsIn); //Mostly for template type type's + Type(NodeTree* typeDefinitionIn, int indirectionIn = 0); + Type(NodeTree* typeDefinitionIn, std::set traitsIn); + Type(ValueType typeIn, NodeTree* typeDefinitionIn, int indirectionIn, std::set traitsIn); + Type(ValueType typeIn, NodeTree* templateDefinitionIn, std::set traitsIn = std::set()); ~Type(); bool const operator==(const Type &other)const; bool const operator!=(const Type &other)const; @@ -39,13 +36,13 @@ class Type { void increaseIndirection(); void decreaseIndirection(); void modifyIndirection(int mod); - void check(); ValueType baseType; NodeTree* typeDefinition; NodeTree* templateDefinition; std::map templateTypeReplacement; - private: + std::set traits; + private: int indirection; }; diff --git a/krakenGrammer.kgm b/krakenGrammer.kgm index 7b81fe9..e7cb9de 100644 --- a/krakenGrammer.kgm +++ b/krakenGrammer.kgm @@ -12,7 +12,8 @@ type_list = type_list WS "," WS type | type ; # # template_dec = "template" WS "<" WS template_param_list WS ">" ; -template_param_list = template_param_list WS "," WS identifier | identifier ; +template_param_list = template_param_list WS "," WS template_param | template_param ; +template_param = identifier WS traits | identifier ; import = "import" WS identifier WS ";" ; @@ -40,7 +41,9 @@ triple_quoted_string = "\"\"\"((\"\"(`|1|2|3|4|5|6|7|8|9|0|-|=| |q|w|e|r|t|y|u|i identifier = alpha | alpha alphanumeric ; -overloadable_operator = "\+" | "-" | "\*" | "/" | "%" | "^" | "&" | "\|" | "~" | "!" | "," | "=" | "\+\+" | "--" | "<<" | ">>" | "==" | "!=" | "&&" | "\|\|" | "\+=" | "-=" | "/=" | "%=" | "^=" | "&=" | "\|=" | "\*=" | "<<=" | ">>=" | "->" ; +#Note that to prevent confilct with nested templates (T>) it is a nonterminal contructed as follows +right_shift = ">" ">" ; +overloadable_operator = "\+" | "-" | "\*" | "/" | "%" | "^" | "&" | "\|" | "~" | "!" | "," | "=" | "\+\+" | "--" | "<<" | right_shift | "==" | "!=" | "&&" | "\|\|" | "\+=" | "-=" | "/=" | "%=" | "^=" | "&=" | "\|=" | "\*=" | "<<=" | ">>=" | "->" ; func_identifier = identifier | identifier overloadable_operator ; function = template_dec WS type WS func_identifier WS "\(" WS opt_typed_parameter_list WS "\)" WS code_block | type WS func_identifier WS "\(" WS opt_typed_parameter_list WS "\)" WS code_block ; @@ -52,10 +55,17 @@ opt_parameter_list = parameter_list | ; 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 "}" ; -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 ; +type_def = "typedef" WS identifier WS type | "typedef" WS template_dec WS identifier WS "{" WS declaration_block WS "}" | "typedef" WS identifier WS "{" WS declaration_block WS "}" | "typedef" WS template_dec WS identifier WS traits WS "{" WS declaration_block WS "}" | "typedef" WS identifier WS traits WS "{" WS declaration_block WS "}" ; + +declaration_block = declaration_statement WS ";" WS declaration_block | function WS declaration_block | declaration_statement WS ";" | function | ; +traits = "\(" WS trait_list WS "\)" ; +trait_list = trait_list WS "," WS identifier | identifier ; + +#Older rule for stuff with visibility labels - this should be added sometime +#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 "}" ; +#class_innerds = visibility_block WS class_innerds | visibility_block ; +#visibility_block = "public:" WS declaration_block | "protected:" WS declaration_block | "private:" WS declaration_block ; + if_statement = "if" WS "\(" WS boolean_expression WS "\)" WS statement | "if" WS "\(" WS boolean_expression WS "\)" WS statement WS "else" WS statement ; @@ -76,12 +86,12 @@ and_boolean_expression = and_boolean_expression "&&" bool_exp | bool_exp ; bool_exp = expression WS comparator WS expression | bool | expression ; comparator = "==" | "<=" | ">=" | "!=" | "<" | ">" ; -expression = expression WS "<<" WS term | expression WS ">>" WS shiftand | shiftand ; +expression = expression WS "<<" WS term | expression WS right_shift WS shiftand | shiftand ; shiftand = shiftand WS "-" WS term | shiftand WS "\+" WS term | term ; term = term WS forward_slash WS factor | term WS "\*" WS factor | term WS "%" WS factor | factor ; factor = "\+\+" WS unarad | unarad WS "\+\+" | "--" WS unarad | unarad WS "--" | "\+" WS unarad | "-" WS unarad | "!" WS unarad | "~" WS unarad | "\(" WS type WS "\)" WS unarad | "\*" WS unarad | "&" WS unarad | unarad ; unarad = number | identifier | identifier WS template_inst | function_call | bool | string | character | "\(" WS boolean_expression WS "\)" | access_operation | unarad WS "[" WS expression WS "]" ; -number = integer | float | double ; +number = integer | floating_literal ; access_operation = unarad "." identifier | unarad "->" identifier ; assignment_statement = factor WS "=" WS boolean_expression | factor WS "\+=" WS boolean_expression | factor WS "-=" WS boolean_expression | factor WS "\*=" WS boolean_expression | factor WS "/=" WS boolean_expression ; @@ -91,8 +101,7 @@ alphanumeric = alphanumeric numeric | alphanumeric alpha | numeric | alpha ; hexadecimal = "0x(1|2|3|4|5|6|7|8|9|a|b|c|d|e|f)+" ; sign = "\+|-" WS | ; integer = sign numeric | sign hexadecimal | "null" ; -float = sign numeric "." numeric "f" ; -double = sign numeric "." numeric | sign numeric "." numeric "d" ; +floating_literal = sign numeric "." numeric | sign numeric "." numeric alpha ; bool = "true" | "false" | "True" | "False" ; character = "'(`|1|2|3|4|5|6|7|8|9|0|-|=| |q|w|e|r|t|y|u|i|o|p|[|]|\\|a|s|d|f|g|h|j|k|l|;|'| |z|x|c|v|b|n|m|,|.|/|~|!|@|#|$|%|^|&|\*|\(|\)|_|\+|Q|W|E|R|T|Y|U|I|O|P|{|}|\||A|S|D|F|G|H|J|K|L|:|\"|Z|X|C|V|B|N|M|<|>|\?| )'" ; diff --git a/src/ASTTransformation.cpp b/src/ASTTransformation.cpp index 63ecabb..33a456c 100644 --- a/src/ASTTransformation.cpp +++ b/src/ASTTransformation.cpp @@ -42,7 +42,7 @@ NodeTree* ASTTransformation::firstPass(std::string fileName, 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 + //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 whether they are classes or ailises, as well as including non-instantiated templates) for (NodeTree* i : children) { @@ -54,10 +54,19 @@ NodeTree* ASTTransformation::firstPass(std::string fileName, NodeTreegetChildren()[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. + auto typedefChildren = i->getChildren(); + if (typedefChildren[0]->getData().getName() == "template_dec") { + if (typedefChildren.size() > 2 && typedefChildren[2]->getData().getName() == "traits") + firstDec->getDataRef()->valueType = new Type(template_type, i, parseTraits(i->getChildren()[2])); + else + firstDec->getDataRef()->valueType = new Type(template_type, i); + } + else if (typedefChildren.size() > 1 && typedefChildren[1]->getData().getName() == "traits") + firstDec->getDataRef()->valueType = new Type(firstDec, parseTraits(i->getChildren()[1])); + else if (typedefChildren.size() == 1 || typedefChildren[1]->getData().getName() != "type") //We don't make the type for alises, because the second pass will assign it the type it points to + firstDec->getDataRef()->valueType = new Type(firstDec); translationUnit->addChild(firstDec); translationUnit->getDataRef()->scope[name].push_back(firstDec); @@ -84,6 +93,14 @@ NodeTree* ASTTransformation::firstPass(std::string fileName, NodeTree ASTTransformation::parseTraits(NodeTree* traitsNode) { + std::set traits; + //Every other one b/c comma separated + for (auto i : slice(traitsNode->getChildren(), 0, -1, 2)) + traits.insert(concatSymbolTree(i)); + return traits; +} + //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 @@ -97,10 +114,10 @@ void ASTTransformation::secondPass(NodeTree* ast, NodeTree* par 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 + NodeTree* typeDef = ast->getDataRef()->scope[name][0]; //No overloaded types (besides uninstantiated templates, which can have multiple versions based on types or specilizations) - //It's an alias - if (typedefChildren[1]->getData().getName() == "type") { + //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 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 @@ -109,7 +126,6 @@ void ASTTransformation::secondPass(NodeTree* ast, NodeTree* par continue; } //Do the inside of classes here - typeDef->getDataRef()->valueType = new Type(typeDef); secondPassDoClassInsides(typeDef, typedefChildren, std::map()); } else if (i->getDataRef()->getName() == "function") { //Do prototypes of functions @@ -160,11 +176,14 @@ NodeTree* ASTTransformation::secondPassFunction(NodeTree* from, 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 -/*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 - + 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 + for (auto i : slice(children[0]->getChildren(), 1, -1, 2)) {//skip commas + if (i->getChildren().size() == 1) + 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 + 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); std::cout << "Template function " << functionName << " has these parameters: "; for (auto i : transChildren) @@ -247,8 +266,8 @@ void ASTTransformation::fourthPass(NodeTree* ast, NodeTree* par 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") + //It's an alias. Note that typedefChildren.size() can equal one when it's a regular class with an empty body, i.e. {} + if (typedefChildren.size() > 1 && typedefChildren[1]->getData().getName() == "type") continue; //We're done with aliases too //Do the inside of classes here @@ -280,7 +299,7 @@ NodeTree* ASTTransformation::seachScopeForFunctionDef(NodeTree types.push_back(type); } std::cout << "About to seach scope about " << concatSymbolTree(children[1]) << std::endl; - NodeTree* result = scopeLookup(scope, functionName, types); + NodeTree* result = functionLookup(scope, functionName, types); std::cout << "Done searching scope about " << concatSymbolTree(children[1]) << std::endl; return result; } @@ -304,47 +323,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()) { - std::string toImport = concatSymbolTree(children[0]); - newNode = new NodeTree(name, ASTData(import, Symbol(toImport, true))); - //Do the imported file too - NodeTree* outsideTranslationUnit = importer->import(toImport + ".krak"); - scope->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) - scope->getDataRef()->scope[i->first].push_back(j); - return newNode; // Don't need children of import - } else */if (name == "identifier") { + if (name == "identifier") { //Make sure we get the entire name std::string lookupName = concatSymbolTree(from); std::cout << "Looking up: " << lookupName << std::endl; - newNode = scopeLookup(scope, lookupName, types); - if (newNode == NULL) { - std::cout << "scope lookup error! Could not find " << lookupName << " in identifier " << std::endl; - throw "LOOKUP ERROR: " + lookupName; - } + if (types.size()) { + newNode = functionLookup(scope, lookupName, types); + if (newNode == NULL) { + std::cout << "scope lookup error! Could not find " << lookupName << " in identifier " << std::endl; + throw "LOOKUP ERROR: " + lookupName; + } + } else { + auto possibleMatches = scopeLookup(scope, lookupName); + if (!possibleMatches.size()) { + std::cout << "scope lookup error! Could not find " << lookupName << " in identifier " << std::endl; + throw "LOOKUP ERROR: " + lookupName; + } + newNode = possibleMatches[0]; + } } else if (name == "type_def") { //If it is an alisis of a type std::string typeAlias; @@ -470,18 +467,6 @@ NodeTree* ASTTransformation::transform(NodeTree* from, NodeTree } 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) { - /* else if (children.size() >= 4) { //Array brackets [] - funcName = "[]"; - std::vector*> transformedChildren; - transformedChildren.push_back(transform(children[0], scope, types, templateTypeReplacements, instantiateTemplates)); - transformedChildren.push_back(transform(children[2], scope, types, templateTypeReplacements, instantiateTemplates)); - NodeTree* function = doFunction(scope, funcName, transformedChildren, templateTypeReplacements); - if (function == NULL) { - std::cout << "scope lookup error! Could not find " << funcName << " in factor " << std::endl; - throw "LOOKUP ERROR: " + funcName; - } - return function; - }*/ NodeTree* lhs = transform(children[0], scope, std::vector(), templateTypeReplacements, instantiateTemplates); //LHS does not inherit types NodeTree* rhs; if (name == "access_operation") { @@ -646,10 +631,17 @@ NodeTree* ASTTransformation::transform(NodeTree* from, NodeTree return transform(children[0], scope, types, templateTypeReplacements, instantiateTemplates); } else if (name == "integer") { newNode = new NodeTree(name, ASTData(value, Symbol(concatSymbolTree(from), true), new Type(integer))); - } else if (name == "float") { - newNode = new NodeTree(name, ASTData(value, Symbol(concatSymbolTree(from), true), new Type(floating))); - } else if (name == "double") { - newNode = new NodeTree(name, ASTData(value, Symbol(concatSymbolTree(from), true), new Type(double_percision))); + } else if (name == "floating_literal") { + std::string literal = concatSymbolTree(from); + ValueType type = double_percision; + if (literal.back() == 'f') { + literal = literal.substr(0, literal.length()-1); + type = floating; + } else if (literal.back() == 'd') { + literal = literal.substr(0, literal.length()-1); + type = double_percision; + } + newNode = new NodeTree(name, ASTData(value, Symbol(literal, true), new Type(type))); } else if (name == "char") { //Is this correct? This might be a useless old thing newNode = new NodeTree(name, ASTData(value, Symbol(concatSymbolTree(children[0]), true), new Type(character, 1))); //Indirection of 1 for array } else if (name == "string" || name == "triple_quoted_string") { @@ -716,7 +708,7 @@ NodeTree* ASTTransformation::doFunction(NodeTree* scope, std:: std::cout << std::endl; NodeTree* operatorMethod = NULL; if (nodes[0]->getDataRef()->valueType && nodes[0]->getDataRef()->valueType->typeDefinition) - operatorMethod = scopeLookup(nodes[0]->getDataRef()->valueType->typeDefinition, lookupOp, mapNodesToTypes(slice(nodes,1,-1))); + operatorMethod = functionLookup(nodes[0]->getDataRef()->valueType->typeDefinition, lookupOp, mapNodesToTypes(slice(nodes,1,-1))); if (operatorMethod) { //Ok, so we construct std::cout << "Early method level operator was found" << std::endl; @@ -738,7 +730,7 @@ NodeTree* ASTTransformation::doFunction(NodeTree* scope, std:: } newNode = new NodeTree(lookup, ASTData(function_call, Symbol(lookup, true))); - NodeTree* function = scopeLookup(scope, lookup, mapNodesToTypes(nodes)); + NodeTree* function = functionLookup(scope, lookup, mapNodesToTypes(nodes)); newNode->addChild(function); newNode->addChildren(nodes); @@ -763,9 +755,8 @@ NodeTree* ASTTransformation::doFunction(NodeTree* scope, std:: return newNode; } -//Search recursively through levels of scope (each ASTData, that is, every node, has its own scope) -//We pass in types so that if we're searching for a function we can find the right overloaded one -NodeTree* ASTTransformation::scopeLookup(NodeTree* scope, std::string lookup, std::vector types) { +//Lookup a function that takes in parameters matching the types passed in +NodeTree* ASTTransformation::functionLookup(NodeTree* scope, std::string lookup, std::vector types) { //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()) { @@ -776,22 +767,17 @@ NodeTree* ASTTransformation::scopeLookup(NodeTree* scope, std: LLElementIterator = languageLevelOperators.find(lookup); if (LLElementIterator != languageLevelOperators.end()) lookup = "operator" + lookup; - //Search the map - auto scopeMap = scope->getDataRef()->scope; - auto elementIterator = scopeMap.find(lookup); - for (auto i : scopeMap) - std::cout << i.first << " "; - std::cout << std::endl; - // - if (elementIterator != scopeMap.end()) { - for (auto i = elementIterator->second.begin(); i != elementIterator->second.end(); i++) { - //Types and functions cannot have the same name, and types very apparently do not have parameter types, so check and short-circuit - if ((*i)->getDataRef()->type == type_def) - return *i; - std::cout << lookup << " has " << elementIterator->second.size() << " possible solutions" << std::endl; + //Look up the name + std::vector*> possibleMatches = scopeLookup(scope, lookup); + std::cout << "Function lookup of " << lookup << " has " << possibleMatches.size() << " possible matches." << std::endl; + if (possibleMatches.size()) { + for (auto i : possibleMatches) { + //We're not looking for types + if (i->getDataRef()->type == type_def) + continue; - std::vector*> children = (*i)->getChildren(); + 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 //and this function is recursive or if this is a non-instantiated template function @@ -818,20 +804,11 @@ NodeTree* ASTTransformation::scopeLookup(NodeTree* scope, std: } } if (typesMatch) - return *i; + return i; } } - //if it doesn't exist, try the enclosing scope if it exists. - auto enclosingIterator = scopeMap.find("~enclosing_scope"); - if (enclosingIterator != scopeMap.end()) { - // std::cout << "upper scope exists, searching it for " << lookup << std::endl; - NodeTree* upperResult = scopeLookup(enclosingIterator->second[0], lookup, types); - if (upperResult) - return upperResult; - } - //std::cout << "upper scope does not exist" << std::endl; - std::cout << "could not find " << lookup << " in standard scope, checking for operator" << std::endl; + std::cout << "could not find " << lookup << " in standard scopes, checking for operator" << std::endl; //Note that we don't check for types. At some point we should, as we don't know how to add objects/structs without overloaded operators, etc //Also, we've already searched for the element because this is also how we keep track of operator overloading if (LLElementIterator != languageLevelOperators.end()) { @@ -839,7 +816,125 @@ NodeTree* ASTTransformation::scopeLookup(NodeTree* scope, std: return LLElementIterator->second[0]; } std::cout << "Did not find, returning NULL" << std::endl; - return NULL; + return NULL; +} + + +//Lookup function for template functions. It has some extra concerns compared to function lookup, namely traits +NodeTree* ASTTransformation::templateFunctionLookup(NodeTree* scope, std::string lookup, std::vector templateInstantiationTypes, std::vector types) { + std::vector*> mostFittingTemplates; + int bestNumTraitsSatisfied = -1; + auto possibleMatches = scopeLookup(scope, lookup); + std::cout << "Template Function instantiation has " << possibleMatches.size() << " possible matches." << std::endl; + for (auto i : possibleMatches) { + NodeTree* templateSyntaxTree = i->getDataRef()->valueType->templateDefinition; + + //When called without a second parameter, makeTemplateFunctionTypeMap returns a map with blank Types filled in that contain the correct Traits + auto nameTraitsPairs = makeTemplateFunctionNameTraitPairs(templateSyntaxTree->getChildren()[0]); + + //Check if sizes match between the placeholder and actual template types + if (nameTraitsPairs.size() != templateInstantiationTypes.size()) + continue; + + std::map typeMap; + bool traitsEqual = true; + int typeIndex = 0; + int currentTraitsSatisfied = 0; + for (auto j : nameTraitsPairs) { + if (j.second != templateInstantiationTypes[typeIndex]->traits) { + traitsEqual = false; + std::cout << "Traits unequal 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; + } + //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(); + typeIndex++; + } + if (!traitsEqual) + continue; + + std::vector*> functionParameters = slice(templateSyntaxTree->getChildren(), 3, -2, 2); //skip template, return type, name, intervening commas, and the code block + std::cout << functionParameters.size() << " " << types.size() << std::endl; + if (functionParameters.size() != types.size()) + continue; + + bool parameterTypesMatch = true; + for (int j = 0; j < functionParameters.size(); j++) { + auto paramType = typeFromTypeNode(functionParameters[j]->getChildren()[0], scope, typeMap, false); + std::cout << "Template param type: " << paramType->toString() << " : Needed Type: " << types[j].toString() << std::endl; + if (*paramType != types[j]) { + parameterTypesMatch = false; + std::cout << "Not equal: " << paramType->toString() << " : Needed Type: " << types[j].toString() << std::endl; + break; + } + } + if (!parameterTypesMatch) + continue; + //See if this is a better match than the current best + if (currentTraitsSatisfied > bestNumTraitsSatisfied) { + mostFittingTemplates.clear(); + std::cout << "Function satisfying " << currentTraitsSatisfied << " beats previous " << bestNumTraitsSatisfied << std::endl; + bestNumTraitsSatisfied = currentTraitsSatisfied; + } else if (currentTraitsSatisfied < bestNumTraitsSatisfied) + continue; + mostFittingTemplates.push_back(i); + std::cout << "Current function fits, satisfying " << currentTraitsSatisfied << " traits" << std::endl; + } + if (!mostFittingTemplates.size()) { + std::cout << "No template functions fit for " << lookup << "!" << std::endl; + throw "No matching template functions"; + } else if (mostFittingTemplates.size() > 1) { + std::cout << "Multiple template functions fit with equal number of traits satisfied for " << lookup << "!" << std::endl; + throw "Multiple matching template functions"; + } + return mostFittingTemplates[0]; +} + +//Extract pairs of type names and traits +std::vector>> ASTTransformation::makeTemplateFunctionNameTraitPairs(NodeTree* templateNode) { + std::vector*> templateParams = slice(templateNode->getChildren(), 1, -2, 2); //Skip <, >, and interveaning commas + std::vector>> typePairs; + for (auto i : templateParams) { + if (i->getChildren().size() > 1) + typePairs.push_back(std::make_pair(concatSymbolTree(i->getChildren()[0]), parseTraits(i->getChildren()[1]))); + else + typePairs.push_back(std::make_pair(concatSymbolTree(i->getChildren()[0]), std::set())); + } + return typePairs; +} + +std::map ASTTransformation::makeTemplateFunctionTypeMap(NodeTree* templateNode, std::vector types) { + auto typePairs = makeTemplateFunctionNameTraitPairs(templateNode); + std::map typeMap; + int typeIndex = 0; + std::cout << typePairs.size() << " " << types.size() << std::endl; + for (auto i : typePairs) { + typeMap[i.first] = types[typeIndex]; + std::cout << "Mapping " << i.first << " to " << types[typeIndex]->toString() << std::endl; + typeIndex++; + } + return typeMap; +} + +std::vector*> ASTTransformation::scopeLookup(NodeTree* scope, std::string lookup) { + 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()); + + // Add results from our enclosing scope, if it exists + auto enclosingIterator = scopeMap.find("~enclosing_scope"); + if (enclosingIterator != scopeMap.end()) { + std::vector*> upperResult = scopeLookup(enclosingIterator->second[0], lookup); + matches.insert(matches.end(), upperResult.begin(), upperResult.end()); + } + return matches; } //Create a type from a syntax tree. This can get complicated with templates @@ -849,6 +944,7 @@ Type* ASTTransformation::typeFromTypeNode(NodeTree* typeNode, NodeTree* typeDefinition = NULL; + std::set traits; while (typeIn[typeIn.size() - indirection - 1] == '*') indirection++; std::string edited = strSlice(typeIn, 0, -(indirection + 1)); if (edited == "void") @@ -865,8 +961,12 @@ Type* ASTTransformation::typeFromTypeNode(NodeTree* typeNode, NodeTreegetDataRef()->valueType->traits; + } //So either this is an uninstatiated template class type, or this is literally a template type T, and we should get it from our //templateTypeReplacements map. We try this first if (templateTypeReplacements.find(edited) != templateTypeReplacements.end()) { @@ -874,18 +974,19 @@ Type* ASTTransformation::typeFromTypeNode(NodeTree* typeNode, NodeTreeclone(); templateTypeReplacement->modifyIndirection(indirection); return templateTypeReplacement; - } else { - std::cout << edited << " was not found in templateTypeReplacements" << std::endl; - std::cout << "templateTypeReplacements consists of : "; - for (auto i : templateTypeReplacements) - std::cout << i.first << " "; - std::cout << std::endl; } - //If not, we better instantiate it and then add it to the highest (not current) scope - if (typeDefinition == NULL && typeNode->getChildren().size() > 1 && typeNode->getChildren()[1]->getData().getName() == "template_inst") { + std::cout << edited << " was not found in templateTypeReplacements" << std::endl; + std::cout << "templateTypeReplacements consists of : "; + for (auto i : templateTypeReplacements) + std::cout << i.first << " "; + std::cout << 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; //Look up this template's plain definition. It's type has the syntax tree that we need to parse - NodeTree* templateDefinition = scopeLookup(scope,concatSymbolTree(typeNode->getChildren()[0])); + possibleMatches = scopeLookup(scope,concatSymbolTree(typeNode->getChildren()[0])); + NodeTree* templateDefinition = possibleMatches[0]; if (templateDefinition == NULL) std::cout << "Template definition is null!" << std::endl; else @@ -931,14 +1032,14 @@ Type* ASTTransformation::typeFromTypeNode(NodeTree* typeNode, NodeTreeaddChildren(transformChildren(templateSyntaxTree->getChildren(), skipChildren, typeDefinition, std::vector(), newTemplateTypeReplacement, instantiateTemplates)); } - } else if (typeDefinition == NULL) { + } else if (possibleMatches.size() == 0) { std::cout << "Could not find type " << edited << ", returning NULL" << std::endl; return NULL; } else { - std::cout << "Type: " << edited << " already instantiated with " << typeDefinition << ", will be " << Type(baseType, typeDefinition, indirection).toString() << std::endl; + std::cout << "Type: " << edited << " already instantiated with " << typeDefinition << ", will be " << Type(baseType, typeDefinition, indirection, traits).toString() << std::endl; } } - Type* toReturn = new Type(baseType, typeDefinition, indirection); + Type* toReturn = new Type(baseType, typeDefinition, indirection, traits); std::cout << "Returning type " << toReturn->toString() << std::endl; return toReturn; } @@ -966,7 +1067,7 @@ NodeTree* ASTTransformation::findOrInstantiateFunctionTemplate(std::vec std::cout << " " << i.toString(); std::cout << std::endl; - NodeTree* instantiatedFunction = scopeLookup(scope, fullyInstantiatedName,types); + NodeTree* instantiatedFunction = functionLookup(scope, fullyInstantiatedName, types); //If it already exists, return it if (instantiatedFunction) { std::cout << fullyInstantiatedName << " already exists! Returning" << std::endl; @@ -976,19 +1077,16 @@ NodeTree* ASTTransformation::findOrInstantiateFunctionTemplate(std::vec } //Otherwise, we're going to instantiate it - //Find the template definition - NodeTree* templateDefinition = scopeLookup(scope,functionName,types); + //Find the template definitions + NodeTree* templateDefinition = templateFunctionLookup(scope, functionName, templateActualTypes, types); if (templateDefinition == NULL) { std::cout << functionName << " search turned up null, returing null" << std::endl; return NULL; } NodeTree* templateSyntaxTree = templateDefinition->getDataRef()->valueType->templateDefinition; - std::map newTemplateTypeReplacement; - 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]; + // Makes a map between the names of the template placeholder parameters and the provided types + std::map newTemplateTypeReplacement = makeTemplateFunctionTypeMap(templateSyntaxTree->getChildren()[0], templateActualTypes); std::vector*> templateChildren = templateSyntaxTree->getChildren(); for (int i = 0; i < templateChildren.size(); i++) diff --git a/src/CGenerator.cpp b/src/CGenerator.cpp index 29cb6ff..20e875e 100644 --- a/src/CGenerator.cpp +++ b/src/CGenerator.cpp @@ -61,12 +61,12 @@ std::string CGenerator::generate(NodeTree* from, NodeTree* enc typedefPoset.addRelationship(children[i], decType->typeDefinition); //Add a dependency } } - //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()) + //In case there are pointer dependencies. We don't do this if this is an alias type + if (children[i]->getDataRef()->valueType->typeDefinition == children[i]) output += "struct " + CifyName(children[i]->getDataRef()->symbol.getName()) + ";\n"; else { Type *aliasType = children[i]->getDataRef()->valueType; - if (aliasType->typeDefinition && aliasType->typeDefinition != children[i] && !aliasType->templateDefinition) //Isn't uninstantiated template or 0 parameter class, so must be alias. if typeDefinition isn't null, then it's an alias of a custom, not a primitive, type. + if (aliasType->typeDefinition && !aliasType->templateDefinition) //Isn't uninstantiated template or 0 parameter class, so must be alias. if typeDefinition isn't null, then it's an alias of a custom, not a primitive, type. typedefPoset.addRelationship(children[i], children[i]->getDataRef()->valueType->typeDefinition); //An alias typedef depends on the type it aliases being declared before it } } @@ -147,7 +147,7 @@ std::string CGenerator::generate(NodeTree* from, NodeTree* enc case type_def: if (data.valueType->baseType == template_type) { return "/* non instantiated template " + data.symbol.getName() + " */"; - } else if (children.size() == 0) { + } else if (data.valueType->typeDefinition != from) { return "typedef " + ValueTypeToCType(data.valueType) + " " + data.symbol.getName() + ";"; } else { std::string objectString = "typedef struct __struct_dummy_" + CifyName(data.symbol.getName()) + "__ {\n"; @@ -471,6 +471,11 @@ std::string CGenerator::CifyName(std::string name) { "<", "lessthan", ">", "greaterthan", ">>=", "doubleleftequals", + "(", "openparen", + ")", "closeparen", + "[", "openbracket", + "]", "closebracket", + " ", "space", "->", "arrow" }; int length = sizeof(operatorsToReplace)/sizeof(std::string); //std::cout << "Length is " << length << std::endl; diff --git a/src/Importer.cpp b/src/Importer.cpp index 29eb143..b5758f6 100644 --- a/src/Importer.cpp +++ b/src/Importer.cpp @@ -37,6 +37,7 @@ Importer::Importer(Parser* parserIn, std::vector includePaths) { collapseSymbols.push_back(Symbol("declaration_block", false)); collapseSymbols.push_back(Symbol("type_list", false)); collapseSymbols.push_back(Symbol("template_param_list", false)); + collapseSymbols.push_back(Symbol("trait_list", false)); } Importer::~Importer() { diff --git a/src/RNGLRParser.cpp b/src/RNGLRParser.cpp index 400b4c4..c95a526 100644 --- a/src/RNGLRParser.cpp +++ b/src/RNGLRParser.cpp @@ -110,13 +110,13 @@ NodeTree* RNGLRParser::parseInput(std::string inputString) { std::cout << input[j].toString() << " "; std::cout << std::endl; range = 1; - std::cout << "\n\n\nThe states in the GSS at last frontiers:" << std::endl; +/* std::cout << "\n\n\nThe states in the GSS at last frontiers:" << std::endl; for (int j = (i-range >= 0 ? i-range : 0); j < i; j++) { std::cout << "Frontier:" << j << " (would get): " << input[j].toString() << std::endl; printReconstructedFrontier(j); } std::cout << "\n\n\n\n" << std::endl; - break; + */ break; } //Clear the vector of SPPF nodes created every step diff --git a/src/Type.cpp b/src/Type.cpp index 1114777..f454127 100644 --- a/src/Type.cpp +++ b/src/Type.cpp @@ -7,47 +7,50 @@ Type::Type() { templateDefinition = NULL; } -Type::Type(ValueType typeIn) { - indirection = 0; - baseType = typeIn; - typeDefinition = NULL; - templateDefinition = NULL; -} - Type::Type(ValueType typeIn, int indirectionIn) { indirection = indirectionIn; baseType = typeIn; typeDefinition = NULL; templateDefinition = NULL; - if (indirection < 0) SEGFAULT } -Type::Type(NodeTree* typeDefinitionIn) { +Type::Type(ValueType typeIn, std::set traitsIn) { indirection = 0; - baseType = none; - typeDefinition = typeDefinitionIn; + baseType = typeIn; + traits = traitsIn; + typeDefinition = NULL; templateDefinition = NULL; } + Type::Type(NodeTree* typeDefinitionIn, int indirectionIn) { indirection = indirectionIn; baseType = none; typeDefinition = typeDefinitionIn; templateDefinition = NULL; - if (indirection < 0) SEGFAULT } -Type::Type(ValueType typeIn, NodeTree* typeDefinitionIn, int indirectionIn) { +Type::Type(NodeTree* typeDefinitionIn, std::set traitsIn) { + indirection = 0; + baseType = none; + typeDefinition = typeDefinitionIn; + traits = traitsIn; + templateDefinition = NULL; +} + +Type::Type(ValueType typeIn, NodeTree* typeDefinitionIn, int indirectionIn, std::set traitsIn) { baseType = typeIn; indirection = indirectionIn; typeDefinition = typeDefinitionIn; - templateDefinition = NULL; - if (indirection < 0) SEGFAULT + traits = traitsIn; + templateDefinition = NULL; } -Type::Type(ValueType typeIn, NodeTree* templateDefinitionIn) { + +Type::Type(ValueType typeIn, NodeTree* templateDefinitionIn, std::set traitsIn) { indirection = 0; baseType = typeIn; typeDefinition = NULL; templateDefinition = templateDefinitionIn; + traits = traitsIn; } @@ -55,7 +58,7 @@ Type::~Type() { } const bool Type::operator==(const Type &other) const { - return( baseType == other.baseType && indirection == other.indirection && typeDefinition == other.typeDefinition && templateDefinition == other.templateDefinition); + return( baseType == other.baseType && indirection == other.indirection && typeDefinition == other.typeDefinition && templateDefinition == other.templateDefinition && other.traits == traits); } const bool Type::operator!=(const Type &other) const { @@ -103,16 +106,18 @@ std::string Type::toString() { } for (int i = 0; i < indirection; i++) typeString += "*"; + if (traits.size()) { + typeString += "[ "; + for (auto i : traits) + typeString += i + " "; + typeString += "]"; + } //std::cout << "Extra components of " << typeString << " are " << indirection << " " << typeDefinition << " " << templateDefinition << std::endl; return typeString; } Type* Type::clone() { - return new Type(baseType, typeDefinition, indirection); -} - -void Type::check() { - if (indirection < 0) SEGFAULT + return new Type(baseType, typeDefinition, indirection, traits); } int Type::getIndirection() { @@ -121,7 +126,6 @@ int Type::getIndirection() { void Type::setIndirection(int indirectionIn) { indirection = indirectionIn; - check(); } void Type::increaseIndirection() { diff --git a/stdlib/io.krak b/stdlib/io.krak index 9cf6dab..60b9118 100644 --- a/stdlib/io.krak +++ b/stdlib/io.krak @@ -43,6 +43,15 @@ void print(float toPrint) { return; } +void print(double toPrint) { + __if_comp__ __C__ { + __simple_passthrough__ """ + printf("%f", toPrint); + """ + } + return; +} + void println(float toPrint) { print(toPrint); println(); diff --git a/tests/commentFirstTest.expected_results b/tests/commentFirstTest.expected_results new file mode 100644 index 0000000..a369ea6 --- /dev/null +++ b/tests/commentFirstTest.expected_results @@ -0,0 +1 @@ +1337 diff --git a/tests/commentFirstTest.krak b/tests/commentFirstTest.krak new file mode 100644 index 0000000..4464897 --- /dev/null +++ b/tests/commentFirstTest.krak @@ -0,0 +1,7 @@ +/* Comment first! */ +import io; + +int main() { + println(1337); + return 0; +} diff --git a/tests/functionMultipleTemplateTest.krak b/tests/functionMultipleTemplateTest.krak index f780891..e6d11ce 100644 --- a/tests/functionMultipleTemplateTest.krak +++ b/tests/functionMultipleTemplateTest.krak @@ -6,7 +6,7 @@ template void addAndPrint(T a, J b) { int main() { - addAndPrint(10,12.14159); + addAndPrint(10,12.14159); print("\n"); return 0; diff --git a/tests/traitsTest.expected_results b/tests/traitsTest.expected_results new file mode 100644 index 0000000..04f7294 --- /dev/null +++ b/tests/traitsTest.expected_results @@ -0,0 +1,5 @@ +No Traits +First Trait +Second Trait +Both Traits + diff --git a/tests/traitsTest.krak b/tests/traitsTest.krak new file mode 100644 index 0000000..ff6162e --- /dev/null +++ b/tests/traitsTest.krak @@ -0,0 +1,77 @@ +import io; + +typedef NoTraits {}; + +typedef Trait1 (FirstTrait) {}; +typedef Trait2 (SecondTrait) {}; +typedef TwoTrait (FirstTrait, SecondTrait) {}; +typedef AlreadySpecilized (FirstTrait, SecondTrait) {}; + +template void OneTwoFunc(T obj) { + println("No Traits"); +} + +template void OneTwoFunc(T obj) { + println("First Trait"); +} + +template void OneTwoFunc(T obj) { + println("Second Trait"); +} + +template void OneTwoFunc(T obj) { + println("Both Traits"); +} +/* +template void OneTwoFunc(AlreadySpecilized obj) { + println("Already Specilized"); +} +*/ +//This should work for objects too! +//To test, we cycle the mapping of traits + +/* + *typedef template OneTwoObj (FirstTrait) {}; + *typedef template OneTwoObj (SecondTrait) {}; + *typedef template OneTwoObj (FirstTrait, SecondTrait) {}; + *typedef template OneTwoObj {}; + *typedef template OneTwoObj { + * void proveSpecilized() { + * println("I'm specilized!"); + * } + *}; + */ + +int main() { + NoTraits a; + Trait1 b; + Trait2 c; + TwoTrait d; + AlreadySpecilized e; + + OneTwoFunc(a); + OneTwoFunc(b); + OneTwoFunc(c); + OneTwoFunc(d); +// OneTwoFunc(e); + + println(); + +/* + * OneTwoObj alpha; + * OneTwoObj beta; + * OneTwoObj gamma; + * OneTwoObj delta; + * OneTwoObj epsilon; + * + * OneTwoFunc>(alpha); + * OneTwoFunc>(b); + * OneTwoFunc>(c); + * OneTwoFunc>(d); + * + * //We can't pass along our inner part, so let's just make sure that it is the right object. + * //epsilon.proveSpecilized(); + */ + + return 0; +} From 93a170408f8086cef2e9a7d92e6b7a1e665cb89e Mon Sep 17 00:00:00 2001 From: Nathan Braswell Date: Sun, 20 Jul 2014 14:21:41 -0700 Subject: [PATCH 31/37] Object traits working now as well. Only specilized templates don't, because I have not yet decided the syntax for them. --- include/ASTTransformation.h | 3 +- include/Type.h | 2 +- src/ASTTransformation.cpp | 96 +++++++++++++++++++++++++------ src/Type.cpp | 4 +- tests/traitsTest.expected_results | 4 ++ tests/traitsTest.krak | 36 ++++++------ 6 files changed, 104 insertions(+), 41 deletions(-) diff --git a/include/ASTTransformation.h b/include/ASTTransformation.h index 18f4e43..4d728a8 100644 --- a/include/ASTTransformation.h +++ b/include/ASTTransformation.h @@ -49,9 +49,10 @@ class ASTTransformation: public NodeTransformation { std::vector*> scopeLookup(NodeTree* scope, std::string lookup); Type* typeFromTypeNode(NodeTree* typeNode, NodeTree* scope, std::map templateTypeReplacements, bool instantiateTemplates); + 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); - std::vector>> makeTemplateFunctionNameTraitPairs(NodeTree* templateNode); + std::vector>> makeTemplateNameTraitPairs(NodeTree* templateNode); private: Importer * importer; std::map*>> languageLevelReservedWords; diff --git a/include/Type.h b/include/Type.h index a56286e..a47fa7b 100644 --- a/include/Type.h +++ b/include/Type.h @@ -30,7 +30,7 @@ class Type { bool const operator==(const Type &other)const; bool const operator!=(const Type &other)const; Type* clone(); - std::string toString(); + std::string toString(bool showTraits = true); int getIndirection(); void setIndirection(int indirectionIn); void increaseIndirection(); diff --git a/src/ASTTransformation.cpp b/src/ASTTransformation.cpp index 33a456c..a5cd7bd 100644 --- a/src/ASTTransformation.cpp +++ b/src/ASTTransformation.cpp @@ -819,6 +819,59 @@ NodeTree* ASTTransformation::functionLookup(NodeTree* scope, s return NULL; } +//Lookup class templates. It evaluates possible matches on traits +NodeTree* ASTTransformation::templateClassLookup(NodeTree* scope, std::string lookup, std::vector templateInstantiationTypes) { + std::vector*> mostFittingTemplates; + int bestNumTraitsSatisfied = -1; + auto possibleMatches = scopeLookup(scope, lookup); + std::cout << "Template Class instantiation has " << possibleMatches.size() << " possible matches." << std::endl; + for (auto i : possibleMatches) { + NodeTree* templateSyntaxTree = i->getDataRef()->valueType->templateDefinition; + + auto nameTraitsPairs = makeTemplateNameTraitPairs(templateSyntaxTree->getChildren()[0]); + //Check if sizes match between the placeholder and actual template types + if (nameTraitsPairs.size() != templateInstantiationTypes.size()) + continue; + + bool traitsEqual = true; + int typeIndex = 0; + int currentTraitsSatisfied = 0; + for (auto j : nameTraitsPairs) { + if (j.second != templateInstantiationTypes[typeIndex]->traits) { + traitsEqual = false; + std::cout << "Traits unequal 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; + } + currentTraitsSatisfied += templateInstantiationTypes[typeIndex]->traits.size(); + typeIndex++; + } + if (!traitsEqual) + continue; + + //See if this is a better match than the current best + if (currentTraitsSatisfied > bestNumTraitsSatisfied) { + mostFittingTemplates.clear(); + std::cout << "Class satisfying " << currentTraitsSatisfied << " beats previous " << bestNumTraitsSatisfied << std::endl; + bestNumTraitsSatisfied = currentTraitsSatisfied; + } else if (currentTraitsSatisfied < bestNumTraitsSatisfied) + continue; + mostFittingTemplates.push_back(i); + std::cout << "Current class fits, satisfying " << currentTraitsSatisfied << " traits" << std::endl; + } + if (!mostFittingTemplates.size()) { + std::cout << "No template classes fit for " << lookup << "!" << std::endl; + throw "No matching template classes"; + } else if (mostFittingTemplates.size() > 1) { + std::cout << "Multiple template classes fit with equal number of traits satisfied for " << lookup << "!" << std::endl; + throw "Multiple matching template classes"; + } + return mostFittingTemplates[0]; +} //Lookup function for template functions. It has some extra concerns compared to function lookup, namely traits NodeTree* ASTTransformation::templateFunctionLookup(NodeTree* scope, std::string lookup, std::vector templateInstantiationTypes, std::vector types) { @@ -826,12 +879,12 @@ NodeTree* ASTTransformation::templateFunctionLookup(NodeTree* int bestNumTraitsSatisfied = -1; auto possibleMatches = scopeLookup(scope, lookup); std::cout << "Template Function instantiation has " << possibleMatches.size() << " possible matches." << std::endl; + int index = 1; for (auto i : possibleMatches) { + std::cout << "Possibility " << index++ << std::endl; NodeTree* templateSyntaxTree = i->getDataRef()->valueType->templateDefinition; - //When called without a second parameter, makeTemplateFunctionTypeMap returns a map with blank Types filled in that contain the correct Traits - auto nameTraitsPairs = makeTemplateFunctionNameTraitPairs(templateSyntaxTree->getChildren()[0]); - + auto nameTraitsPairs = makeTemplateNameTraitPairs(templateSyntaxTree->getChildren()[0]); //Check if sizes match between the placeholder and actual template types if (nameTraitsPairs.size() != templateInstantiationTypes.size()) continue; @@ -869,7 +922,7 @@ NodeTree* ASTTransformation::templateFunctionLookup(NodeTree* std::cout << "Template param type: " << paramType->toString() << " : Needed Type: " << types[j].toString() << std::endl; if (*paramType != types[j]) { parameterTypesMatch = false; - std::cout << "Not equal: " << paramType->toString() << " : Needed Type: " << types[j].toString() << std::endl; + std::cout << "Not equal template param: " << paramType->toString() << " : Needed Type actual param: " << types[j].toString() << std::endl; break; } } @@ -896,7 +949,7 @@ NodeTree* ASTTransformation::templateFunctionLookup(NodeTree* } //Extract pairs of type names and traits -std::vector>> ASTTransformation::makeTemplateFunctionNameTraitPairs(NodeTree* templateNode) { +std::vector>> ASTTransformation::makeTemplateNameTraitPairs(NodeTree* templateNode) { std::vector*> templateParams = slice(templateNode->getChildren(), 1, -2, 2); //Skip <, >, and interveaning commas std::vector>> typePairs; for (auto i : templateParams) { @@ -909,7 +962,7 @@ std::vector>> ASTTransformation::ma } std::map ASTTransformation::makeTemplateFunctionTypeMap(NodeTree* templateNode, std::vector types) { - auto typePairs = makeTemplateFunctionNameTraitPairs(templateNode); + auto typePairs = makeTemplateNameTraitPairs(templateNode); std::map typeMap; int typeIndex = 0; std::cout << typePairs.size() << " " << types.size() << std::endl; @@ -984,9 +1037,18 @@ Type* ASTTransformation::typeFromTypeNode(NodeTree* typeNode, NodeTreegetChildren().size() > 1 && typeNode->getChildren()[1]->getData().getName() == "template_inst") { std::cout << "Template type: " << edited << " not yet instantiated" << std::endl; + + //We pull out the replacement types first so that we can choose the correct possibly overloaded template + std::vector*> templateParamInstantiationNodes = slice(typeNode->getChildren()[1]->getChildren(), 1, -2, 2); //same + std::vector templateParamInstantiationTypes; + std::string instTypeString = ""; + for (int i = 0; i < templateParamInstantiationNodes.size(); i++) { + Type* instType = typeFromTypeNode(templateParamInstantiationNodes[i], scope, templateTypeReplacements, instantiateTemplates); + 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 - possibleMatches = scopeLookup(scope,concatSymbolTree(typeNode->getChildren()[0])); - NodeTree* templateDefinition = possibleMatches[0]; + NodeTree* templateDefinition = templateClassLookup(scope, concatSymbolTree(typeNode->getChildren()[0]), templateParamInstantiationTypes); if (templateDefinition == NULL) std::cout << "Template definition is null!" << std::endl; else @@ -994,25 +1056,23 @@ 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; -/*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::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))); - Type* selfType = new Type(typeDefinition); //Type is self-referential since this is the definition + 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 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 diff --git a/src/Type.cpp b/src/Type.cpp index f454127..a6988e6 100644 --- a/src/Type.cpp +++ b/src/Type.cpp @@ -65,7 +65,7 @@ const bool Type::operator!=(const Type &other) const { return(!this->operator==(other)); } -std::string Type::toString() { +std::string Type::toString(bool showTraits) { std::string typeString; switch (baseType) { case none: @@ -106,7 +106,7 @@ std::string Type::toString() { } for (int i = 0; i < indirection; i++) typeString += "*"; - if (traits.size()) { + if (traits.size() && showTraits) { typeString += "[ "; for (auto i : traits) typeString += i + " "; diff --git a/tests/traitsTest.expected_results b/tests/traitsTest.expected_results index 04f7294..603431e 100644 --- a/tests/traitsTest.expected_results +++ b/tests/traitsTest.expected_results @@ -3,3 +3,7 @@ First Trait Second Trait Both Traits +First Trait +Second Trait +Both Traits +No Traits diff --git a/tests/traitsTest.krak b/tests/traitsTest.krak index ff6162e..70e1ce9 100644 --- a/tests/traitsTest.krak +++ b/tests/traitsTest.krak @@ -30,11 +30,11 @@ template void OneTwoFunc(AlreadySpecilized obj) { //This should work for objects too! //To test, we cycle the mapping of traits +typedef template OneTwoObj (FirstTrait) {}; +typedef template OneTwoObj (SecondTrait) {}; +typedef template OneTwoObj (FirstTrait, SecondTrait) {}; +typedef template OneTwoObj {}; /* - *typedef template OneTwoObj (FirstTrait) {}; - *typedef template OneTwoObj (SecondTrait) {}; - *typedef template OneTwoObj (FirstTrait, SecondTrait) {}; - *typedef template OneTwoObj {}; *typedef template OneTwoObj { * void proveSpecilized() { * println("I'm specilized!"); @@ -57,21 +57,19 @@ int main() { println(); -/* - * OneTwoObj alpha; - * OneTwoObj beta; - * OneTwoObj gamma; - * OneTwoObj delta; - * OneTwoObj epsilon; - * - * OneTwoFunc>(alpha); - * OneTwoFunc>(b); - * OneTwoFunc>(c); - * OneTwoFunc>(d); - * - * //We can't pass along our inner part, so let's just make sure that it is the right object. - * //epsilon.proveSpecilized(); - */ + OneTwoObj alpha; + OneTwoObj beta; + OneTwoObj gamma; + OneTwoObj delta; +// OneTwoObj epsilon; + + OneTwoFunc>(alpha); + OneTwoFunc>(beta); + OneTwoFunc>(gamma); + OneTwoFunc>(delta); + + //We can't pass along our inner part, so let's just make sure that it is the right object. + //epsilon.proveSpecilized(); return 0; } From eae538907dbac973443647fbfd93aebdb17ff773 Mon Sep 17 00:00:00 2001 From: Nathan Braswell Date: Sun, 20 Jul 2014 20:42:26 -0700 Subject: [PATCH 32/37] Fixed some mem things, found an odd parsing bug where a // comment before a function definition at top level does not parse. Deferring for now. --- krakenGrammer.kgm | 4 ---- src/ASTTransformation.cpp | 14 ++++++++++++-- stdlib/mem.krak | 16 +++++++++++----- 3 files changed, 23 insertions(+), 11 deletions(-) diff --git a/krakenGrammer.kgm b/krakenGrammer.kgm index e7cb9de..1e735b0 100644 --- a/krakenGrammer.kgm +++ b/krakenGrammer.kgm @@ -7,10 +7,6 @@ type = type WS "\*" | "void" | "int" | "float" | "double" | "char" | identifier template_inst = "<" WS type_list WS ">" ; type_list = type_list WS "," WS type | type ; -#What does that even mean? -#some -# -# template_dec = "template" WS "<" WS template_param_list WS ">" ; template_param_list = template_param_list WS "," WS template_param | template_param ; template_param = identifier WS traits | identifier ; diff --git a/src/ASTTransformation.cpp b/src/ASTTransformation.cpp index a5cd7bd..688ba8d 100644 --- a/src/ASTTransformation.cpp +++ b/src/ASTTransformation.cpp @@ -331,13 +331,13 @@ NodeTree* ASTTransformation::transform(NodeTree* from, NodeTree if (types.size()) { newNode = functionLookup(scope, lookupName, types); if (newNode == NULL) { - std::cout << "scope lookup error! Could not find " << lookupName << " in identifier " << std::endl; + std::cout << "scope lookup error! Could not find " << lookupName << " in identifier (functionLookup)" << std::endl; throw "LOOKUP ERROR: " + lookupName; } } else { auto possibleMatches = scopeLookup(scope, lookupName); if (!possibleMatches.size()) { - std::cout << "scope lookup error! Could not find " << lookupName << " in identifier " << std::endl; + std::cout << "scope lookup error! Could not find " << lookupName << " in identifier (scopeLookup)" << std::endl; throw "LOOKUP ERROR: " + lookupName; } newNode = possibleMatches[0]; @@ -883,6 +883,10 @@ NodeTree* ASTTransformation::templateFunctionLookup(NodeTree* for (auto i : possibleMatches) { std::cout << "Possibility " << index++ << std::endl; NodeTree* templateSyntaxTree = i->getDataRef()->valueType->templateDefinition; + if (!templateSyntaxTree) { + std::cout << "Not a template, skipping" << std::endl; + continue; + } auto nameTraitsPairs = makeTemplateNameTraitPairs(templateSyntaxTree->getChildren()[0]); //Check if sizes match between the placeholder and actual template types @@ -975,6 +979,12 @@ std::map ASTTransformation::makeTemplateFunctionTypeMap(Node } std::vector*> ASTTransformation::scopeLookup(NodeTree* scope, std::string lookup) { + //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()) { + std::cout << "found it at language level as reserved word." << std::endl; + return LLElementIterator->second; + } std::vector*> matches; std::map*>> scopeMap = scope->getDataRef()->scope; auto possibleMatches = scopeMap.find(lookup); diff --git a/stdlib/mem.krak b/stdlib/mem.krak index c4b30c5..48b0505 100644 --- a/stdlib/mem.krak +++ b/stdlib/mem.krak @@ -22,6 +22,7 @@ void free(char* memPtr) { } } +/* we have a template version so we don't have to cast */ template void free(T* memPtr) { __if_comp__ __C__ { __simple_passthrough__ """ @@ -41,7 +42,6 @@ template int sizeof() { return result; } - template T* new(int count) { return malloc( sizeof() * count ); } @@ -50,18 +50,24 @@ template T* new() { return new(1); } -template void delete(T* toDelete, int itemDestructCount) { +/* We specilize on the trait Destructable to decide on whether or not the destructor should be called */ +template void delete(T* toDelete, int itemCount) { + delete(toDelete); +} + +template void delete(T* toDelete, int itemCount) { for (int i = 0; i < itemDestructCount; i++;) toDelete[i].destruct(); delete(toDelete); } +/* We specilize on the trait Destructable to decide on whether or not the destructor should be called */ template void delete(T* toDelete) { - delete(toDelete, true); + free(toDelete); } -template void delete(T* toDelete, bool destruct) { +template void delete(T* toDelete) { if (destruct) toDelete->destruct(); - free(toDelete); + free(toDelete); } From 87ad0c187ef3719f25a6342ff474d650849b6ee2 Mon Sep 17 00:00:00 2001 From: Nathan Braswell Date: Wed, 23 Jul 2014 02:23:21 -0700 Subject: [PATCH 33/37] Fixed quite a few bugs, including makeing find template functions check for trait subset, not trait equality, and add the number required to the satisfied count. Based on what is now breaking, it looks like it's time to give the builtin functions types. --- include/ASTTransformation.h | 10 +- include/util.h | 9 ++ krakenGrammer.kgm | 2 +- src/ASTTransformation.cpp | 264 +++++++++++++++++++++--------------- stdlib/mem.krak | 5 +- stdlib/vector.krak | 4 +- tests/vectorTest.krak | 19 +-- 7 files changed, 182 insertions(+), 131 deletions(-) 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; } From 4cf8dbbd5bb0f013dbdf6920c9b6ef305e62505e Mon Sep 17 00:00:00 2001 From: Nathan Braswell Date: Mon, 28 Jul 2014 01:52:15 -0700 Subject: [PATCH 34/37] vector and vector test are finally working! Also found some bugs that I don't have time to fix before bed. Added file future_features.txt to keep track of bugs and features. --- future_features.txt | 10 ++ include/CGenerator.h | 4 +- krakenGrammer.kgm | 2 +- src/ASTTransformation.cpp | 45 ++++--- src/CGenerator.cpp | 193 +++++++++++++++++++----------- stdlib/mem.krak | 18 +-- stdlib/vector.krak | 21 ++-- tests/vectorTest.expected_results | 1 - tests/vectorTest.krak | 6 +- 9 files changed, 183 insertions(+), 117 deletions(-) create mode 100644 future_features.txt diff --git a/future_features.txt b/future_features.txt new file mode 100644 index 0000000..88b0a92 --- /dev/null +++ b/future_features.txt @@ -0,0 +1,10 @@ +Declaration of a pointer and multiplication are ambigious! +( T* a; maybe either a declaration or a multiplication) + +Fix destructors being placed after return. +Fix functions before declaration? (in class? (this is from an old file)) +Template instantiation without explicit type param +Fix // comment right before top level function declaration. Something to do +with the return as /* comment */ does not have that problem +for in or for each loops +Traits on aliases, maybe that keep their old traits? diff --git a/include/CGenerator.h b/include/CGenerator.h index 84fba11..a0472fb 100644 --- a/include/CGenerator.h +++ b/include/CGenerator.h @@ -18,11 +18,13 @@ class CGenerator { CGenerator(); ~CGenerator(); void generateCompSet(std::map*> ASTs, std::string outputName); + std::string generateClassStruct(NodeTree* from); std::string generate(NodeTree* from, NodeTree* enclosingObject = NULL); + std::string generateAliasChains(NodeTree* scopeNode, NodeTree* definition); static std::string ValueTypeToCType(Type *type); static std::string ValueTypeToCTypeDecoration(Type *type); static std::string CifyName(std::string name); - std::string generateObjectMethod(NodeTree* enclosingObject, NodeTree* from); + std::string generateObjectMethod(NodeTree* enclosingObject, NodeTree* from, std::string *functionPrototype); NodeTree* getMethodsObjectType(NodeTree* scope, std::string functionName); std::string generatorString; private: diff --git a/krakenGrammer.kgm b/krakenGrammer.kgm index c1bfd26..799c1ab 100644 --- a/krakenGrammer.kgm +++ b/krakenGrammer.kgm @@ -96,7 +96,7 @@ declaration_statement = type WS identifier WS "=" WS boolean_expression | type W alphanumeric = alphanumeric numeric | alphanumeric alpha | numeric | alpha ; hexadecimal = "0x(1|2|3|4|5|6|7|8|9|a|b|c|d|e|f)+" ; sign = "\+|-" WS | ; -integer = sign numeric | sign hexadecimal | "null" ; +integer = sign numeric | sign hexadecimal ; floating_literal = sign numeric "." numeric | sign numeric "." numeric alpha ; bool = "true" | "false" | "True" | "False" ; character = "'(`|1|2|3|4|5|6|7|8|9|0|-|=| |q|w|e|r|t|y|u|i|o|p|[|]|\\|a|s|d|f|g|h|j|k|l|;|'| diff --git a/src/ASTTransformation.cpp b/src/ASTTransformation.cpp index efd6be0..c883adf 100644 --- a/src/ASTTransformation.cpp +++ b/src/ASTTransformation.cpp @@ -17,14 +17,14 @@ ASTTransformation::ASTTransformation(Importer *importerIn) { languageLevelOperators["&"].push_back(new NodeTree("function", ASTData(function, Symbol("&", true), NULL))); languageLevelOperators["--"].push_back(new NodeTree("function", ASTData(function, Symbol("--", true), NULL))); languageLevelOperators["++"].push_back(new NodeTree("function", ASTData(function, Symbol("++", true), NULL))); - languageLevelOperators["=="].push_back(new NodeTree("function", ASTData(function, Symbol("==", true), NULL))); - languageLevelOperators["<="].push_back(new NodeTree("function", ASTData(function, Symbol("<=", true), NULL))); - languageLevelOperators[">="].push_back(new NodeTree("function", ASTData(function, Symbol(">=", true), NULL))); - languageLevelOperators["<"].push_back(new NodeTree("function", ASTData(function, Symbol("<", true), NULL))); - languageLevelOperators[">"].push_back(new NodeTree("function", ASTData(function, Symbol(">", true), NULL))); - languageLevelOperators["&&"].push_back(new NodeTree("function", ASTData(function, Symbol("&&", true), NULL))); - languageLevelOperators["||"].push_back(new NodeTree("function", ASTData(function, Symbol("||", true), NULL))); - languageLevelOperators["!"].push_back(new NodeTree("function", ASTData(function, Symbol("!", true), NULL))); + languageLevelOperators["=="].push_back(new NodeTree("function", ASTData(function, Symbol("==", true), new Type(boolean)))); + languageLevelOperators["<="].push_back(new NodeTree("function", ASTData(function, Symbol("<=", true), new Type(boolean)))); + languageLevelOperators[">="].push_back(new NodeTree("function", ASTData(function, Symbol(">=", true), new Type(boolean)))); + languageLevelOperators["<"].push_back(new NodeTree("function", ASTData(function, Symbol("<", true), new Type(boolean)))); + languageLevelOperators[">"].push_back(new NodeTree("function", ASTData(function, Symbol(">", true), new Type(boolean)))); + languageLevelOperators["&&"].push_back(new NodeTree("function", ASTData(function, Symbol("&&", true), new Type(boolean)))); + languageLevelOperators["||"].push_back(new NodeTree("function", ASTData(function, Symbol("||", true), new Type(boolean)))); + languageLevelOperators["!"].push_back(new NodeTree("function", ASTData(function, Symbol("!", true), new Type(boolean)))); languageLevelOperators["*="].push_back(new NodeTree("function", ASTData(function, Symbol("*=", true), NULL))); languageLevelOperators["+="].push_back(new NodeTree("function", ASTData(function, Symbol("+=", true), NULL))); languageLevelOperators["-="].push_back(new NodeTree("function", ASTData(function, Symbol("-=", true), NULL))); @@ -651,10 +651,14 @@ 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 == "string" || name == "triple_quoted_string") { newNode = new NodeTree(name, ASTData(value, Symbol(concatSymbolTree(children[0]), true), new Type(character, 1))); //Indirection of 1 for array - }else if (name == "character") { + } 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 if (name == "bool") { + newNode = new NodeTree(name, ASTData(value, Symbol(concatSymbolTree(children[0]), true), new Type(boolean, 0))); //Indirection of 0 for character } else if (name == "AmbiguityPackOuter" || name == "AmbiguityPackInner") { + std::cout << "///////////////////////////////////////////////////////////////////////////////" << std::endl; std::cout << "Ambigious program when parsed by this grammer! This is a bug, please report it." << std::endl; + std::cout << "///////////////////////////////////////////////////////////////////////////////" << std::endl; throw "Ambigious parse!"; } else { // Should get rid of this eventually. Right now it handles cases like sign, alpha, a comma, etc @@ -1128,10 +1132,11 @@ Type* ASTTransformation::typeFromTypeNode(NodeTree* typeNode, NodeTreegetDataRef()->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); - + //NodeTree* templateHighScope = templateDefinition->getDataRef()->scope["~enclosing_scope"][0]; + //if (topScope != templateHighScope) + //templateHighScope->getDataRef()->scope[fullyInstantiatedName].push_back(typeDefinition); + // We put it in the scope of the template so that it can find itself (as it's scope is its template definition) + templateDefinition->getDataRef()->scope[fullyInstantiatedName].push_back(typeDefinition); //Note that the instantiated template's scope is the template's definition. typeDefinition->getDataRef()->scope["~enclosing_scope"].push_back(templateDefinition); @@ -1184,7 +1189,12 @@ NodeTree* ASTTransformation::findOrInstantiateFunctionTemplate(std::vec if (instantiatedFunction) { std::cout << fullyInstantiatedName << " already exists! Returning" << std::endl; return instantiatedFunction; - } else { + } else { + instantiatedFunction = functionLookup(topScope, fullyInstantiatedName, types); + if (instantiatedFunction) { + std::cout << fullyInstantiatedName << "already exists! Found in TopScope" << std::endl; + return instantiatedFunction; + } std::cout << fullyInstantiatedName << " does NOT exist" << std::endl; } @@ -1210,13 +1220,14 @@ NodeTree* ASTTransformation::findOrInstantiateFunctionTemplate(std::vec skipChildren.insert(0); skipChildren.insert(1); skipChildren.insert(2); - scope->getDataRef()->scope[fullyInstantiatedName].push_back(instantiatedFunction); + //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 + topScope->getDataRef()->scope[fullyInstantiatedName].push_back(instantiatedFunction); + topScope->addChild(instantiatedFunction); //Add this object the the highest scope's + std::cout << "About to do children of " << functionName << " to " << fullyInstantiatedName << std::endl; 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 std::cout << "Fully Instantiated function " << functionName << " to " << fullyInstantiatedName << std::endl; diff --git a/src/CGenerator.cpp b/src/CGenerator.cpp index 20e875e..6234d7a 100644 --- a/src/CGenerator.cpp +++ b/src/CGenerator.cpp @@ -15,7 +15,8 @@ void CGenerator::generateCompSet(std::map*> ASTs, std::ofstream outputCFile; outputCFile.open(i->first + ".c"); if (outputCFile.is_open()) { - outputCFile << generate(i->second); + // Prequel common to all files + outputCFile << "#include \n#include \n#include \n" << generate(i->second); } else { std::cout << "Cannot open file " << i->first << ".c" << std::endl; } @@ -35,64 +36,109 @@ std::string CGenerator::tabs() { return returnTabs; } +std::string CGenerator::generateClassStruct(NodeTree* from) { + auto data = from->getData(); + auto children = from->getChildren(); + std::string objectString = "struct __struct_dummy_" + CifyName(data.symbol.getName()) + "__ {\n"; + tabLevel++; + for (int i = 0; i < children.size(); i++) { + std::cout << children[i]->getName() << std::endl; + if (children[i]->getName() != "function") + objectString += tabs() + generate(children[i], nullptr) + "\n"; + } + tabLevel--; + objectString += "};"; + return objectString; +} + +// This method recurseivly generates all aliases of some definition +std::string CGenerator::generateAliasChains(NodeTree* scopeNode, NodeTree* definition) { + auto scope = scopeNode->getDataRef()->scope; + std::string output; + for (auto i = scope.begin(); i != scope.end(); i++) { + for (auto declaration : i->second) { + auto declarationData = declaration->getDataRef(); + if (declarationData->type == type_def + && declarationData->valueType->typeDefinition != declaration + && declarationData->valueType->typeDefinition == definition) { + output += "typedef " + CifyName(definition->getDataRef()->symbol.getName()) + " " + CifyName(declarationData->symbol.getName()) + ";\n"; + // Recursively add the ones that depend on this one + output += generateAliasChains(scopeNode, declaration); + } + } + } + return output; +} + //The enclosing object is for when we're generating the inside of object methods. They allow us to check scope lookups against the object we're in std::string CGenerator::generate(NodeTree* from, NodeTree* enclosingObject) { ASTData data = from->getData(); std::vector*> children = from->getChildren(); - std::string output = ""; + std::string output; switch (data.type) { case translation_unit: - //Do here because we may need the typedefs before the declarations of variables - //Note that we need to be careful of the order, though, as some declarations depend on others. - //What is this then? It's a poset! Wooo posets! { + // Ok, so we've got to do this in passes to preserve mututally recursive definitions. + // + // First Pass: All classes get "struct dummy_thing; typedef struct dummy_thing thing;". + // Also, other typedefs follow after their naming. + // Second Pass: All top level variable declarations + // Third Pass: Define all actual structs of a class, in correct order (done with posets) + // Fourth Pass: Declare all function prototypes (as functions may be mutually recursive too). + // (this includes object methods) + // Fifth Pass: Define all functions (including object methods). + + // However, most of these do not actually have to be done as separate passes. First, second, fourth, and fifth + // are done simultanously, but append to different strings that are then concatinated properly, in order. + + std::string plainTypedefs = "/**\n * Plain Typedefs\n */\n\n"; + std::string variableDeclarations = "/**\n * Variable Declarations \n */\n\n"; + std::string classStructs = "/**\n * Class Structs\n */\n\n"; + std::string functionPrototypes = "/**\n * Function Prototypes\n */\n\n"; + std::string functionDefinitions = "/**\n * Function Definitions\n */\n\n"; + Poset*> typedefPoset; for (int i = 0; i < children.size(); i++) { if (children[i]->getDataRef()->type == type_def) { - typedefPoset.addVertex(children[i]); //We add this definition by itthis just in case there are no dependencies. - //If it has dependencies, there's no harm in adding it here - //Go through every child in the class looking for declaration statements. For each of these that is not a primitive type - //we will add a dependency from this definition to that definition in the poset. + // If we're an alias type, continue. We handle those differently + if (children[i]->getDataRef()->valueType->typeDefinition != children[i]) + continue; + + typedefPoset.addVertex(children[i]); // We add this definition by itself just in case there are no dependencies. + // If it has dependencies, there's no harm in adding it here + // Go through every child in the class looking for declaration statements. For each of these that is not a primitive type + // we will add a dependency from this definition to that definition in the poset. std::vector*> classChildren = children[i]->getChildren(); for (auto j : classChildren) { if (j->getDataRef()->type == declaration_statement) { - Type* decType = j->getChildren()[0]->getDataRef()->valueType; //Type of the declaration - if (decType->typeDefinition && decType->getIndirection() == 0) //If this is a custom type and not a pointer - typedefPoset.addRelationship(children[i], decType->typeDefinition); //Add a dependency + Type* decType = j->getChildren()[0]->getDataRef()->valueType; // Type of the declaration + if (decType->typeDefinition && decType->getIndirection() == 0) // If this is a custom type and not a pointer + typedefPoset.addRelationship(children[i], decType->typeDefinition); // Add a dependency } } - //In case there are pointer dependencies. We don't do this if this is an alias type - if (children[i]->getDataRef()->valueType->typeDefinition == children[i]) - output += "struct " + CifyName(children[i]->getDataRef()->symbol.getName()) + ";\n"; - else { - Type *aliasType = children[i]->getDataRef()->valueType; - if (aliasType->typeDefinition && !aliasType->templateDefinition) //Isn't uninstantiated template or 0 parameter class, so must be alias. if typeDefinition isn't null, then it's an alias of a custom, not a primitive, type. - 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 for (NodeTree* i : typedefPoset.getTopoSort()) - output += generate(i, enclosingObject) + "\n"; + classStructs += generateClassStruct(i) + "\n"; //Declare everything in translation unit scope here. (allows stuff from other files, automatic forward declarations) for (auto i = data.scope.begin(); i != data.scope.end(); i++) { - for (auto overloadedMembers : i->second) { - NodeTree* declaration = overloadedMembers; + for (auto declaration : i->second) { std::vector*> decChildren = declaration->getChildren(); ASTData declarationData = declaration->getData(); switch(declarationData.type) { case identifier: - output += ValueTypeToCType(declarationData.valueType) + " " + declarationData.symbol.getName() + "; /*identifier*/\n"; + variableDeclarations += ValueTypeToCType(declarationData.valueType) + " " + declarationData.symbol.getName() + "; /*identifier*/\n"; break; case function: { if (declarationData.valueType->baseType == template_type) - output += "/* template function " + declarationData.symbol.toString() + " */\n"; + functionPrototypes += "/* 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"; + functionPrototypes += "/* built in function: " + declarationData.symbol.toString() + " */\n"; else { - output += "\n" + ValueTypeToCType(declarationData.valueType) + " "; + functionPrototypes += "\n" + ValueTypeToCType(declarationData.valueType) + " "; std::string nameDecoration, parameters; for (int j = 0; j < decChildren.size()-1; j++) { if (j > 0) @@ -100,24 +146,51 @@ 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"; + functionPrototypes += CifyName(declarationData.symbol.getName() + nameDecoration) + "(" + parameters + "); /*func*/\n"; + // Only generate function if this is the unit it was defined in + std::cout << "Generating " << CifyName(declarationData.symbol.getName()) << std::endl; + if (contains(children, declaration)) + functionDefinitions += generate(declaration, enclosingObject); } } break; - case type_def: - //type - output += "/*typedef " + declarationData.symbol.getName() + " */\n"; - break; + case type_def: + //type + plainTypedefs += "/*typedef " + declarationData.symbol.getName() + " */\n"; + + if (declarationData.valueType->baseType == template_type) { + plainTypedefs += "/* non instantiated template " + declarationData.symbol.getName() + " */"; + } else if (declarationData.valueType->typeDefinition != declaration) { + if (declarationData.valueType->typeDefinition) + continue; // Aliases of objects are done with the thing it alises + // Otherwise, we're actually a renaming of a primitive, can generate here + plainTypedefs += "typedef " + ValueTypeToCType(declarationData.valueType) + " " + CifyName(declarationData.symbol.getName()) + ";\n"; + plainTypedefs += generateAliasChains(from, declaration); + } else { + plainTypedefs += "typedef struct __struct_dummy_" + CifyName(declarationData.symbol.getName()) + "__ " + CifyName(declarationData.symbol.getName()) + ";\n"; + functionPrototypes += "/* Method Prototypes for " + declarationData.symbol.getName() + " */\n"; + // We use a seperate string for this because we only include it if this is the file we're defined in + std::string objectFunctionDefinitions = "/* Method Definitions for " + declarationData.symbol.getName() + " */\n"; + for (int j = 0; j < decChildren.size(); j++) { + std::cout << decChildren[j]->getName() << std::endl; + if (decChildren[j]->getName() == "function") //If object method + objectFunctionDefinitions += generateObjectMethod(declaration, decChildren[j], &functionPrototypes) + "\n"; + } + // Add all aliases to the plain typedefs. This will add any alias that aliases to this object, and any alias that aliases to that, and so on + plainTypedefs += generateAliasChains(from, declaration); + functionPrototypes += "/* Done with " + declarationData.symbol.getName() + " */\n"; + // If this is the file the object is defined in, include methods + if (contains(children, declaration)) + functionDefinitions += objectFunctionDefinitions + "/* Done with " + declarationData.symbol.getName() + " */\n"; + } + break; default: //std::cout << "Declaration? named " << declaration->getName() << " of unknown type " << ASTData::ASTTypeToString(declarationData.type) << " in translation unit scope" << std::endl; output += "/*unknown declaration named " + declaration->getName() + "*/\n"; } } } - //Do here because we need the newlines - for (int i = 0; i < children.size(); i++) - if (children[i]->getDataRef()->type != type_def) - output += generate(children[i], enclosingObject) + "\n"; + output += plainTypedefs + variableDeclarations + classStructs + functionPrototypes + functionDefinitions; return output; } break; @@ -139,31 +212,8 @@ std::string CGenerator::generate(NodeTree* from, NodeTree* enc std::string preName; if (enclosingObject && enclosingObject->getDataRef()->scope.find(data.symbol.getName()) != enclosingObject->getDataRef()->scope.end()) preName += "this->"; - if (false) - for (int j = 0; j < children.size()-1; j++) - preName += ValueTypeToCType(children[j]->getData().valueType) + "_"; return preName + CifyName(data.symbol.getName()); //Cifying does nothing if not an operator overload } - case type_def: - if (data.valueType->baseType == template_type) { - return "/* non instantiated template " + data.symbol.getName() + " */"; - } else if (data.valueType->typeDefinition != from) { - return "typedef " + ValueTypeToCType(data.valueType) + " " + data.symbol.getName() + ";"; - } else { - std::string objectString = "typedef struct __struct_dummy_" + CifyName(data.symbol.getName()) + "__ {\n"; - std::string postString; //The functions have to be outside the struct definition - tabLevel++; - for (int i = 0; i < children.size(); i++) { - std::cout << children[i]->getName() << std::endl; - if (children[i]->getName() == "function") //If object method - postString += generateObjectMethod(from, children[i]) + "\n"; - else - objectString += tabs() + generate(children[i], enclosingObject) + "\n"; - } - tabLevel--; - objectString += "} " + CifyName(data.symbol.getName()) + ";"; - return objectString + postString; //Functions come after the declaration of the struct - } case function: { if (data.valueType->baseType == template_type) @@ -191,7 +241,10 @@ std::string CGenerator::generate(NodeTree* from, NodeTree* enc output += line; if (children[i]->getChildren().size() && children[i]->getChildren()[0]->getDataRef()->type == declaration_statement) { NodeTree *identifier = children[i]->getChildren()[0]->getChildren()[0]; - NodeTree *typeDefinition = identifier->getDataRef()->valueType->typeDefinition; + Type* declarationType = identifier->getDataRef()->valueType; + if (declarationType->getIndirection()) + continue; + NodeTree *typeDefinition = declarationType->typeDefinition; if (!typeDefinition) continue; if (typeDefinition->getDataRef()->scope.find("destruct") == typeDefinition->getDataRef()->scope.end()) @@ -261,13 +314,13 @@ std::string CGenerator::generate(NodeTree* from, NodeTree* enc if (funcType == function) { if (name == "++" || name == "--") return generate(children[1], enclosingObject) + name; - if ( (name == "*" || name == "&") && children.size() == 2) //Is dereference, not multiplication, or address-of + if ( (name == "*" || name == "&" || name == "!" ) && children.size() == 2) //Is dereference, not multiplication, address-of, or other unary operator return name + "(" + generate(children[1], enclosingObject) + ")"; if (name == "[]") return "(" + generate(children[1], enclosingObject) + ")[" +generate(children[2],enclosingObject) + "]"; if (name == "+" || name == "-" || name == "*" || name == "/" || name == "==" || name == ">=" || name == "<=" || name == "!=" || name == "<" || name == ">" || name == "%" || name == "+=" || name == "-=" || name == "*=" || name == "/=" || name == "||" - || name == "&&" || name == "!" ) + || name == "&&") return "((" + generate(children[1], enclosingObject) + ")" + name + "(" + generate(children[2], enclosingObject) + "))"; else if (name == "." || name == "->") { if (children.size() == 1) @@ -310,7 +363,7 @@ std::string CGenerator::generate(NodeTree* from, NodeTree* enc //Check to see if we're inside of an object and this is a method call bool isSelfObjectMethod = enclosingObject && contains(enclosingObject->getChildren(), children[0]); if (isSelfObjectMethod) - output += enclosingObject->getDataRef()->symbol.getName() +"__"; + output += CifyName(enclosingObject->getDataRef()->symbol.getName()) +"__"; /*HERE*/ output += CifyName(name + nameDecoration) + "("; if (isSelfObjectMethod) output += children.size() > 1 ? "this," : "this"; @@ -349,8 +402,9 @@ NodeTree* CGenerator::getMethodsObjectType(NodeTree* scope, st scope = scope->getDataRef()->valueType->typeDefinition; return (scope->getDataRef()->scope.find(functionName) != scope->getDataRef()->scope.end()) ? scope : NULL; } -std::string CGenerator::generateObjectMethod(NodeTree* enclosingObject, NodeTree* from) { - std::string output; + +// Returns the function prototype in the out param and the full definition normally +std::string CGenerator::generateObjectMethod(NodeTree* enclosingObject, NodeTree* from, std::string *functionPrototype) { ASTData data = from->getData(); Type enclosingObjectType = *(enclosingObject->getDataRef()->valueType); //Copy a new type so we can turn it into a pointer if we need to enclosingObjectType.increaseIndirection(); @@ -360,10 +414,11 @@ std::string CGenerator::generateObjectMethod(NodeTree* enclosingObject, parameters += ", " + ValueTypeToCType(children[i]->getData().valueType) + " " + generate(children[i]); nameDecoration += "_" + ValueTypeToCTypeDecoration(children[i]->getData().valueType); } - output += "\n" + ValueTypeToCType(data.valueType) + " " + CifyName(enclosingObject->getDataRef()->symbol.getName()) +"__" + std::string functionSignature = "\n" + ValueTypeToCType(data.valueType) + " " + CifyName(enclosingObject->getDataRef()->symbol.getName()) +"__" + CifyName(data.symbol.getName()) + nameDecoration + "(" + ValueTypeToCType(&enclosingObjectType) - + " this" + parameters + ")\n" + generate(children[children.size()-1], enclosingObject); //Pass in the object so we can properly handle access to member stuff - return output; + + " this" + parameters + ")"; + *functionPrototype += functionSignature + ";\n"; + return functionSignature + "\n" + generate(children[children.size()-1], enclosingObject); //Pass in the object so we can properly handle access to member stuff } std::string CGenerator::ValueTypeToCType(Type *type) { @@ -407,7 +462,7 @@ std::string CGenerator::ValueTypeToCTypeDecoration(Type *type) { switch (type->baseType) { case none: if (type->typeDefinition) - return_type = type->typeDefinition->getDataRef()->symbol.getName(); + return_type = CifyName(type->typeDefinition->getDataRef()->symbol.getName()); else return_type = "none"; break; diff --git a/stdlib/mem.krak b/stdlib/mem.krak index 0c4ca92..b011463 100644 --- a/stdlib/mem.krak +++ b/stdlib/mem.krak @@ -2,10 +2,10 @@ __if_comp__ __C__ __simple_passthrough__ """ #include """ -char* nullPtr = 0; +/* we have a template versions so we don't have to cast (because we don't have that yet) */ -char* malloc(int size) { - char* memPtr = nullPtr; +template T* malloc(int size) { + T* memPtr = 0; __if_comp__ __C__ { __simple_passthrough__ """ memPtr = malloc(size); @@ -14,15 +14,6 @@ char* malloc(int size) { return memPtr; } -void free(char* memPtr) { - __if_comp__ __C__ { - __simple_passthrough__ """ - free(memPtr); - """ - } -} - -/* we have a template version so we don't have to cast */ template void free(T* memPtr) { __if_comp__ __C__ { __simple_passthrough__ """ @@ -43,7 +34,7 @@ template int sizeof() { } template T* new(int count) { - return malloc( sizeof() * count ); + return malloc( sizeof() * count ); } template T* new() { @@ -55,6 +46,7 @@ template void delete(T* toDelete, int itemCount) { delete(toDelete); } +/* Calling this with itemCount = 0 allows you to delete destructable objects without calling their destructors. */ template void delete(T* toDelete, int itemCount) { for (int i = 0; i < itemCount; i++;) toDelete[i].destruct(); diff --git a/stdlib/vector.krak b/stdlib/vector.krak index ae52fe6..ab320c2 100644 --- a/stdlib/vector.krak +++ b/stdlib/vector.krak @@ -1,15 +1,13 @@ import mem; import util; +import io; typedef template vector (Destructable) { T *data; int size; int available; - bool destroyItems; - vector* construct(bool destroyItemsIn) { - destroyItems = destroyItemsIn; - return construct(); + vector* construct() { size = 0; available = 8; data = new(8); @@ -17,17 +15,14 @@ typedef template vector (Destructable) { } void destruct() { - if (destroyItems) - delete(data, size); - else - delete(data); + delete(data); } bool resize(int newSize) { T* newData = new(newSize); if (!newData) return false; - for (int i = 0; i < lesser(size, newSize); i++;) + for (int i = 0; i < lesser(size, newSize); i++;) newData[i] = data[i]; delete(data, 0); return true; @@ -38,8 +33,10 @@ typedef template vector (Destructable) { } T get(int index) { - if (index < 0 || index >= size) - return null; + if (index < 0 || index >= size) { + println("Vector access out of bounds! Retuning 0th element as sanest option"); + return data[0]; + } return data[index]; } @@ -53,6 +50,6 @@ typedef template vector (Destructable) { size++; else resize(size*2); - data[size-1]; + data[size-1] = dataIn; } }; diff --git a/tests/vectorTest.expected_results b/tests/vectorTest.expected_results index 2239baa..c7ae395 100644 --- a/tests/vectorTest.expected_results +++ b/tests/vectorTest.expected_results @@ -1,3 +1,2 @@ 1337 Destroyed! - diff --git a/tests/vectorTest.krak b/tests/vectorTest.krak index 878745f..4ee170a 100644 --- a/tests/vectorTest.krak +++ b/tests/vectorTest.krak @@ -9,17 +9,17 @@ typedef AbleToBeDestroyed (Destructable) { }; int main() { - vector intVec.construct(false); + vector intVec.construct(); intVec.addEnd(1); intVec.addEnd(3); intVec.addEnd(3); intVec.addEnd(7); - for (int i = 0; i < intVec.size(); i++;) + for (int i = 0; i < intVec.size; i++;) print(intVec.at(i)); println(); - vector* desVec = new>()->construct(true); + vector* desVec = new>()->construct(); AbleToBeDestroyed testDestruct; desVec->addEnd(testDestruct); delete>(desVec); From 5b57770774daaa41211a4d2c64b98033ba07c51c Mon Sep 17 00:00:00 2001 From: Nathan Braswell Date: Fri, 1 Aug 2014 00:45:48 -0700 Subject: [PATCH 35/37] Declarations are now written |type| identifier;, generally. Functions are similar |void| func() {}, etc. Special declarations still work, etc --- krakenGrammer.kgm | 7 +++-- src/Importer.cpp | 2 ++ stdlib/io.krak | 16 +++++------ stdlib/math.krak | 8 +++--- stdlib/mem.krak | 26 ++++++++--------- stdlib/trivial_container.krak | 4 +-- stdlib/util.krak | 4 +-- stdlib/vector.krak | 24 ++++++++-------- tests/OperatorOverloadTest.krak | 32 ++++++++++----------- tests/RecursiveTest.krak | 4 +-- tests/commentFirstTest.krak | 2 +- tests/declarationsTest.krak | 14 ++++----- tests/destructorTest.krak | 18 ++++++------ tests/emptyBracesFunction.krak | 4 +-- tests/functionMultipleTemplateTest.krak | 4 +-- tests/functionOrderingTest.krak | 6 ++-- tests/functionTemplateTest.krak | 5 ++-- tests/memTest.krak | 14 ++++----- tests/moreComplexObjectTest.krak | 16 +++++------ tests/moreObjectTemplateTest.krak | 18 ++++++------ tests/objectOrderingTest.krak | 14 ++++----- tests/simpleFunctionTest.krak | 6 ++-- tests/simpleObjectMultipleTemplateTest.krak | 12 ++++---- tests/simpleObjectTemplateTest.krak | 12 ++++---- tests/simpleObjectTest.krak | 8 +++--- tests/templateTest.krak | 22 +++++++------- tests/testArrayNotation.krak | 6 ++-- tests/traitsTest.krak | 32 ++++++++++----------- tests/typeExpr.expected_results | 2 ++ tests/typeExpr.krak | 20 +++++++++++++ tests/vectorTest.krak | 12 ++++---- 31 files changed, 199 insertions(+), 175 deletions(-) create mode 100644 tests/typeExpr.expected_results create mode 100644 tests/typeExpr.krak diff --git a/krakenGrammer.kgm b/krakenGrammer.kgm index 799c1ab..a9af015 100644 --- a/krakenGrammer.kgm +++ b/krakenGrammer.kgm @@ -3,6 +3,7 @@ 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 ; +dec_type = "\|" WS type WS "\|" ; template_inst = "<" WS type_list WS ">" ; type_list = type_list WS "," WS type | type ; @@ -41,11 +42,11 @@ identifier = alpha | alpha alphanumeric ; right_shift = ">" ">" ; overloadable_operator = "\+" | "-" | "\*" | "/" | "%" | "^" | "&" | "\|" | "~" | "!" | "," | "=" | "\+\+" | "--" | "<<" | right_shift | "==" | "!=" | "&&" | "\|\|" | "\+=" | "-=" | "/=" | "%=" | "^=" | "&=" | "\|=" | "\*=" | "<<=" | ">>=" | "->" ; func_identifier = identifier | identifier overloadable_operator ; -function = template_dec WS type WS func_identifier WS "\(" WS opt_typed_parameter_list WS "\)" WS code_block | type WS func_identifier WS "\(" WS opt_typed_parameter_list WS "\)" WS code_block ; +function = template_dec WS dec_type WS func_identifier WS "\(" WS opt_typed_parameter_list WS "\)" WS code_block | dec_type WS func_identifier WS "\(" WS opt_typed_parameter_list WS "\)" WS code_block ; opt_typed_parameter_list = typed_parameter_list | ; typed_parameter_list = typed_parameter_list WS "," WS typed_parameter | typed_parameter ; -typed_parameter = type WS identifier ; +typed_parameter = dec_type WS identifier ; opt_parameter_list = parameter_list | ; parameter_list = parameter_list WS "," WS parameter | parameter ; @@ -91,7 +92,7 @@ number = integer | floating_literal ; access_operation = unarad "." identifier | unarad "->" identifier ; assignment_statement = factor WS "=" WS boolean_expression | factor WS "\+=" WS boolean_expression | factor WS "-=" WS boolean_expression | factor WS "\*=" WS boolean_expression | factor WS "/=" WS boolean_expression ; -declaration_statement = type WS identifier WS "=" WS boolean_expression | type WS identifier | type WS identifier WS "." WS identifier WS "\(" WS opt_parameter_list WS "\)" ; +declaration_statement = dec_type WS identifier WS "=" WS boolean_expression | dec_type WS identifier | dec_type WS identifier WS "." WS identifier WS "\(" WS opt_parameter_list WS "\)" ; alphanumeric = alphanumeric numeric | alphanumeric alpha | numeric | alpha ; hexadecimal = "0x(1|2|3|4|5|6|7|8|9|a|b|c|d|e|f)+" ; diff --git a/src/Importer.cpp b/src/Importer.cpp index b5758f6..7d6ac37 100644 --- a/src/Importer.cpp +++ b/src/Importer.cpp @@ -24,6 +24,7 @@ Importer::Importer(Parser* parserIn, std::vector includePaths) { removeSymbols.push_back(Symbol("comp_simple_passthrough", true)); removeSymbols.push_back(Symbol("typedef", true)); removeSymbols.push_back(Symbol("template", true)); + removeSymbols.push_back(Symbol("\\|", true)); collapseSymbols.push_back(Symbol("opt_typed_parameter_list", false)); collapseSymbols.push_back(Symbol("opt_parameter_list", false)); @@ -38,6 +39,7 @@ Importer::Importer(Parser* parserIn, std::vector includePaths) { collapseSymbols.push_back(Symbol("type_list", false)); collapseSymbols.push_back(Symbol("template_param_list", false)); collapseSymbols.push_back(Symbol("trait_list", false)); + collapseSymbols.push_back(Symbol("dec_type", false)); } Importer::~Importer() { diff --git a/stdlib/io.krak b/stdlib/io.krak index 60b9118..552ec4d 100644 --- a/stdlib/io.krak +++ b/stdlib/io.krak @@ -2,11 +2,11 @@ __if_comp__ __C__ __simple_passthrough__ """ #include """ -void println() { +|void| println() { print("\n"); } -void print(char* toPrint) { +|void| print(|char*| toPrint) { __if_comp__ __C__ { __simple_passthrough__ """ printf(toPrint); @@ -15,12 +15,12 @@ void print(char* toPrint) { return; } -void println(char* toPrint) { +|void| println(|char*| toPrint) { print(toPrint); println(); } -void print(int toPrint) { +|void| print(|int| toPrint) { __if_comp__ __C__ { __simple_passthrough__ """ printf("%d", toPrint); @@ -29,12 +29,12 @@ void print(int toPrint) { return; } -void println(int toPrint) { +|void| println(|int| toPrint) { print(toPrint); println(); } -void print(float toPrint) { +|void| print(|float| toPrint) { __if_comp__ __C__ { __simple_passthrough__ """ printf("%f", toPrint); @@ -43,7 +43,7 @@ void print(float toPrint) { return; } -void print(double toPrint) { +|void| print(|double| toPrint) { __if_comp__ __C__ { __simple_passthrough__ """ printf("%f", toPrint); @@ -52,7 +52,7 @@ void print(double toPrint) { return; } -void println(float toPrint) { +|void| println(|float| toPrint) { print(toPrint); println(); } diff --git a/stdlib/math.krak b/stdlib/math.krak index 5b245ab..0652e47 100644 --- a/stdlib/math.krak +++ b/stdlib/math.krak @@ -1,9 +1,9 @@ -int NotPi = 3; -float Pi = 3.141592654; +|int| NotPi = 3; +|float| Pi = 3.141592654; -int fibanacci(int num) { +|int| fibanacci(|int| num) { if (num < 2) return 1; return fibanacci(num-1) + fibanacci(num-2); -} \ No newline at end of file +} diff --git a/stdlib/mem.krak b/stdlib/mem.krak index b011463..406592a 100644 --- a/stdlib/mem.krak +++ b/stdlib/mem.krak @@ -4,8 +4,8 @@ __if_comp__ __C__ __simple_passthrough__ """ /* we have a template versions so we don't have to cast (because we don't have that yet) */ -template T* malloc(int size) { - T* memPtr = 0; +template |T*| malloc(|int| size) { + |T*| memPtr = 0; __if_comp__ __C__ { __simple_passthrough__ """ memPtr = malloc(size); @@ -14,7 +14,7 @@ template T* malloc(int size) { return memPtr; } -template void free(T* memPtr) { +template |void| free(|T*| memPtr) { __if_comp__ __C__ { __simple_passthrough__ """ free(memPtr); @@ -22,9 +22,9 @@ template void free(T* memPtr) { } } -template int sizeof() { - int result = 0; - T testObj; +template |int| sizeof() { + |int| result = 0; + |T| testObj; __if_comp__ __C__ { __simple_passthrough__ """ result = sizeof(testObj); @@ -33,32 +33,32 @@ template int sizeof() { return result; } -template T* new(int count) { +template |T*| new(|int| count) { return malloc( sizeof() * count ); } -template T* new() { +template |T*| new() { return new(1); } /* We specilize on the trait Destructable to decide on whether or not the destructor should be called */ -template void delete(T* toDelete, int itemCount) { +template |void| delete(|T*| toDelete, |int| itemCount) { delete(toDelete); } /* Calling this with itemCount = 0 allows you to delete destructable objects without calling their destructors. */ -template void delete(T* toDelete, int itemCount) { - for (int i = 0; i < itemCount; i++;) +template |void| delete(|T*| toDelete, |int| itemCount) { + for (|int| i = 0; i < itemCount; i++;) toDelete[i].destruct(); delete(toDelete); } /* We specilize on the trait Destructable to decide on whether or not the destructor should be called */ -template void delete(T* toDelete) { +template |void| delete(|T*| toDelete) { free(toDelete); } -template void delete(T* toDelete) { +template |void| delete(|T*| toDelete) { toDelete->destruct(); free(toDelete); } diff --git a/stdlib/trivial_container.krak b/stdlib/trivial_container.krak index 341c4d2..80bebeb 100644 --- a/stdlib/trivial_container.krak +++ b/stdlib/trivial_container.krak @@ -1,8 +1,8 @@ import io; typedef template trivialContainer { - T data; - void print() { + |T| data; + |void| print() { print(data); } }; diff --git a/stdlib/util.krak b/stdlib/util.krak index 02416d6..70e605c 100644 --- a/stdlib/util.krak +++ b/stdlib/util.krak @@ -1,11 +1,11 @@ -template T greater(T a, T b) { +template |T| greater(|T| a, |T| b) { if (a > b) return a; return b; } -template T lesser(T a, T b) { +template |T| lesser(|T| a, |T| b) { if (a > b) return b; return a; diff --git a/stdlib/vector.krak b/stdlib/vector.krak index ab320c2..0cf12df 100644 --- a/stdlib/vector.krak +++ b/stdlib/vector.krak @@ -3,36 +3,36 @@ import util; import io; typedef template vector (Destructable) { - T *data; - int size; - int available; + |T*| data; + |int| size; + |int| available; - vector* construct() { + |vector*| construct() { size = 0; available = 8; data = new(8); return this; } - void destruct() { + |void| destruct() { delete(data); } - bool resize(int newSize) { - T* newData = new(newSize); + |bool| resize(|int| newSize) { + |T*| newData = new(newSize); if (!newData) return false; - for (int i = 0; i < lesser(size, newSize); i++;) + for (|int| i = 0; i < lesser(size, newSize); i++;) newData[i] = data[i]; delete(data, 0); return true; } - T at(int index) { + |T| at(|int| index) { return get(index); } - T get(int index) { + |T| get(|int| index) { if (index < 0 || index >= size) { println("Vector access out of bounds! Retuning 0th element as sanest option"); return data[0]; @@ -40,12 +40,12 @@ typedef template vector (Destructable) { return data[index]; } - void set(int index, T dataIn) { + |void| set(|int| index, |T| dataIn) { if (index < 0 || index >= size) return; data[index] = dataIn; } - void addEnd(T dataIn) { + |void| addEnd(|T| dataIn) { if (size < available) size++; else diff --git a/tests/OperatorOverloadTest.krak b/tests/OperatorOverloadTest.krak index 2362187..bcc1d78 100644 --- a/tests/OperatorOverloadTest.krak +++ b/tests/OperatorOverloadTest.krak @@ -1,64 +1,64 @@ import io; typedef Vec2 { - int x; - int y; + |int| x; + |int| y; - void print() { + |void| print() { print(x); print(" "); print(y); } - Vec2 add(Vec2 other) { - Vec2 toReturn; + |Vec2| add(|Vec2| other) { + |Vec2| toReturn; toReturn.x = x + other.x; toReturn.y = y + other.y; print(); return toReturn; } - Vec2 subtract(Vec2 other) { - Vec2 toReturn; + |Vec2| subtract(|Vec2| other) { + |Vec2| toReturn; toReturn.x = x - other.x; toReturn.y = y - other.y; print(); return toReturn; } - Vec2 operator+(Vec2 other) { + |Vec2| operator+(|Vec2| other) { return add(other); } }; -Vec2 operator-(Vec2 lhs, Vec2 rhs) { +|Vec2| operator-(|Vec2| lhs, |Vec2| rhs) { return lhs.subtract(rhs); } -int main() { - Vec2 vector1; - Vec2 vector2; +|int| main() { + |Vec2| vector1; + |Vec2| vector2; vector1.x = 3; vector1.y = 9; vector2 = vector1; /* NOTE COMMENT - Vec2 vector3; + |Vec2| vector3; vector3.x = vector1.x + vector2.x; vector3.y = vector1.y + vector2.y; vector2.print(); */ - Vec2 addition = vector1 + vector2; + |Vec2| addition = vector1 + vector2; print("\n"); addition.print(); print("\nSubtraction\n"); vector2.x = 100; vector2.y = 70; - Vec2 subtraction = vector1 - vector2; + |Vec2| subtraction = vector1 - vector2; print("\n"); print(subtraction.x); print(" "); print(subtraction.y); print("\n"); - + return 0; } diff --git a/tests/RecursiveTest.krak b/tests/RecursiveTest.krak index 4e61ccc..03c8b9f 100644 --- a/tests/RecursiveTest.krak +++ b/tests/RecursiveTest.krak @@ -1,12 +1,12 @@ import io; -int fibanacci(int num) { +|int| fibanacci(|int| num) { if (num < 2) return 1; return fibanacci(num-1) + fibanacci(num-2); } -int main() { +|int| main() { print(fibanacci(4)); print("\n"); return 0; diff --git a/tests/commentFirstTest.krak b/tests/commentFirstTest.krak index 4464897..0cd8f27 100644 --- a/tests/commentFirstTest.krak +++ b/tests/commentFirstTest.krak @@ -1,7 +1,7 @@ /* Comment first! */ import io; -int main() { +|int| main() { println(1337); return 0; } diff --git a/tests/declarationsTest.krak b/tests/declarationsTest.krak index 9bfe547..4e29cc4 100644 --- a/tests/declarationsTest.krak +++ b/tests/declarationsTest.krak @@ -2,24 +2,24 @@ import io; import mem; typedef ClassWithConstructor { - int data; - ClassWithConstructor* construct(int inData) { + |int| data; + |ClassWithConstructor*| construct(|int| inData) { data = inData; return this; } - void printData() { + |void| printData() { println(data); } }; -int main() { - ClassWithConstructor object.construct(4); +|int| main() { + |ClassWithConstructor| object.construct(4); //ClassWithConstructor object; //object.construct(4); object.printData(); - int a = 8; + |int| a = 8; println(a); - ClassWithConstructor* objPtr = new()->construct(11); + |ClassWithConstructor*| objPtr = new()->construct(11); objPtr->printData(); delete(objPtr); return 0; diff --git a/tests/destructorTest.krak b/tests/destructorTest.krak index 21a2619..a63276f 100644 --- a/tests/destructorTest.krak +++ b/tests/destructorTest.krak @@ -1,27 +1,27 @@ import io; typedef DestructorPrint { - char* myStr; - DestructorPrint* construct(char* str) { + |char*| myStr; + |DestructorPrint*| construct(|char*| str) { myStr = str; return this; } - void destruct() { + |void| destruct() { println(myStr); } }; typedef NoDistruction { - int a; - void dummyFunc() {} + |int| a; + |void| dummyFunc() {} }; -void indirPrint() { - DestructorPrint testObj.construct("Hello Destructors!"); - NoDistruction dummy; +|void| indirPrint() { + |DestructorPrint| testObj.construct("Hello Destructors!"); + |NoDistruction| dummy; } -int main() { +|int| main() { indirPrint(); return 0; } diff --git a/tests/emptyBracesFunction.krak b/tests/emptyBracesFunction.krak index 0fbe029..d02cbd7 100644 --- a/tests/emptyBracesFunction.krak +++ b/tests/emptyBracesFunction.krak @@ -1,8 +1,8 @@ import io; -void nothing() {} +|void| nothing() {} -int main() { +|int| main() { nothing(); println("It was nothing"); return 0; diff --git a/tests/functionMultipleTemplateTest.krak b/tests/functionMultipleTemplateTest.krak index e6d11ce..a30f9d5 100644 --- a/tests/functionMultipleTemplateTest.krak +++ b/tests/functionMultipleTemplateTest.krak @@ -1,10 +1,10 @@ import io; -template void addAndPrint(T a, J b) { +template |void| addAndPrint(|T| a, |J| b) { print(a+b); } -int main() { +|int| main() { addAndPrint(10,12.14159); print("\n"); diff --git a/tests/functionOrderingTest.krak b/tests/functionOrderingTest.krak index 8075128..c26f5a9 100644 --- a/tests/functionOrderingTest.krak +++ b/tests/functionOrderingTest.krak @@ -1,17 +1,17 @@ import io; -int ret1() { +|int| ret1() { return ret2() / 2; } -int main() { +|int| main() { print(ret1()); print(ret2()); print("\n"); return 0; } -int ret2() { +|int| ret2() { return 2; } diff --git a/tests/functionTemplateTest.krak b/tests/functionTemplateTest.krak index 16fabea..e6b2597 100644 --- a/tests/functionTemplateTest.krak +++ b/tests/functionTemplateTest.krak @@ -1,12 +1,11 @@ import io; -template T addAndPrint(T a, T b) { +template |T| addAndPrint(|T| a, |T| b) { print(a+b); return a+b; } -int main() { - +|int| main() { addAndPrint(10,12); print("\n"); diff --git a/tests/memTest.krak b/tests/memTest.krak index 44acd40..6ddbac9 100644 --- a/tests/memTest.krak +++ b/tests/memTest.krak @@ -2,11 +2,11 @@ import mem; import io; typedef AnObject { - int a; - int b; - char* c; + |int| a; + |int| b; + |char*| c; - void print() { + |void| print() { print(a+b); print("\n"); print(c); @@ -15,8 +15,8 @@ typedef AnObject { }; -int main() { - AnObject* ptr = new(); +|int| main() { + |AnObject*| ptr = new(); ptr->a = 4; ptr->b = 7; ptr->c = "Hello decent memory! Quite a nice feeling\n"; @@ -24,4 +24,4 @@ int main() { delete(ptr); return 0; -} \ No newline at end of file +} diff --git a/tests/moreComplexObjectTest.krak b/tests/moreComplexObjectTest.krak index 8da7762..2c06e6b 100644 --- a/tests/moreComplexObjectTest.krak +++ b/tests/moreComplexObjectTest.krak @@ -1,25 +1,25 @@ import io; typedef firstObject { - int objectNum; - int other; - void print() { + |int| objectNum; + |int| other; + |void| print() { print(other); } - void printInd() { + |void| printInd() { print(); } }; typedef Int int; -Int aliasNum; +|Int| aliasNum; -int main() { - firstObject wooObject; +|int| main() { + |firstObject| wooObject; wooObject.objectNum = 7; print(wooObject.objectNum); - firstObject* objPtr = &wooObject; + |firstObject*| objPtr = &wooObject; objPtr->objectNum = 42; print(objPtr->objectNum); print("\n"); diff --git a/tests/moreObjectTemplateTest.krak b/tests/moreObjectTemplateTest.krak index 1a08428..6c7ae78 100644 --- a/tests/moreObjectTemplateTest.krak +++ b/tests/moreObjectTemplateTest.krak @@ -2,30 +2,30 @@ import io; import trivial_container; typedef RegularObject { - int num; - trivialContainer innerContainer; - void set(char* message, int number) { + |int| num; + |trivialContainer| innerContainer; + |void| set(|char*| message, |int| number) { innerContainer.data = message; num = number; } - char* get() { + |char*| get() { return innerContainer.data; } - void print() { + |void| print() { print(num); innerContainer.print(); } }; typedef MyIntContainer trivialContainer; -MyIntContainer roundabout; -RegularObject outsideDec; +|MyIntContainer| roundabout; +|RegularObject| outsideDec; -void print(trivialContainer toPrint) { +|void| print(|trivialContainer| toPrint) { print(toPrint.data); } -int main() { +|int| main() { roundabout.data = 4; outsideDec.set("Hello!", 5); roundabout.print(); diff --git a/tests/objectOrderingTest.krak b/tests/objectOrderingTest.krak index 80a96cb..4812bb8 100644 --- a/tests/objectOrderingTest.krak +++ b/tests/objectOrderingTest.krak @@ -1,24 +1,24 @@ import io; typedef objectA { - int a; + |int| a; }; typedef BigObject { - objectA a; - objectB b; - int add() { + |objectA| a; + |objectB| b; + |int| add() { return a.a + b.b; } }; typedef objectB { - int b; + |int| b; }; -int main() { - BigObject c; +|int| main() { + |BigObject| c; c.a.a = 4; c.b.b = 8; print(c.add()); diff --git a/tests/simpleFunctionTest.krak b/tests/simpleFunctionTest.krak index c78e629..2e45927 100644 --- a/tests/simpleFunctionTest.krak +++ b/tests/simpleFunctionTest.krak @@ -1,14 +1,14 @@ import io; -int addAndPrintInt(int a, int b) { +|int| addAndPrintInt(|int| a, |int| b) { print(a+b); return a+b; } -int main() { +|int| main() { print(addAndPrintInt(7,12)); print("\n"); return 0; -} \ No newline at end of file +} diff --git a/tests/simpleObjectMultipleTemplateTest.krak b/tests/simpleObjectMultipleTemplateTest.krak index cb8b831..f3615e4 100644 --- a/tests/simpleObjectMultipleTemplateTest.krak +++ b/tests/simpleObjectMultipleTemplateTest.krak @@ -2,9 +2,9 @@ import io; typedef template TemplateTest { - T a; - J b; - void print() { + |T| a; + |J| b; + |void| print() { print("a: "); print(a); print("\n"); @@ -14,10 +14,10 @@ typedef template TemplateTest { } }; -int main() { +|int| main() { - TemplateTest test; - TemplateTest test2; + |TemplateTest| test; + |TemplateTest| test2; test.a = 24; test.b = "Hello World"; test2.a = "Pi incoming"; diff --git a/tests/simpleObjectTemplateTest.krak b/tests/simpleObjectTemplateTest.krak index 9f16211..7aeebc2 100644 --- a/tests/simpleObjectTemplateTest.krak +++ b/tests/simpleObjectTemplateTest.krak @@ -2,9 +2,9 @@ import io; typedef template TemplateTest { - int a; - T b; - void print() { + |int| a; + |T| b; + |void| print() { print("a: "); print(a); print("\n"); @@ -14,10 +14,10 @@ typedef template TemplateTest { } }; -int main() { +|int| main() { - TemplateTest test; - TemplateTest test2; + |TemplateTest| test; + |TemplateTest| test2; test.a = 5; test.b = 7; test2.a = 9; diff --git a/tests/simpleObjectTest.krak b/tests/simpleObjectTest.krak index 9a96ac5..3e8f14f 100644 --- a/tests/simpleObjectTest.krak +++ b/tests/simpleObjectTest.krak @@ -2,15 +2,15 @@ import io; typedef FirstObject { - int objectNum; - void PrintSelf(int a) { + |int| objectNum; + |void| PrintSelf(|int| a) { print(objectNum); print(a); } }; -int main() { - FirstObject wooObject; +|int| main() { + |FirstObject| wooObject; wooObject.objectNum = 5; wooObject.PrintSelf(7); print("\n"); diff --git a/tests/templateTest.krak b/tests/templateTest.krak index a755ce2..8843126 100644 --- a/tests/templateTest.krak +++ b/tests/templateTest.krak @@ -2,10 +2,10 @@ import io; import trivial_container; typedef template TemplateTest { - int a; - T b; - trivialContainer c; - void print() { + |int| a; + |T| b; + |trivialContainer| c; + |void| print() { print("a: "); print(a); print("\n"); @@ -19,17 +19,17 @@ typedef template TemplateTest { typedef MyInt int; -MyInt c; +|MyInt| c; -template T addAndPrint(T a, T b) { +template |T| addAndPrint(|T| a, |T| b) { print(a+b); return a+b; } -int main() { - TemplateTest test; - TemplateTest test2; +|int| main() { + |TemplateTest| test; + |TemplateTest| test2; test.a = 5; test.b = 7; test.c.data = 1337; @@ -40,7 +40,7 @@ int main() { test.print(); test2.print(); - trivialContainer testImport; + |trivialContainer| testImport; testImport.data = "From another file! Whoh!"; testImport.print(); print("\n"); @@ -49,4 +49,4 @@ int main() { print("\n"); return 0; -} \ No newline at end of file +} diff --git a/tests/testArrayNotation.krak b/tests/testArrayNotation.krak index 9d4a0d9..9b04b25 100644 --- a/tests/testArrayNotation.krak +++ b/tests/testArrayNotation.krak @@ -1,9 +1,9 @@ import io; import mem; -int main() { - int b; - int* a = &b; +|int| main() { + |int| b; + |int*| a = &b; a [ 0 ] = 7; print(a [ 0 ] ); print(*a); diff --git a/tests/traitsTest.krak b/tests/traitsTest.krak index 70e1ce9..566e5ed 100644 --- a/tests/traitsTest.krak +++ b/tests/traitsTest.krak @@ -7,23 +7,23 @@ typedef Trait2 (SecondTrait) {}; typedef TwoTrait (FirstTrait, SecondTrait) {}; typedef AlreadySpecilized (FirstTrait, SecondTrait) {}; -template void OneTwoFunc(T obj) { +template |void| OneTwoFunc(|T| obj) { println("No Traits"); } -template void OneTwoFunc(T obj) { +template |void| OneTwoFunc(|T| obj) { println("First Trait"); } -template void OneTwoFunc(T obj) { +template |void| OneTwoFunc(|T| obj) { println("Second Trait"); } -template void OneTwoFunc(T obj) { +template |void| OneTwoFunc(|T| obj) { println("Both Traits"); } /* -template void OneTwoFunc(AlreadySpecilized obj) { +template |void| OneTwoFunc(|AlreadySpecilized| obj) { println("Already Specilized"); } */ @@ -42,12 +42,12 @@ typedef template OneTwoObj {}; *}; */ -int main() { - NoTraits a; - Trait1 b; - Trait2 c; - TwoTrait d; - AlreadySpecilized e; +|int| main() { + |NoTraits| a; + |Trait1| b; + |Trait2| c; + |TwoTrait| d; + |AlreadySpecilized| e; OneTwoFunc(a); OneTwoFunc(b); @@ -57,11 +57,11 @@ int main() { println(); - OneTwoObj alpha; - OneTwoObj beta; - OneTwoObj gamma; - OneTwoObj delta; -// OneTwoObj epsilon; + |OneTwoObj| alpha; + |OneTwoObj| beta; + |OneTwoObj| gamma; + |OneTwoObj| delta; +// |OneTwoObj| epsilon; OneTwoFunc>(alpha); OneTwoFunc>(beta); diff --git a/tests/typeExpr.expected_results b/tests/typeExpr.expected_results new file mode 100644 index 0000000..de78180 --- /dev/null +++ b/tests/typeExpr.expected_results @@ -0,0 +1,2 @@ +4 +8 diff --git a/tests/typeExpr.krak b/tests/typeExpr.krak new file mode 100644 index 0000000..e7dcae2 --- /dev/null +++ b/tests/typeExpr.krak @@ -0,0 +1,20 @@ +import io; + +typedef ClassWithConstructor { + |int| data; + |ClassWithConstructor*| construct(|int| inData) { + data = inData; + return this; + } + |void| printData() { + println(data); + } +}; + +|int| main() { + |ClassWithConstructor| object.construct(4); + object.printData(); + |int| a = 8; + println(a); + return 0; +} diff --git a/tests/vectorTest.krak b/tests/vectorTest.krak index 4ee170a..579fe24 100644 --- a/tests/vectorTest.krak +++ b/tests/vectorTest.krak @@ -3,24 +3,24 @@ import mem; import vector; typedef AbleToBeDestroyed (Destructable) { - void destruct() { + |void| destruct() { println("Destroyed!"); } }; -int main() { - vector intVec.construct(); +|int| main() { + |vector| intVec.construct(); intVec.addEnd(1); intVec.addEnd(3); intVec.addEnd(3); intVec.addEnd(7); - for (int i = 0; i < intVec.size; i++;) + for (|int| i = 0; i < intVec.size; i++;) print(intVec.at(i)); println(); - vector* desVec = new>()->construct(); - AbleToBeDestroyed testDestruct; + |vector*| desVec = new>()->construct(); + |AbleToBeDestroyed| testDestruct; desVec->addEnd(testDestruct); delete>(desVec); From 9badee1d0bcdb2411f70d0193fd1b0ab0ad1a8fc Mon Sep 17 00:00:00 2001 From: Nathan Braswell Date: Fri, 1 Aug 2014 18:32:23 -0700 Subject: [PATCH 36/37] Create LICENCE.md --- LICENCE.md | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 LICENCE.md diff --git a/LICENCE.md b/LICENCE.md new file mode 100644 index 0000000..da3550f --- /dev/null +++ b/LICENCE.md @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) {{{2014}}} {{{Nathan Christopher Braswell}}} + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. From 07c2aeed6475a268aeff5f63ae406b6bc954af43 Mon Sep 17 00:00:00 2001 From: Nathan Braswell Date: Fri, 1 Aug 2014 18:32:50 -0700 Subject: [PATCH 37/37] Update LICENCE.md --- LICENCE.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/LICENCE.md b/LICENCE.md index da3550f..4717d3f 100644 --- a/LICENCE.md +++ b/LICENCE.md @@ -1,6 +1,6 @@ The MIT License (MIT) -Copyright (c) {{{2014}}} {{{Nathan Christopher Braswell}}} +Copyright (c) 2014 Nathan Christopher Braswell Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal