From 6f9ceaa717440ca5d9dd2474ec6dc011172523d4 Mon Sep 17 00:00:00 2001 From: Nathan Braswell Date: Mon, 1 Jun 2015 01:43:23 -0400 Subject: [PATCH] work on string, bug fixes, overloaded assignment operator. Still need to get overloaded copy_construct for declaration assignment --- include/ASTTransformation.h | 2 +- include/CCodeTriple.h | 2 +- src/ASTTransformation.cpp | 38 +++++++++++++++++------------- src/CCodeTriple.cpp | 4 ++-- src/CGenerator.cpp | 27 +++++++++++++++++---- stdlib/io.krak | 36 +++++++--------------------- stdlib/string.krak | 34 ++++++++++++++++++++++++-- stdlib/vector.krak | 25 +++++++++++++++++++- tests/test_string.expected_results | 3 +++ tests/test_string.krak | 8 +++++++ 10 files changed, 124 insertions(+), 55 deletions(-) diff --git a/include/ASTTransformation.h b/include/ASTTransformation.h index 3f1e763..484452a 100644 --- a/include/ASTTransformation.h +++ b/include/ASTTransformation.h @@ -50,7 +50,7 @@ class ASTTransformation: public NodeTransformation { NodeTree* functionLookup(NodeTree* scope, std::string lookup, std::vector types); NodeTree* templateFunctionLookup(NodeTree* scope, std::string lookup, std::vector* templateInstantiationTypes, std::vector types, std::map scopeTypeMap); std::vector*> scopeLookup(NodeTree* scope, std::string lookup, bool includeModules = false); - std::vector*> scopeLookup(NodeTree* scope, std::string lookup, bool includeModules, std::vector*> visited); + std::vector*> scopeLookup(NodeTree* scope, std::string lookup, bool includeModules, std::set*> visited); NodeTree* getUpperTranslationUnit(NodeTree* node); NodeTree* addToScope(std::string name, NodeTree* toAdd, NodeTree* addTo); diff --git a/include/CCodeTriple.h b/include/CCodeTriple.h index 95f46f1..81637e8 100644 --- a/include/CCodeTriple.h +++ b/include/CCodeTriple.h @@ -12,7 +12,7 @@ class CCodeTriple { CCodeTriple(const char* val); CCodeTriple(); ~CCodeTriple(); - std::string oneString(); + std::string oneString(bool endValue = false); CCodeTriple & operator=(const CCodeTriple &rhs); CCodeTriple & operator+=(const CCodeTriple &rhs); diff --git a/src/ASTTransformation.cpp b/src/ASTTransformation.cpp index 1a46072..3e8c9e3 100644 --- a/src/ASTTransformation.cpp +++ b/src/ASTTransformation.cpp @@ -29,6 +29,7 @@ ASTTransformation::ASTTransformation(Importer *importerIn) { languageLevelOperators["||"].push_back(addToScope("~enclosing_scope", builtin_trans_unit, new NodeTree("function", ASTData(function, Symbol("||", true), new Type(boolean))))); languageLevelOperators["!"].push_back(addToScope("~enclosing_scope", builtin_trans_unit, new NodeTree("function", ASTData(function, Symbol("!", true), new Type(boolean))))); languageLevelOperators["*="].push_back(addToScope("~enclosing_scope", builtin_trans_unit, new NodeTree("function", ASTData(function, Symbol("*=", true), NULL)))); + languageLevelOperators["="].push_back(addToScope("~enclosing_scope", builtin_trans_unit, new NodeTree("function", ASTData(function, Symbol("=", true), NULL)))); languageLevelOperators["+="].push_back(addToScope("~enclosing_scope", builtin_trans_unit, new NodeTree("function", ASTData(function, Symbol("+=", true), NULL)))); languageLevelOperators["-="].push_back(addToScope("~enclosing_scope", builtin_trans_unit, new NodeTree("function", ASTData(function, Symbol("-=", true), NULL)))); languageLevelOperators["."].push_back(addToScope("~enclosing_scope", builtin_trans_unit, new NodeTree("function", ASTData(function, Symbol(".", true), NULL)))); @@ -592,16 +593,21 @@ NodeTree* ASTTransformation::transform(NodeTree* from, NodeTree } else if (name == "defer_statement") { newNode = new NodeTree(name, ASTData(defer_statement)); } else if (name == "assignment_statement") { - newNode = new NodeTree(name, ASTData(assignment_statement)); std::string assignFuncName = concatSymbolTree(children[1]); + 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); + + // see if this is an overloaded assignment + NodeTree* function = doFunction(scope, assignFuncName, transformedChildren, templateTypeReplacements); + if (function) + return function; + + newNode = new NodeTree(name, ASTData(assignment_statement)); if (assignFuncName == "=") { - newNode->addChild(transform(children[0], scope, types, templateTypeReplacements)); - newNode->addChild(transform(children[2], scope, types, templateTypeReplacements)); + newNode->addChildren(transformedChildren); } 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); - 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) { @@ -1218,13 +1224,15 @@ std::map ASTTransformation::makeTemplateFunctionTypeMap(Node // We need recursion protection std::vector*> ASTTransformation::scopeLookup(NodeTree* scope, std::string lookup, bool includeModules) { - return scopeLookup(scope, lookup, includeModules, std::vector*>()); + return scopeLookup(scope, lookup, includeModules, std::set*>()); } -std::vector*> ASTTransformation::scopeLookup(NodeTree* scope, std::string lookup, bool includeModules, std::vector*> visited) { +std::vector*> ASTTransformation::scopeLookup(NodeTree* scope, std::string lookup, bool includeModules, std::set*> visited) { std::cout << "Scp]|[e looking up " << lookup << std::endl; // Don't visit this node again when looking for the smae lookup. Note that we don't prevent coming back for the scope operator, as that should be able to come back. - visited.push_back(scope); + if (visited.find(scope) != visited.end()) + return std::vector*>(); + visited.insert(scope); //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()) { @@ -1463,6 +1471,7 @@ NodeTree* ASTTransformation::findOrInstantiateFunctionTemplate(std::vec std::cout << "\n\nFinding or instantiating templated function\n\n" << std::endl; std::string functionName = concatSymbolTree(children[0]); std::string fullyInstantiatedName; + std::string scopelessFullyInstantiatedName; std::vector templateActualTypes; NodeTree* templateDefinition = NULL; @@ -1529,6 +1538,7 @@ NodeTree* ASTTransformation::findOrInstantiateFunctionTemplate(std::vec std::cout << functionName << " search turned up null, returing null" << std::endl; return NULL; } + scopelessFullyInstantiatedName = templateDefinition->getDataRef()->symbol.getName() + "<" + instTypeString + ">"; NodeTree* templateSyntaxTree = templateDefinition->getDataRef()->valueType->templateDefinition; // Makes a map between the names of the template placeholder parameters and the provided types @@ -1539,14 +1549,10 @@ 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[templateChildren.size()-2], scope, newTemplateTypeReplacement))); + instantiatedFunction = new NodeTree("function", ASTData(function, Symbol(scopelessFullyInstantiatedName, true), typeFromTypeNode(templateChildren[templateChildren.size()-2], scope, newTemplateTypeReplacement))); addToScope("~enclosing_scope", templateDefinition->getDataRef()->scope["~enclosing_scope"][0], instantiatedFunction); - // 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 - // OR, THIS IS A TEMPLATE METHOD AND ADD TO THE OBJECT - auto templateTopScope = objectForTemplateMethod ? objectForTemplateMethod : getUpperTranslationUnit(templateDefinition); - addToScope(fullyInstantiatedName, instantiatedFunction, templateTopScope); - templateTopScope->addChild(instantiatedFunction); // Add this object the the highest scope's + addToScope(scopelessFullyInstantiatedName, instantiatedFunction, templateDefinition->getDataRef()->scope["~enclosing_scope"][0]); + templateDefinition->getDataRef()->scope["~enclosing_scope"][0]->addChild(instantiatedFunction); // Add this object the the highest scope's std::cout << "About to do children of " << functionName << " to " << fullyInstantiatedName << std::endl; diff --git a/src/CCodeTriple.cpp b/src/CCodeTriple.cpp index 313d882..c73066e 100644 --- a/src/CCodeTriple.cpp +++ b/src/CCodeTriple.cpp @@ -19,8 +19,8 @@ CCodeTriple::CCodeTriple() { CCodeTriple::~CCodeTriple() { } -std::string CCodeTriple::oneString() { - return preValue + value + postValue; +std::string CCodeTriple::oneString(bool endValue) { + return preValue + value + (endValue ? ";" : "") + postValue; } CCodeTriple & CCodeTriple::operator=(const CCodeTriple &rhs) { diff --git a/src/CGenerator.cpp b/src/CGenerator.cpp index 7df5e94..a36f5dd 100644 --- a/src/CGenerator.cpp +++ b/src/CGenerator.cpp @@ -10,7 +10,7 @@ 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. void CGenerator::generateCompSet(std::map*> ASTs, std::string outputName) { //Generate an entire set of files - std::string buildString = "#!/bin/sh\ncc -std=c99 "; + std::string buildString = "#!/bin/sh\ncc -g -std=c99 "; std::cout << "\n\n =====GENERATE PASS===== \n\n" << std::endl; std::cout << "\n\nGenerate pass for: " << outputName << std::endl; buildString += outputName + ".c "; @@ -305,8 +305,13 @@ CCodeTriple CGenerator::generate(NodeTree* from, NodeTree* enc parameters += ValueTypeToCType(children[j]->getData().valueType, generate(children[j], enclosingObject, justFuncName).oneString()); nameDecoration += "_" + ValueTypeToCTypeDecoration(children[j]->getData().valueType); // add parameters to distructDoubleStack so that their destructors will be called at return (if they exist) + std::cout << "HAHA: " << generate(children[j], enclosingObject, justFuncName).oneString() << std::endl; distructDoubleStack.back().push_back(children[j]); } + if (children.size() == 1) + std::cout << "HEHE: " << data.symbol.getName() << " has only one child" << std::endl; + else if (children.size() == 0) + std::cout << "HEHE: " << data.symbol.getName() << " has only 0 child" << std::endl; // this is for using functions as values if (justFuncName) { output = ((data.symbol.getName() == "main") ? "" : scopePrefix(from)) + CifyName(data.symbol.getName() + nameDecoration); @@ -455,7 +460,6 @@ CCodeTriple CGenerator::generate(NodeTree* from, NodeTree* enc deferDoubleStack.back().push_back(children[0]); return CCodeTriple("/*defer " + generate(children[0], enclosingObject, justFuncName).oneString() + "*/"); case assignment_statement: - //if (methodExists(retType, "operator=")) { return generate(children[0], enclosingObject, justFuncName).oneString() + " = " + generate(children[1], enclosingObject, true); case declaration_statement: // adding declaration to the distructDoubleStack so that we can call their destructors when leaving scope (}, return, break, continue) @@ -469,7 +473,8 @@ CCodeTriple CGenerator::generate(NodeTree* from, NodeTree* enc && 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, justFuncName).oneString()) + "; " + generate(children[1], enclosingObject, true).oneString() + "/*Init Position Call*/"; + // be sure to end value by passing oneString true + return ValueTypeToCType(children[0]->getData().valueType, generate(children[0], enclosingObject, justFuncName).oneString()) + "; " + generate(children[1], enclosingObject, true).oneString(true) + "/*Init Position Call*/"; } else { // copy constructor if of the same type if (*children[0]->getDataRef()->valueType == *children[1]->getDataRef()->valueType && methodExists(children[1]->getDataRef()->valueType, "copy_construct")) { @@ -533,7 +538,7 @@ CCodeTriple CGenerator::generate(NodeTree* from, NodeTree* enc if (name == "[]") return "(" + generate(children[1], enclosingObject, true) + ")[" + generate(children[2],enclosingObject, true) + "]"; if (name == "+" || name == "-" || name == "*" || name == "/" || name == "==" || name == ">=" || name == "<=" || name == "!=" - || name == "<" || name == ">" || name == "%" || name == "+=" || name == "-=" || name == "*=" || name == "/=" || name == "||" + || name == "<" || name == ">" || name == "%" || name == "=" || name == "+=" || name == "-=" || name == "*=" || name == "/=" || name == "||" || name == "&&") { std::cout << "THIS IS IT NAME: " << name << std::endl; return "((" + generate(children[1], enclosingObject, true).oneString() + ")" + name + "(" + generate(children[2], enclosingObject, true).oneString() + "))"; @@ -643,6 +648,8 @@ NodeTree* CGenerator::getMethodsObjectType(NodeTree* scope, st // Returns the function prototype in the out param and the full definition normally std::string CGenerator::generateObjectMethod(NodeTree* enclosingObject, NodeTree* from, std::string *functionPrototype) { + distructDoubleStack.push_back(std::vector*>()); + 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(); @@ -651,12 +658,20 @@ std::string CGenerator::generateObjectMethod(NodeTree* enclosingObject, for (int i = 0; i < children.size()-1; i++) { parameters += ", " + ValueTypeToCType(children[i]->getData().valueType, generate(children[i]).oneString()); nameDecoration += "_" + ValueTypeToCTypeDecoration(children[i]->getData().valueType); + + distructDoubleStack.back().push_back(children[i]); } std::string functionSignature = "\n" + ValueTypeToCType(data.valueType->returnType, scopePrefix(from) + CifyName(enclosingObject->getDataRef()->symbol.getName()) +"__" + CifyName(data.symbol.getName()) + nameDecoration) + "(" + ValueTypeToCType(&enclosingObjectType, "this") + parameters + ")"; *functionPrototype += functionSignature + ";\n"; // Note that we always wrap out child in {}, as we now allow one statement functions without a codeblock - return functionSignature + " {\n" + generate(children[children.size()-1], enclosingObject).oneString() + "}\n"; //Pass in the object so we can properly handle access to member stuff + // + std::string output; + output += functionSignature + " {\n" + generate(children[children.size()-1], enclosingObject).oneString(); + output += emitDestructors(reverse(distructDoubleStack.back()), enclosingObject); + output += "}\n"; //Pass in the object so we can properly handle access to member stuff + distructDoubleStack.pop_back(); + return output; } NodeTree* CGenerator::getMethod(Type* type, std::string method) { @@ -683,6 +698,8 @@ std::string CGenerator::generateMethodIfExists(Type* type, std::string method, s for (Type *paramType : methodDef->getDataRef()->valueType->parameterTypes) nameDecoration += "_" + ValueTypeToCTypeDecoration(paramType); return scopePrefix(typeDefinition) + CifyName(typeDefinition->getDataRef()->symbol.getName()) + "__" + method + nameDecoration + "(" + parameter + ");\n"; + } else { + std::cout << method << " DOESN'T EXIST FOR TYPE " << type->toString() << std::endl; } return ""; } diff --git a/stdlib/io.krak b/stdlib/io.krak index c41a819..d9350e8 100644 --- a/stdlib/io.krak +++ b/stdlib/io.krak @@ -1,4 +1,5 @@ import string:*; +import mem:* __if_comp__ __C__ simple_passthrough """ #include @@ -8,6 +9,11 @@ fun println() : void { print("\n"); } +fun println(toPrint: T) : void { + print(toPrint) + print("\n") +} + fun print(toPrint: char*) : void { __if_comp__ __C__ { simple_passthrough(toPrint = toPrint::) """ @@ -17,17 +23,10 @@ fun print(toPrint: char*) : void { return; } -fun println(toPrint: char*) : void { - print(toPrint); - println(); -} - fun print(toPrint: string) : void { - print(toPrint.toCharArray()); -} - -fun println(toPrint: string): void { - println(toPrint.toCharArray()); + var charArr = toPrint.toCharArray() + defer delete(charArr) + print(charArr); } fun print(toPrint: int): void { @@ -39,11 +38,6 @@ fun print(toPrint: int): void { return; } -fun println(toPrint: int): void { - print(toPrint); - println(); -} - fun print(toPrint: float): void { __if_comp__ __C__ { simple_passthrough(toPrint = toPrint::) """ @@ -62,15 +56,3 @@ fun print(toPrint: double) : void{ return; } -fun println(toPrint: float): void { - print(toPrint); - println(); -} - -fun println(toPrint: double): void { - print(toPrint); - println(); -} - - - diff --git a/stdlib/string.krak b/stdlib/string.krak index 1db0a2c..8f2e9f0 100644 --- a/stdlib/string.krak +++ b/stdlib/string.krak @@ -13,15 +13,45 @@ obj string (Destructable) { data.addEnd(*str); str += 1; } + // no null terminator + return this; + } + fun construct(vec: vector::vector): string* { + data.copy_construct(&vec); return this; } + fun copy_construct(old: string*): void { + data.copy_construct(&old->data) + } + + fun destruct():void { + data.destruct() + } + + fun operator=(str: char*): void { + destruct(); + construct(str) + } + + fun operator+(str: char*): string { + var newStr.construct(str):string + var ret.construct(data + newStr.data):string + return ret + } + + fun operator+=(str: char*): void { + var newStr.construct(str):string + data += newStr.data + } + fun toCharArray(): char* { - var out: char* = mem::new(data.size); + var out: char* = mem::new(data.size+1); for (var i: int = 0; i < data.size; i++;) out[i] = data.get(i); + // null terminator + out[data.size] = 0 return out; } }; - diff --git a/stdlib/vector.krak b/stdlib/vector.krak index 1330e9c..832d956 100644 --- a/stdlib/vector.krak +++ b/stdlib/vector.krak @@ -29,7 +29,29 @@ obj vector (Destructable) { } fun destruct(): void { - delete(data); + if (data) + delete(data); + data = 0 + } + + fun operator=(other:vector):void { + resize(other.size) + for (var i = 0; i < other.size; i++;) + set(i, other.get(i)) + } + + fun operator+(other:vector):vector { + var newVec.construct(size + other.size):vector + for (var i = 0; i < size; i++;) + newVec.set(i, get(i)) + for (var i = 0; i < other.size; i++;) + newVec.set(i+size, other.get(i)) + return newVec + } + + fun operator+=(other:vector):void { + for (var i = 0; i < other.size; i++;) + addEnd(other.get(i)) } fun clone(): vector { @@ -48,6 +70,7 @@ obj vector (Destructable) { delete(data, 0); data = newData; available = newSize; + size = lesser(size, newSize) return true; } diff --git a/tests/test_string.expected_results b/tests/test_string.expected_results index abf1ab2..bd9b87c 100644 --- a/tests/test_string.expected_results +++ b/tests/test_string.expected_results @@ -1 +1,4 @@ hello strings +assignment overload +assignment overload2 +assignment overload with additional diff --git a/tests/test_string.krak b/tests/test_string.krak index 6988fd6..7d1d17f 100644 --- a/tests/test_string.krak +++ b/tests/test_string.krak @@ -5,6 +5,14 @@ import string; fun main(): int { var str.construct("hello strings"): string::string; io::println(str); + str = "assignment overload" + io::println(str); + io::println(str + "2"); + str += " with additional" + io::println(str); + //var initilized:string::string = "hope" + //io::println(initilized) + //io::println(initilized+ "3") return 0; }