diff --git a/.gitignore b/.gitignore index 86a6f61..8cf53c5 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ _site build +build-ninja *.comp stats *.swp diff --git a/include/ASTTransformation.h b/include/ASTTransformation.h index e063b83..69686c8 100644 --- a/include/ASTTransformation.h +++ b/include/ASTTransformation.h @@ -49,6 +49,7 @@ class ASTTransformation: public NodeTransformation { std::vector*> scopeLookup(NodeTree* scope, std::string lookup, bool includeModules = false); std::vector*> scopeLookup(NodeTree* scope, std::string lookup, bool includeModules, std::vector*> visited); + NodeTree* getUpperTranslationUnit(NodeTree* node); 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); diff --git a/include/CGenerator.h b/include/CGenerator.h index 13103e4..1dfb99f 100644 --- a/include/CGenerator.h +++ b/include/CGenerator.h @@ -24,9 +24,9 @@ class CGenerator { std::string generateClassStruct(NodeTree* from); bool isUnderTranslationUnit(NodeTree* from, NodeTree* typeDefinition); NodeTree* highestScope(NodeTree* node); - std::pair generateTranslationUnit(NodeTree* from); + std::pair generateTranslationUnit(std::string name, std::map*> ASTs); std::string generate(NodeTree* from, NodeTree* enclosingObject = NULL); - std::string generateAliasChains(NodeTree* scopeNode, NodeTree* definition); + std::string generateAliasChains(std::map*> ASTs, NodeTree* definition); static std::string ValueTypeToCType(Type *type); static std::string ValueTypeToCTypeDecoration(Type *type); static std::string ValueTypeToCTypeThingHelper(Type *type, std::string ptrStr); diff --git a/src/ASTTransformation.cpp b/src/ASTTransformation.cpp index 20117d5..1c65953 100644 --- a/src/ASTTransformation.cpp +++ b/src/ASTTransformation.cpp @@ -1112,6 +1112,18 @@ std::vector*> ASTTransformation::scopeLookup(NodeTree return matches; } +// Find the translation unit that is the top of the passed in node +NodeTree* ASTTransformation::getUpperTranslationUnit(NodeTree* node) { + auto scope = node->getDataRef()->scope; + auto iter = scope.find("~enclosing_scope"); + while(iter != scope.end()) { + node = iter->second[0]; + scope = node->getDataRef()->scope; + iter = scope.find("~enclosing_scope"); + } + return node; +} + //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 = concatSymbolTree(typeNode); @@ -1180,16 +1192,16 @@ Type* ASTTransformation::typeFromTypeNode(NodeTree* typeNode, NodeTreegetChildren()[0]); - std::string fullyInstantiatedName = classNameWithoutTemplate + "<" + instTypeString + ">"; + std::string templateLookupName = classNameWithoutTemplate + "<" + instTypeString + ">"; // Recheck for prior definition here, now that we have the true name. - possibleMatches = scopeLookup(scope, fullyInstantiatedName); + possibleMatches = scopeLookup(scope, templateLookupName); if (possibleMatches.size()) { typeDefinition = possibleMatches[0]; traits = typeDefinition->getDataRef()->valueType->traits; - std::cout << "Found already instantiated template of " << fullyInstantiatedName << " at second check" << std::endl; + std::cout << "Found already instantiated template of " << templateLookupName << " at second check" << std::endl; } else { - std::cout << "Did not find already instantiated template of " << fullyInstantiatedName << " at second check" << std::endl; + std::cout << "Did not find already instantiated template of " << templateLookupName << " 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) @@ -1197,6 +1209,8 @@ Type* ASTTransformation::typeFromTypeNode(NodeTree* typeNode, NodeTreegetDataRef()->symbol.getName() + "<" + instTypeString + ">"; + 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 @@ -1211,9 +1225,17 @@ Type* ASTTransformation::typeFromTypeNode(NodeTree* typeNode, NodeTreegetDataRef()->scope[fullyInstantiatedName].push_back(typeDefinition); - topScope->addChild(typeDefinition); //Add this object the the highest scope's + //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 + + // Actually, let's just put it in the scope of the origional template, which should work just fine under the new scoping rules and will ACTUALLY prevent multiple instantiation. + // At least, hopefully it will if we also check it's scope for it. Which I think it should be anyway. Yeah, I think it should work. + std::cout << "Adding to template top scope and template's origional scope with fullyInstantiatedName " << fullyInstantiatedName << std::endl; + auto templateTopScope = getUpperTranslationUnit(templateDefinition); + templateTopScope->getDataRef()->scope[fullyInstantiatedName].push_back(typeDefinition); + templateTopScope->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); @@ -1304,8 +1326,13 @@ NodeTree* ASTTransformation::findOrInstantiateFunctionTemplate(std::vec 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 - topScope->getDataRef()->scope[fullyInstantiatedName].push_back(instantiatedFunction); - topScope->addChild(instantiatedFunction); //Add this object the the highest scope's + // Arrrrrgh this has a hard time working because the functions will need to see their parameter once they are emitted as C. + // HAHAHAHAHA DOESN'T MATTER ALL ONE C FILE NOW, swap back to old way + auto templateTopScope = getUpperTranslationUnit(templateDefinition); + templateTopScope->getDataRef()->scope[fullyInstantiatedName].push_back(instantiatedFunction); + templateTopScope->addChild(instantiatedFunction); // Add this object the the highest scope's + //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)); diff --git a/src/CGenerator.cpp b/src/CGenerator.cpp index b2969bc..881cf21 100644 --- a/src/CGenerator.cpp +++ b/src/CGenerator.cpp @@ -4,7 +4,6 @@ CGenerator::CGenerator() : generatorString("__C__") { tabLevel = 0; } CGenerator::~CGenerator() { - } // Note the use of std::pair to hold two strings - the running string for the header file and the running string for the c file. @@ -16,23 +15,23 @@ void CGenerator::generateCompSet(std::map*> ASTs, std::cout << "Could not make directory " << outputName << std::endl; //throw "could not make directory "; } - for (auto i = ASTs.begin(); i != ASTs.end(); i++) { - std::cout << "\n\nGenerate pass for: " << i->first << std::endl; - buildString += i->first + ".c "; - std::ofstream outputCFile, outputHFile; - outputCFile.open(outputName + "/" + i->first + ".c"); - outputHFile.open(outputName + "/" + i->first + ".h"); - if (outputCFile.is_open() || outputHFile.is_open()) { - // Prequel common to all files - auto chPair = generateTranslationUnit(i->second); - outputHFile << "#include \n#include \n#include \n" << chPair.first; - outputCFile << "#include \"" + i->first + ".h\"\n\n" << chPair.second; - } else { - std::cout << "Cannot open file " << i->first << ".c/h" << std::endl; - } - outputCFile.close(); - outputHFile.close(); - } + + std::cout << "\n\nGenerate pass for: " << outputName << std::endl; + buildString += outputName + ".c "; + std::ofstream outputCFile, outputHFile; + outputCFile.open(outputName + "/" + outputName + ".c"); + outputHFile.open(outputName + "/" + outputName + ".h"); + if (outputCFile.is_open() || outputHFile.is_open()) { + // Prequel common to all files + auto chPair = generateTranslationUnit(outputName, ASTs); + outputHFile << "#include \n#include \n#include \n" << chPair.first; + outputCFile << "#include \"" + outputName + ".h\"\n\n" << chPair.second; + } else { + std::cout << "Cannot open file " << outputName << ".c/h" << std::endl; + } + outputCFile.close(); + outputHFile.close(); + buildString += "-o " + outputName; std::ofstream outputBuild; outputBuild.open(outputName + "/" + split(outputName, '/').back() + ".sh"); @@ -63,18 +62,19 @@ std::string CGenerator::generateClassStruct(NodeTree* from) { } // This method recurseivly generates all aliases of some definition -std::string CGenerator::generateAliasChains(NodeTree* scopeNode, NodeTree* definition) { - auto scope = scopeNode->getDataRef()->scope; +std::string CGenerator::generateAliasChains(std::map*> ASTs, NodeTree* definition) { 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); + for (auto trans : ASTs) { + for (auto i = trans.second->getDataRef()->scope.begin(); i != trans.second->getDataRef()->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(ASTs, declaration); + } } } } @@ -104,9 +104,8 @@ NodeTree* CGenerator::highestScope(NodeTree* node) { } // We do translation units in their own function so they can do the pariwise h/c stuff and regualr in function body generation does not -std::pair CGenerator::generateTranslationUnit(NodeTree* from) { - ASTData data = from->getData(); - std::vector*> children = from->getChildren(); +std::pair CGenerator::generateTranslationUnit(std::string name, std::map*> ASTs) { + // We now pass in the entire map of ASTs and loop through them so that we generate out into a single file std::string cOutput, hOutput; // Ok, so we've got to do this in passes to preserve mututally recursive definitions. // @@ -129,30 +128,29 @@ std::pair CGenerator::generateTranslationUnit(NodeTree std::string functionPrototypes = "/**\n * Function Prototypes\n */\n\n"; std::string functionDefinitions = "/**\n * Function Definitions\n */\n\n"; - // Ok, let's handle the included files - for (auto i : from->getChildren()) - if (i->getDataRef()->type == import) - importIncludes += "#include \"" + i->getDataRef()->symbol.getName() + ".krak.h\" //woo importing!\n"; // And get the correct order for emiting classes, but not if they're not in our file, then they will get included // Note that this is not sufsticated enough for some multiple file mutually recursive types, but I want to get this simple version working first Poset*> typedefPoset; - for (int i = 0; i < children.size(); i++) { - if (children[i]->getDataRef()->type == type_def) { - // If we're an alias type, continue. We handle those differently - if (children[i]->getDataRef()->valueType->typeDefinition != children[i]) - continue; + for (auto trans : ASTs) { + auto children = trans.second->getChildren(); + for (int i = 0; i < children.size(); i++) { + if (children[i]->getDataRef()->type == type_def) { + // 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 && isUnderTranslationUnit(from, decType->typeDefinition)) // If this is a custom type and not a pointer and actually should be defined in this file - typedefPoset.addRelationship(children[i], decType->typeDefinition); // Add a dependency + 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 + } } } } @@ -161,76 +159,74 @@ std::pair CGenerator::generateTranslationUnit(NodeTree for (NodeTree* i : typedefPoset.getTopoSort()) classStructs += generateClassStruct(i) + "\n"; - // Declare everything in translation unit scope here. (allows stuff from other files, automatic forward declarations) + // Declare everything in translation unit scope here (now for ALL translation units). (allows stuff from other files, automatic forward declarations) // Also, everything in all of the import's scopes - std::map*>> combinedMap; - combinedMap = from->getDataRef()->scope; // Actually, just do this file. We're moving back to using include files - for (auto i = combinedMap.begin(); i != combinedMap.end(); i++) { - for (auto declaration : i->second) { - std::vector*> decChildren = declaration->getChildren(); - ASTData declarationData = declaration->getData(); - switch(declarationData.type) { - case identifier: - variableDeclarations += ValueTypeToCType(declarationData.valueType) + " " + declarationData.symbol.getName() + "; /*identifier*/\n"; - variableExternDeclarations += "extern " + ValueTypeToCType(declarationData.valueType) + " " + declarationData.symbol.getName() + "; /*extern identifier*/\n"; - break; - case function: - { - if (declarationData.valueType->baseType == template_type) - functionPrototypes += "/* template function " + declarationData.symbol.toString() + " */\n"; - else if (decChildren.size() == 0) //Not a real function, must be a built in passthrough - functionPrototypes += "/* built in function: " + declarationData.symbol.toString() + " */\n"; - else { - functionPrototypes += "\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], nullptr); - nameDecoration += "_" + ValueTypeToCTypeDecoration(decChildren[j]->getData().valueType); - } - 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)) + for (auto trans : ASTs) { + for (auto i = trans.second->getDataRef()->scope.begin(); i != trans.second->getDataRef()->scope.end(); i++) { + for (auto declaration : i->second) { + std::vector*> decChildren = declaration->getChildren(); + ASTData declarationData = declaration->getData(); + switch(declarationData.type) { + case identifier: + variableDeclarations += ValueTypeToCType(declarationData.valueType) + " " + declarationData.symbol.getName() + "; /*identifier*/\n"; + variableExternDeclarations += "extern " + ValueTypeToCType(declarationData.valueType) + " " + declarationData.symbol.getName() + "; /*extern identifier*/\n"; + break; + case function: + { + if (declarationData.valueType->baseType == template_type) + functionPrototypes += "/* template function " + declarationData.symbol.toString() + " */\n"; + else if (decChildren.size() == 0) //Not a real function, must be a built in passthrough + functionPrototypes += "/* built in function: " + declarationData.symbol.toString() + " */\n"; + else { + functionPrototypes += "\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], nullptr); + nameDecoration += "_" + ValueTypeToCTypeDecoration(decChildren[j]->getData().valueType); + } + functionPrototypes += CifyName(declarationData.symbol.getName() + nameDecoration) + "(" + parameters + "); /*func*/\n"; + // generate function + std::cout << "Generating " << CifyName(declarationData.symbol.getName()) << std::endl; functionDefinitions += generate(declaration, nullptr); + } } - } - break; - case type_def: - //type - plainTypedefs += "/*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)) + 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(ASTs, 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(ASTs, declaration); + functionPrototypes += "/* Done with " + declarationData.symbol.getName() + " */\n"; + // include methods 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; - cOutput += "/*unknown declaration named " + declaration->getName() + "*/\n"; - hOutput += "/*unknown declaration named " + declaration->getName() + "*/\n"; + } + break; + default: + //std::cout << "Declaration? named " << declaration->getName() << " of unknown type " << ASTData::ASTTypeToString(declarationData.type) << " in translation unit scope" << std::endl; + cOutput += "/*unknown declaration named " + declaration->getName() + "*/\n"; + hOutput += "/*unknown declaration named " + declaration->getName() + "*/\n"; + } } } } @@ -262,11 +258,12 @@ std::string CGenerator::generate(NodeTree* from, NodeTree* enc case identifier: { //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 (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()) @@ -480,6 +477,7 @@ std::string CGenerator::generateObjectMethod(NodeTree* enclosingObject, 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) { return ValueTypeToCTypeThingHelper(type, "*"); } std::string CGenerator::ValueTypeToCTypeDecoration(Type *type) { return ValueTypeToCTypeThingHelper(type, "_P__"); } std::string CGenerator::ValueTypeToCTypeThingHelper(Type *type, std::string ptrStr) { @@ -557,6 +555,7 @@ std::string CGenerator::CifyName(std::string name) { "[", "openbracket", "]", "closebracket", " ", "space", + ".", "dot", "->", "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 36b84d2..309142a 100644 --- a/src/Importer.cpp +++ b/src/Importer.cpp @@ -167,6 +167,7 @@ NodeTree* Importer::parseAndTrim(std::string fileName) { } else { std::cout << "ParseTree returned from parser for " << fileName << " is NULL!" << std::endl; outFile.close(); outFileTransformed.close(); + throw "unexceptablblllll"; return NULL; } outFile.close(); diff --git a/stdlib/io.krak b/stdlib/io.krak index 552ec4d..3182d81 100644 --- a/stdlib/io.krak +++ b/stdlib/io.krak @@ -1,3 +1,5 @@ +import string:*; + __if_comp__ __C__ __simple_passthrough__ """ #include """ @@ -20,6 +22,14 @@ __if_comp__ __C__ __simple_passthrough__ """ println(); } +|void| print(|string| toPrint) { + print(toPrint.toCharArray()); +} + +|void| println(|string| toPrint) { + println(toPrint.toCharArray()); +} + |void| print(|int| toPrint) { __if_comp__ __C__ { __simple_passthrough__ """ diff --git a/stdlib/string.krak b/stdlib/string.krak new file mode 100644 index 0000000..50432e3 --- /dev/null +++ b/stdlib/string.krak @@ -0,0 +1,27 @@ +import vector; +import mem; + +typedef string (Destructable) { + |vector::vector| data; + |string*| construct() { + data.construct(); + return this; + } + |string*| construct(|char*| str) { + data.construct(); + while(*str) { + data.addEnd(*str); + str += 1; + } + return this; + } + + |char*| toCharArray() { + |char*| out = mem::new(data.size); + for (|int| i = 0; i < data.size; i++;) + out[i] = data.get(i); + return out; + } +}; + + diff --git a/stdlib/vector.krak b/stdlib/vector.krak index d3e9dbc..61e55fc 100644 --- a/stdlib/vector.krak +++ b/stdlib/vector.krak @@ -1,6 +1,6 @@ import mem:*; import util:*; -import io:*; +//import io:*; typedef template vector (Destructable) { |T*| data; @@ -25,6 +25,8 @@ typedef template vector (Destructable) { for (|int| i = 0; i < lesser(size, newSize); i++;) newData[i] = data[i]; delete(data, 0); + data = newData; + available = newSize; return true; } @@ -34,21 +36,22 @@ typedef template vector (Destructable) { |T| get(|int| index) { if (index < 0 || index >= size) { - println("Vector access out of bounds! Retuning 0th element as sanest option"); + // println("Vector access out of bounds! Retuning 0th element as sanest option"); return data[0]; } return data[index]; } + |T*| getBackingMemory() { return data; } + |void| set(|int| index, |T| dataIn) { if (index < 0 || index >= size) return; data[index] = dataIn; } |void| addEnd(|T| dataIn) { - if (size < available) - size++; - else + size++; + if (size >= available) resize(size*2); data[size-1] = dataIn; } diff --git a/tests/runTests-ninja.sh b/tests/runTests-ninja.sh new file mode 100644 index 0000000..1217420 --- /dev/null +++ b/tests/runTests-ninja.sh @@ -0,0 +1,15 @@ +#!/bin/bash + +krakenPath="../build-ninja/kraken" +#testDir=${1:-"../tests"} +testDir="." +ext=${2:-"krak"} + +fileList="" +for dir in `find ${testDir} -type f -name "test_*.${ext}"`; do + filename=$(basename ${dir}) + filename="${filename%.*}" + fileList+=\ $testDir\/$filename +done + +${krakenPath} "--test" ${fileList} diff --git a/tests/test_string.expected_results b/tests/test_string.expected_results new file mode 100644 index 0000000..abf1ab2 --- /dev/null +++ b/tests/test_string.expected_results @@ -0,0 +1 @@ +hello strings diff --git a/tests/test_string.krak b/tests/test_string.krak new file mode 100644 index 0000000..01b69db --- /dev/null +++ b/tests/test_string.krak @@ -0,0 +1,10 @@ +import io; +import string; + + +|int| main() { + |string::string| str.construct("hello strings"); + io::println(str); + return 0; +} + diff --git a/tests/test_vectorTest.expected_results b/tests/test_vectorTest.expected_results index c7ae395..e38777c 100644 --- a/tests/test_vectorTest.expected_results +++ b/tests/test_vectorTest.expected_results @@ -1,2 +1,3 @@ +4 1337 Destroyed! diff --git a/tests/test_vectorTest.krak b/tests/test_vectorTest.krak index c47e3de..3c25ee3 100644 --- a/tests/test_vectorTest.krak +++ b/tests/test_vectorTest.krak @@ -14,6 +14,7 @@ typedef AbleToBeDestroyed (Destructable) { intVec.addEnd(3); intVec.addEnd(3); intVec.addEnd(7); + println(intVec.size); for (|int| i = 0; i < intVec.size; i++;) print(intVec.at(i));