From 2ea504ffc17593844ca9d5ee9fd903128cd71985 Mon Sep 17 00:00:00 2001 From: Nathan Braswell Date: Mon, 9 Nov 2015 13:26:02 -0500 Subject: [PATCH] More work on ADTs --- include/Type.h | 1 + src/ASTTransformation.cpp | 13 +- src/CGenerator.cpp | 1368 +++++++++++++++++++------------------ src/Type.cpp | 7 +- tests/test_adt.krak | 21 +- 5 files changed, 718 insertions(+), 692 deletions(-) diff --git a/include/Type.h b/include/Type.h index f783fdb..5ed2198 100644 --- a/include/Type.h +++ b/include/Type.h @@ -41,6 +41,7 @@ class Type { void decreaseIndirection(); void modifyIndirection(int mod); Type withIncreasedIndirection(); + Type *withIncreasedIndirectionPtr(); Type withDecreasedIndirection(); Type* withoutReference(); diff --git a/src/ASTTransformation.cpp b/src/ASTTransformation.cpp index 20c43b6..e666be6 100644 --- a/src/ASTTransformation.cpp +++ b/src/ASTTransformation.cpp @@ -197,6 +197,15 @@ void ASTTransformation::secondPass(NodeTree* ast, NodeTree* par std::cout << "there are " << getNodes("adt_option", i).size() << " adt_options" << std::endl; std::string name = concatSymbolTree(getNode("identifier", i)); NodeTree* adtDef = ast->getDataRef()->scope[name][0]; //No overloaded types (besides uninstantiated templates, which can have multiple versions based on types or specilizations) + + // Let's make an equality function prototype + Type *thisADTType = adtDef->getDataRef()->valueType; + NodeTree* equalityFunc = new NodeTree("function", ASTData(function, Symbol("operator==", true), new Type(std::vector{thisADTType}, new Type(boolean)))); + //NodeTree* equalityFunc = new NodeTree("function", ASTData(function, Symbol("operator==", true), new Type(std::vector{thisADTType, thisADTType}, new Type(boolean)))); + adtDef->addChild(equalityFunc); + addToScope("operator==", equalityFunc, adtDef); + addToScope("~enclosing_scope", adtDef, equalityFunc); + for (NodeTree* j : getNodes("adt_option", i)) { std::string ident_name = concatSymbolTree(getNode("identifier", j)); std::cout << "add ing " << ident_name << " to " << name << " for ADT" << std::endl; @@ -209,11 +218,11 @@ void ASTTransformation::secondPass(NodeTree* ast, NodeTree* par // also make a function prototype for a function that returns an instance of this type. If we don't contain a type, it's just the literal //enum_variant_function = new NodeTree("function", ASTData(function, Symbol("fun_"+ident_name, true), new Type(std::vector{actual_type}, adtDef->getDataRef()->valueType))); - enum_variant_function = new NodeTree("function", ASTData(function, Symbol(ident_name, true), new Type(std::vector{actual_type}, adtDef->getDataRef()->valueType))); + enum_variant_function = new NodeTree("function", ASTData(function, Symbol(ident_name, true), new Type(std::vector{actual_type}, thisADTType))); } else { enum_variant_identifier = new NodeTree("identifier", ASTData(identifier, Symbol(ident_name, true), adtDef->getDataRef()->valueType)); // now a function in both cases... - enum_variant_function = new NodeTree("function", ASTData(function, Symbol(ident_name, true), new Type(std::vector(), adtDef->getDataRef()->valueType))); + enum_variant_function = new NodeTree("function", ASTData(function, Symbol(ident_name, true), new Type(std::vector(), thisADTType))); } adtDef->addChild(enum_variant_identifier); addToScope(ident_name, enum_variant_identifier, adtDef); diff --git a/src/CGenerator.cpp b/src/CGenerator.cpp index ffa1c0f..a86af5c 100644 --- a/src/CGenerator.cpp +++ b/src/CGenerator.cpp @@ -1,7 +1,7 @@ #include "CGenerator.h" CGenerator::CGenerator() : generatorString("__C__") { - tabLevel = 0; + tabLevel = 0; id = 0; function_header = "fun_"; functionTypedefString = ""; @@ -12,9 +12,9 @@ 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 -g -O3 -std=c99 "; - std::cout << "\n\n =====GENERATE PASS===== \n\n" << std::endl; + //Generate an entire set of files + std::string buildString = "#!/bin/sh\ncc -g -O3 -std=c99 "; + std::cout << "\n\n =====GENERATE PASS===== \n\n" << std::endl; std::cout << "\n\nGenerate pass for: " << outputName << std::endl; buildString += outputName + ".c "; //std::ofstream outputCFile, outputHFile; @@ -34,20 +34,20 @@ void CGenerator::generateCompSet(std::map*> ASTs, outputCFile.close(); //outputHFile.close(); - buildString += linkerString; - buildString += "-o " + outputName; - std::ofstream outputBuild; - outputBuild.open(outputName + "/" + split(outputName, '/').back() + ".sh"); - outputBuild << buildString; - outputBuild.close(); + buildString += linkerString; + buildString += "-o " + outputName; + std::ofstream outputBuild; + outputBuild.open(outputName + "/" + split(outputName, '/').back() + ".sh"); + outputBuild << buildString; + outputBuild.close(); std::cout << "DEFER DOUBLE STACK " << deferDoubleStack.size() << std::endl; } std::string CGenerator::tabs() { - std::string returnTabs; - for (int i = 0; i < tabLevel; i++) - returnTabs += "\t"; - return returnTabs; + std::string returnTabs; + for (int i = 0; i < tabLevel; i++) + returnTabs += "\t"; + return returnTabs; } std::string CGenerator::getID() { @@ -81,7 +81,15 @@ std::string CGenerator::generateTypeStruct(NodeTree* from) { enumString += tabs() + generate(child, nullptr).oneString() + (data.type == adt_def ? ",\n" : "\n"); } else { if (data.type == adt_def) { - functionString += "\n" + ValueTypeToCType(child->getDataRef()->valueType->returnType, "fun_" + child->getDataRef()->symbol.getName()) + "(" + + std::string fun_name = child->getDataRef()->symbol.getName(); + std::string first_param; + if (fun_name == "operator==") { + fun_name = "fun_" + data.symbol.getName() + "__" + CifyName(fun_name); + first_param = ValueTypeToCType(child->getDataRef()->valueType->parameterTypes[0]->withIncreasedIndirectionPtr(), "this") + ", "; + } else { + fun_name = "fun_" + fun_name; + } + functionString += "\n" + ValueTypeToCType(child->getDataRef()->valueType->returnType, fun_name) + "(" + first_param + (child->getDataRef()->valueType->parameterTypes.size() ? ValueTypeToCType(child->getDataRef()->valueType->parameterTypes[0], "in") : "") + "); /*adt func*/\n"; } } @@ -101,144 +109,144 @@ std::string CGenerator::generateTypeStruct(NodeTree* from) { // This method recurseivly generates all aliases of some definition std::string CGenerator::generateAliasChains(std::map*> ASTs, NodeTree* definition) { -std::string output; -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 " + - prefixIfNeeded(scopePrefix(definition), CifyName(definition->getDataRef()->symbol.getName())) + " " + - prefixIfNeeded(scopePrefix(declaration), CifyName(declarationData->symbol.getName())) + ";\n"; - // Recursively add the ones that depend on this one - output += generateAliasChains(ASTs, declaration); + std::string output; + 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 " + + prefixIfNeeded(scopePrefix(definition), CifyName(definition->getDataRef()->symbol.getName())) + " " + + prefixIfNeeded(scopePrefix(declaration), CifyName(declarationData->symbol.getName())) + ";\n"; + // Recursively add the ones that depend on this one + output += generateAliasChains(ASTs, declaration); + } } } } -} -return output; + return output; } bool CGenerator::isUnderNodeWithType(NodeTree* from, ASTType type) { -auto scope = from->getDataRef()->scope; -auto upper = scope.find("~enclosing_scope"); -if (upper != scope.end()) { - if (upper->second[0]->getDataRef()->type == type) - return true; - return isUnderNodeWithType(upper->second[0], type); -} -return false; + auto scope = from->getDataRef()->scope; + auto upper = scope.find("~enclosing_scope"); + if (upper != scope.end()) { + if (upper->second[0]->getDataRef()->type == type) + return true; + return isUnderNodeWithType(upper->second[0], type); + } + return false; } bool CGenerator::isUnderTranslationUnit(NodeTree* from, NodeTree* node) { -auto scope = from->getDataRef()->scope; -for (auto i : scope) - for (auto j : i.second) - if (j == node) - return true; + auto scope = from->getDataRef()->scope; + for (auto i : scope) + for (auto j : i.second) + if (j == node) + return true; -auto upper = scope.find("~enclosing_scope"); -if (upper != scope.end()) - return isUnderTranslationUnit(upper->second[0], node); -return false; + auto upper = scope.find("~enclosing_scope"); + if (upper != scope.end()) + return isUnderTranslationUnit(upper->second[0], node); + return false; } NodeTree* CGenerator::highestScope(NodeTree* node) { -auto it = node->getDataRef()->scope.find("~enclosing_scope"); -while (it != node->getDataRef()->scope.end()) { - node = it->second[0]; - it = node->getDataRef()->scope.find("~enclosing_scope"); -} -return node; + auto it = node->getDataRef()->scope.find("~enclosing_scope"); + while (it != node->getDataRef()->scope.end()) { + node = it->second[0]; + it = node->getDataRef()->scope.find("~enclosing_scope"); + } + return 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(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. -// -// 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). + // 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. + // + // 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. + // 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 importIncludes = "/**\n * Import Includes\n */\n\n"; -std::string topLevelCPassthrough = "/**\n * Top Level C Passthrough\n */\n\n"; -std::string variableExternDeclarations = "/**\n * Extern Variable Declarations \n */\n\n"; -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"; -// There also exists functionTypedefString which is a member variable that keeps -// track of utility typedefs that allow our C type generation to be more sane -// it is emitted in the h file right before functionPrototypes + std::string importIncludes = "/**\n * Import Includes\n */\n\n"; + std::string topLevelCPassthrough = "/**\n * Top Level C Passthrough\n */\n\n"; + std::string variableExternDeclarations = "/**\n * Extern Variable Declarations \n */\n\n"; + 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"; + // There also exists functionTypedefString which is a member variable that keeps + // track of utility typedefs that allow our C type generation to be more sane + // it is emitted in the h file right before functionPrototypes -Poset*> typedefPoset; -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; + Poset*> typedefPoset; + 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) // If this is a custom type and not a pointer - 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 + } } + } else if (children[i]->getDataRef()->type == adt_def) { + // + typedefPoset.addVertex(children[i]); // We add this definition by itself just in case there are no dependencies. } - } else if (children[i]->getDataRef()->type == adt_def) { - // - typedefPoset.addVertex(children[i]); // We add this definition by itself just in case there are no dependencies. } } -} -//Now generate the typedef's in the correct, topological order -for (NodeTree* i : typedefPoset.getTopoSort()) - classStructs += generateTypeStruct(i) + "\n"; + //Now generate the typedef's in the correct, topological order + for (NodeTree* i : typedefPoset.getTopoSort()) + classStructs += generateTypeStruct(i) + "\n"; -// 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 -// Also c passthrough -for (auto trans : ASTs) { - // First go through and emit all the passthroughs, etc - for (auto i : trans.second->getChildren()) { - if (i->getDataRef()->type == if_comp) - topLevelCPassthrough += generate(i, nullptr).oneString(); - } + // 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 + // Also c passthrough + for (auto trans : ASTs) { + // First go through and emit all the passthroughs, etc + for (auto i : trans.second->getChildren()) { + if (i->getDataRef()->type == if_comp) + topLevelCPassthrough += generate(i, nullptr).oneString(); + } - 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: - { - auto parent = declaration->getDataRef()->scope["~enclosing_scope"][0]; - if (parent->getChildren().size() == 1) - variableDeclarations += ValueTypeToCType(declarationData.valueType, prefixIfNeeded(scopePrefix(declaration), declarationData.symbol.getName())) + "; /*identifier*/\n"; - else - variableDeclarations += ValueTypeToCType(declarationData.valueType, generate(parent->getChildren()[0], nullptr, true, nullptr).oneString()) + " = " + generate(parent->getChildren()[1], nullptr, true, nullptr).oneString() + ";"; - variableExternDeclarations += "extern " + ValueTypeToCType(declarationData.valueType, declarationData.symbol.getName()) + "; /*extern identifier*/\n"; - break; + 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: + { + auto parent = declaration->getDataRef()->scope["~enclosing_scope"][0]; + if (parent->getChildren().size() == 1) + variableDeclarations += ValueTypeToCType(declarationData.valueType, prefixIfNeeded(scopePrefix(declaration), declarationData.symbol.getName())) + "; /*identifier*/\n"; + else + variableDeclarations += ValueTypeToCType(declarationData.valueType, generate(parent->getChildren()[0], nullptr, true, nullptr).oneString()) + " = " + generate(parent->getChildren()[1], nullptr, true, nullptr).oneString() + ";"; + variableExternDeclarations += "extern " + ValueTypeToCType(declarationData.valueType, declarationData.symbol.getName()) + "; /*extern identifier*/\n"; + break; } case function: { @@ -276,12 +284,12 @@ for (auto trans : ASTs) { 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, - prefixIfNeeded(scopePrefix(declaration), CifyName(declarationData.symbol.getName()))) + ";\n"; + prefixIfNeeded(scopePrefix(declaration), CifyName(declarationData.symbol.getName()))) + ";\n"; plainTypedefs += generateAliasChains(ASTs, declaration); } else { plainTypedefs += "typedef struct __struct_dummy_" + - prefixIfNeeded(scopePrefix(declaration), CifyName(declarationData.symbol.getName()) + "__") + " " + - prefixIfNeeded(scopePrefix(declaration), CifyName(declarationData.symbol.getName())) + ";\n"; + prefixIfNeeded(scopePrefix(declaration), CifyName(declarationData.symbol.getName()) + "__") + " " + + prefixIfNeeded(scopePrefix(declaration), 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"; @@ -299,19 +307,19 @@ for (auto trans : ASTs) { } break; case adt_def: - { - //type - //don't even need to do this anymore, it's all earlier - //plainTypedefs += "/* adt " + declarationData.symbol.getName() + " */\n"; - //plainTypedefs += "typedef struct __struct_dummy_" + - //prefixIfNeeded(scopePrefix(declaration), CifyName(declarationData.symbol.getName())+ "__") + " " + - //prefixIfNeeded(scopePrefix(declaration), CifyName(declarationData.symbol.getName())) + ";\n"; - //// skip the name of the thing - //for (int j = 1; j < decChildren.size(); j++) { + { + //type + //don't even need to do this anymore, it's all earlier + //plainTypedefs += "/* adt " + declarationData.symbol.getName() + " */\n"; + //plainTypedefs += "typedef struct __struct_dummy_" + + //prefixIfNeeded(scopePrefix(declaration), CifyName(declarationData.symbol.getName())+ "__") + " " + + //prefixIfNeeded(scopePrefix(declaration), CifyName(declarationData.symbol.getName())) + ";\n"; + //// skip the name of the thing + //for (int j = 1; j < decChildren.size(); j++) { //std::cout << decChildren[j]->getName() << std::endl; - //} - break; - } + //} + 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"; @@ -327,153 +335,153 @@ for (auto trans : ASTs) { //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 CCodeTriple CGenerator::generate(NodeTree* from, NodeTree* enclosingObject, bool justFuncName, NodeTree* enclosingFunction) { - ASTData data = from->getData(); - std::vector*> children = from->getChildren(); + ASTData data = from->getData(); + std::vector*> children = from->getChildren(); //std::string output; CCodeTriple output; - switch (data.type) { - case translation_unit: - { - // Should not happen! We do this in it's own function now! - std::cerr << "Trying to normal generate a translation unit! That's a nono! (" << from->getDataRef()->toString() << ")" << std::endl; - throw "That's not gonna work"; - } - break; - case interpreter_directive: - //Do nothing - break; - case import: - return CCodeTriple("/* never reached import? */\n"); - case identifier: - { - std::string preName = ""; - std::string postName = ""; - bool closed = false; - // check for this being a closed over variable - // first, get declaring function, if it exists - if (enclosingFunction) { - if (enclosingFunction->getDataRef()->closedVariables.size()) { - std::cout << "WHOH IS A CLOSER" << std::endl; - if (enclosingFunction->getDataRef()->closedVariables.find(from) != enclosingFunction->getDataRef()->closedVariables.end()) { - preName += "(*closed_variables->"; - postName += ")"; - closed = true; - } - } - } - // enclosing function comes first now, we might have a double closure that both close over the this pointer of an object - //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 || enclosingFunction) - return CCodeTriple(preName + "this" + postName); - std::cerr << "Error: this used in non-object scope" << std::endl; - throw "Error: this used in non-object scope"; - } - //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. - if (enclosingObject && enclosingObject->getDataRef()->scope.find(data.symbol.getName()) != enclosingObject->getDataRef()->scope.end()) - preName = "(" + preName + "this)->"; // incase this is a closed over this that is referencing another thing (I think this happens for a.b when a is supposed to be closed over but isn't) - // dereference references, but only if inside a function and not if this is a closed over variable - if (enclosingFunction && data.valueType->is_reference && !closed) { - preName += "(*"; - postName += ")"; - } - // we're scope prefixing EVERYTHING, but only if needed - return preName + prefixIfNeeded(scopePrefix(from), CifyName(data.symbol.getName())) + postName; //Cifying does nothing if not an operator overload - } - case function: - { - if (data.valueType->baseType == template_type) - return "/* template function: " + data.symbol.getName() + " */"; - - // we push on a new vector to hold parameters that might need a destructor call - distructDoubleStack.push_back(std::vector*>()); - - std::string nameDecoration, parameters; - if (data.closedVariables.size()) - parameters += closureStructType(data.closedVariables) + " *closed_variables"; - for (int j = 0; j < children.size()-1; j++) { - if (j > 0 || data.closedVariables.size()) - parameters += ", "; - parameters += ValueTypeToCType(children[j]->getData().valueType, generate(children[j], enclosingObject, justFuncName, enclosingFunction).oneString()); - nameDecoration += "_" + ValueTypeToCTypeDecoration(children[j]->getData().valueType); - // add parameters to distructDoubleStack so that their destructors will be called at return (if they exist) - distructDoubleStack.back().push_back(children[j]); - } - // this is for using functions as values - if (justFuncName) { - std::string funcName; - if (data.symbol.getName() != "main") - funcName += function_header + prefixIfNeeded(scopePrefix(from), CifyName(data.symbol.getName() + nameDecoration)); - else - funcName += CifyName(data.symbol.getName() + nameDecoration); - if (from->getDataRef()->closedVariables.size()) { - std::string tmpStruct = "closureStruct" + getID(); - output.preValue += closureStructType(data.closedVariables) + " " + tmpStruct + " = {"; - bool notFirst = false; - for (auto var : data.closedVariables) { - if (notFirst) - output.preValue += ", "; - notFirst = true; - std::string varName = var->getDataRef()->symbol.getName(); - std::string preName; - if (enclosingObject && enclosingObject->getDataRef()->scope.find(varName) != enclosingObject->getDataRef()->scope.end()) - preName += "this->"; - varName = (varName == "this") ? varName : prefixIfNeeded(scopePrefix(var), varName); - // so that we can close over things that have been closed over by an enclosing closure - output.preValue += "." + varName + " = &/*woo*/" + generate(var, enclosingObject, justFuncName, enclosingFunction).oneString() + "/*woo*/"; - //output.preValue += "." + varName + " = &" + preName + varName; - } - output.preValue += "};\n"; - output += "("+ ValueTypeToCType(data.valueType, "") +"){(void*)" + funcName + ", &" + tmpStruct + "}"; - } else { - output += "("+ ValueTypeToCType(data.valueType, "") +"){" + funcName + ", NULL}"; - } - } else { - // Note that we always wrap out child in {}, as we now allow one statement functions without a codeblock - std::string funName = (data.symbol.getName() == "main") ? "main" : function_header + prefixIfNeeded(scopePrefix(from), CifyName(data.symbol.getName() + nameDecoration)); - output = "\n" + ValueTypeToCType(data.valueType->returnType, funName) + "(" + parameters + ") {\n" + - generate(children[children.size()-1], enclosingObject, justFuncName, from).oneString(); - output += emitDestructors(reverse(distructDoubleStack.back()), enclosingObject); - output += "}\n"; - } - - distructDoubleStack.pop_back(); - return output; - } - case code_block: - { - output += "{\n"; - tabLevel++; - - // we push on a new vector to hold parameters that might need a destructor call - distructDoubleStack.push_back(std::vector*>()); - // we push on a new vector to hold deferred statements - deferDoubleStack.push_back(std::vector*>()); - for (int i = 0; i < children.size(); i++) - output += generate(children[i], enclosingObject, justFuncName, enclosingFunction).oneString(); - // we pop off the vector and go through them in reverse emitting them - for (auto iter = deferDoubleStack.back().rbegin(); iter != deferDoubleStack.back().rend(); iter++) - output += generate(*iter, enclosingObject, justFuncName, enclosingFunction).oneString(); - deferDoubleStack.pop_back(); - output += emitDestructors(reverse(distructDoubleStack.back()), enclosingObject); - distructDoubleStack.pop_back(); - - tabLevel--; - output += tabs() + "}"; - - return output; - } - case expression: - output += " " + data.symbol.getName() + ", "; - case boolean_expression: - output += " " + data.symbol.getName() + " "; - case statement: + switch (data.type) { + case translation_unit: { - CCodeTriple stat = generate(children[0], enclosingObject, justFuncName, enclosingFunction); - return tabs() + stat.preValue + stat.value + ";\n" + stat.postValue ; + // Should not happen! We do this in it's own function now! + std::cerr << "Trying to normal generate a translation unit! That's a nono! (" << from->getDataRef()->toString() << ")" << std::endl; + throw "That's not gonna work"; } - case if_statement: - output += "if (" + generate(children[0], enclosingObject, true, enclosingFunction) + ")\n\t"; + break; + case interpreter_directive: + //Do nothing + break; + case import: + return CCodeTriple("/* never reached import? */\n"); + case identifier: + { + std::string preName = ""; + std::string postName = ""; + bool closed = false; + // check for this being a closed over variable + // first, get declaring function, if it exists + if (enclosingFunction) { + if (enclosingFunction->getDataRef()->closedVariables.size()) { + std::cout << "WHOH IS A CLOSER" << std::endl; + if (enclosingFunction->getDataRef()->closedVariables.find(from) != enclosingFunction->getDataRef()->closedVariables.end()) { + preName += "(*closed_variables->"; + postName += ")"; + closed = true; + } + } + } + // enclosing function comes first now, we might have a double closure that both close over the this pointer of an object + //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 || enclosingFunction) + return CCodeTriple(preName + "this" + postName); + std::cerr << "Error: this used in non-object scope" << std::endl; + throw "Error: this used in non-object scope"; + } + //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. + if (enclosingObject && enclosingObject->getDataRef()->scope.find(data.symbol.getName()) != enclosingObject->getDataRef()->scope.end()) + preName = "(" + preName + "this)->"; // incase this is a closed over this that is referencing another thing (I think this happens for a.b when a is supposed to be closed over but isn't) + // dereference references, but only if inside a function and not if this is a closed over variable + if (enclosingFunction && data.valueType->is_reference && !closed) { + preName += "(*"; + postName += ")"; + } + // we're scope prefixing EVERYTHING, but only if needed + return preName + prefixIfNeeded(scopePrefix(from), CifyName(data.symbol.getName())) + postName; //Cifying does nothing if not an operator overload + } + case function: + { + if (data.valueType->baseType == template_type) + return "/* template function: " + data.symbol.getName() + " */"; + + // we push on a new vector to hold parameters that might need a destructor call + distructDoubleStack.push_back(std::vector*>()); + + std::string nameDecoration, parameters; + if (data.closedVariables.size()) + parameters += closureStructType(data.closedVariables) + " *closed_variables"; + for (int j = 0; j < children.size()-1; j++) { + if (j > 0 || data.closedVariables.size()) + parameters += ", "; + parameters += ValueTypeToCType(children[j]->getData().valueType, generate(children[j], enclosingObject, justFuncName, enclosingFunction).oneString()); + nameDecoration += "_" + ValueTypeToCTypeDecoration(children[j]->getData().valueType); + // add parameters to distructDoubleStack so that their destructors will be called at return (if they exist) + distructDoubleStack.back().push_back(children[j]); + } + // this is for using functions as values + if (justFuncName) { + std::string funcName; + if (data.symbol.getName() != "main") + funcName += function_header + prefixIfNeeded(scopePrefix(from), CifyName(data.symbol.getName() + nameDecoration)); + else + funcName += CifyName(data.symbol.getName() + nameDecoration); + if (from->getDataRef()->closedVariables.size()) { + std::string tmpStruct = "closureStruct" + getID(); + output.preValue += closureStructType(data.closedVariables) + " " + tmpStruct + " = {"; + bool notFirst = false; + for (auto var : data.closedVariables) { + if (notFirst) + output.preValue += ", "; + notFirst = true; + std::string varName = var->getDataRef()->symbol.getName(); + std::string preName; + if (enclosingObject && enclosingObject->getDataRef()->scope.find(varName) != enclosingObject->getDataRef()->scope.end()) + preName += "this->"; + varName = (varName == "this") ? varName : prefixIfNeeded(scopePrefix(var), varName); + // so that we can close over things that have been closed over by an enclosing closure + output.preValue += "." + varName + " = &/*woo*/" + generate(var, enclosingObject, justFuncName, enclosingFunction).oneString() + "/*woo*/"; + //output.preValue += "." + varName + " = &" + preName + varName; + } + output.preValue += "};\n"; + output += "("+ ValueTypeToCType(data.valueType, "") +"){(void*)" + funcName + ", &" + tmpStruct + "}"; + } else { + output += "("+ ValueTypeToCType(data.valueType, "") +"){" + funcName + ", NULL}"; + } + } else { + // Note that we always wrap out child in {}, as we now allow one statement functions without a codeblock + std::string funName = (data.symbol.getName() == "main") ? "main" : function_header + prefixIfNeeded(scopePrefix(from), CifyName(data.symbol.getName() + nameDecoration)); + output = "\n" + ValueTypeToCType(data.valueType->returnType, funName) + "(" + parameters + ") {\n" + + generate(children[children.size()-1], enclosingObject, justFuncName, from).oneString(); + output += emitDestructors(reverse(distructDoubleStack.back()), enclosingObject); + output += "}\n"; + } + + distructDoubleStack.pop_back(); + return output; + } + case code_block: + { + output += "{\n"; + tabLevel++; + + // we push on a new vector to hold parameters that might need a destructor call + distructDoubleStack.push_back(std::vector*>()); + // we push on a new vector to hold deferred statements + deferDoubleStack.push_back(std::vector*>()); + for (int i = 0; i < children.size(); i++) + output += generate(children[i], enclosingObject, justFuncName, enclosingFunction).oneString(); + // we pop off the vector and go through them in reverse emitting them + for (auto iter = deferDoubleStack.back().rbegin(); iter != deferDoubleStack.back().rend(); iter++) + output += generate(*iter, enclosingObject, justFuncName, enclosingFunction).oneString(); + deferDoubleStack.pop_back(); + output += emitDestructors(reverse(distructDoubleStack.back()), enclosingObject); + distructDoubleStack.pop_back(); + + tabLevel--; + output += tabs() + "}"; + + return output; + } + case expression: + output += " " + data.symbol.getName() + ", "; + case boolean_expression: + output += " " + data.symbol.getName() + " "; + case statement: + { + CCodeTriple stat = generate(children[0], enclosingObject, justFuncName, enclosingFunction); + return tabs() + stat.preValue + stat.value + ";\n" + stat.postValue ; + } + case if_statement: + output += "if (" + generate(children[0], enclosingObject, true, enclosingFunction) + ")\n\t"; // We have to see if the then statement is a regular single statement or a block. // If it's a block, because it's also a statement a semicolon will be emitted even though // we don't want it to be, as if (a) {b}; else {c}; is not legal C, but if (a) {b} else {c}; is. @@ -485,107 +493,107 @@ CCodeTriple CGenerator::generate(NodeTree* from, NodeTree* enc output += "{ " + generate(children[1], enclosingObject, justFuncName, enclosingFunction).oneString() + " }"; } // Always emit blocks here too - if (children.size() > 2) - output += " else { " + generate(children[2], enclosingObject, justFuncName, enclosingFunction).oneString() + " }"; - return output; - case while_loop: - { - // we push on a new vector to hold while stuff that might need a destructor call - loopDistructStackDepth.push(distructDoubleStack.size()); - distructDoubleStack.push_back(std::vector*>()); - // keep track of the current size of the deferDoubleStack so that statements that - // break or continue inside this loop can correctly emit all of the defers through - // all of the inbetween scopes - loopDeferStackDepth.push(deferDoubleStack.size()); - // gotta do like this so that the preconditions can happen every loop - output += "while (1) {\n"; - CCodeTriple condtition = generate(children[0], enclosingObject, true, enclosingFunction); - output += condtition.preValue; - output += "if (!( " + condtition.value + ")) break;\n"; - output += condtition.postValue; - output += generate(children[1], enclosingObject, justFuncName, enclosingFunction).oneString(); - output += emitDestructors(reverse(distructDoubleStack.back()),enclosingObject); - output += + "}"; - - distructDoubleStack.pop_back(); - loopDistructStackDepth.pop(); - // and pop it off again - loopDeferStackDepth.pop(); - return output; - } - case for_loop: - { - // we push on a new vector to hold for stuff that might need a destructor call - loopDistructStackDepth.push(distructDoubleStack.size()); - distructDoubleStack.push_back(std::vector*>()); - // keep track of the current size of the deferDoubleStack so that statements that - // break or continue inside this loop can correctly emit all of the defers through - // all of the inbetween scopes - loopDeferStackDepth.push(deferDoubleStack.size()); - //The strSlice's are there to get ride of an unwanted return and an unwanted semicolon(s) - - std::string doUpdateName = "do_update" + getID(); - // INITIALIZER - output += "{"; - output += generate(children[0], enclosingObject, true, enclosingFunction).oneString(); - output += "bool " + doUpdateName + " = false;\n"; - output += "for (;;) {"; - // UPDATE - output += "if (" + doUpdateName + ") {"; - output += generate(children[2], enclosingObject, true, enclosingFunction).oneString(); - output += "}\n"; - output += doUpdateName + " = true;\n"; - // CONDITION - // note that the postValue happens whether or not we break - CCodeTriple condition = generate(children[1], enclosingObject, true, enclosingFunction); - output += condition.preValue; - output += "if (!(" + condition.value + ")) {\n"; - output += condition.postValue; - output += "break;\n}"; - output += condition.postValue; - // BODY - output += generate(children[3], enclosingObject, justFuncName, enclosingFunction).oneString(); - output += emitDestructors(reverse(distructDoubleStack.back()),enclosingObject); - output += "}"; - output += "}"; - distructDoubleStack.pop_back(); - loopDistructStackDepth.pop(); - // and pop it off again - loopDeferStackDepth.pop(); - return output; - } - case return_statement: - { - // we pop off the vector and go through them in reverse emitting them, going - // through all of both arrays, as return will go through all scopes - for (auto topItr = deferDoubleStack.rbegin(); topItr != deferDoubleStack.rend(); topItr++) - for (auto iter = (*topItr).rbegin(); iter != (*topItr).rend(); iter++) - output += generate(*iter, enclosingObject, justFuncName, enclosingFunction).oneString(); - - std::string destructors = emitDestructors(reverse(flatten(distructDoubleStack)),enclosingObject); - if (children.size()) { - CCodeTriple expr = generate(children[0], enclosingObject, true, enclosingFunction); - output.preValue += expr.preValue; - std::string retTemp = "ret_temp" + getID(); - // use the function's return value so we do the right thing with references - output.preValue += ValueTypeToCType(enclosingFunction->getDataRef()->valueType->returnType, retTemp) + ";\n"; - if (enclosingFunction->getDataRef()->valueType->returnType->is_reference) - output.preValue += retTemp + " = &" + expr.value + ";\n"; - else if (methodExists(children[0]->getDataRef()->valueType, "copy_construct", std::vector{children[0]->getDataRef()->valueType->withIncreasedIndirection()})) - output.preValue += generateMethodIfExists(children[0]->getDataRef()->valueType, "copy_construct", "&"+retTemp + ", &" + expr.value, std::vector{children[0]->getDataRef()->valueType->withIncreasedIndirection()}); - else - output.preValue += retTemp + " = " + expr.value + ";\n"; - // move expr post to before return - output.value += expr.postValue; - output.value += destructors; - output.value += "return " + retTemp; - } else { - output.value += destructors; - output += "return"; - } + if (children.size() > 2) + output += " else { " + generate(children[2], enclosingObject, justFuncName, enclosingFunction).oneString() + " }"; return output; + case while_loop: + { + // we push on a new vector to hold while stuff that might need a destructor call + loopDistructStackDepth.push(distructDoubleStack.size()); + distructDoubleStack.push_back(std::vector*>()); + // keep track of the current size of the deferDoubleStack so that statements that + // break or continue inside this loop can correctly emit all of the defers through + // all of the inbetween scopes + loopDeferStackDepth.push(deferDoubleStack.size()); + // gotta do like this so that the preconditions can happen every loop + output += "while (1) {\n"; + CCodeTriple condtition = generate(children[0], enclosingObject, true, enclosingFunction); + output += condtition.preValue; + output += "if (!( " + condtition.value + ")) break;\n"; + output += condtition.postValue; + output += generate(children[1], enclosingObject, justFuncName, enclosingFunction).oneString(); + output += emitDestructors(reverse(distructDoubleStack.back()),enclosingObject); + output += + "}"; + + distructDoubleStack.pop_back(); + loopDistructStackDepth.pop(); + // and pop it off again + loopDeferStackDepth.pop(); + return output; } - case break_statement: + case for_loop: + { + // we push on a new vector to hold for stuff that might need a destructor call + loopDistructStackDepth.push(distructDoubleStack.size()); + distructDoubleStack.push_back(std::vector*>()); + // keep track of the current size of the deferDoubleStack so that statements that + // break or continue inside this loop can correctly emit all of the defers through + // all of the inbetween scopes + loopDeferStackDepth.push(deferDoubleStack.size()); + //The strSlice's are there to get ride of an unwanted return and an unwanted semicolon(s) + + std::string doUpdateName = "do_update" + getID(); + // INITIALIZER + output += "{"; + output += generate(children[0], enclosingObject, true, enclosingFunction).oneString(); + output += "bool " + doUpdateName + " = false;\n"; + output += "for (;;) {"; + // UPDATE + output += "if (" + doUpdateName + ") {"; + output += generate(children[2], enclosingObject, true, enclosingFunction).oneString(); + output += "}\n"; + output += doUpdateName + " = true;\n"; + // CONDITION + // note that the postValue happens whether or not we break + CCodeTriple condition = generate(children[1], enclosingObject, true, enclosingFunction); + output += condition.preValue; + output += "if (!(" + condition.value + ")) {\n"; + output += condition.postValue; + output += "break;\n}"; + output += condition.postValue; + // BODY + output += generate(children[3], enclosingObject, justFuncName, enclosingFunction).oneString(); + output += emitDestructors(reverse(distructDoubleStack.back()),enclosingObject); + output += "}"; + output += "}"; + distructDoubleStack.pop_back(); + loopDistructStackDepth.pop(); + // and pop it off again + loopDeferStackDepth.pop(); + return output; + } + case return_statement: + { + // we pop off the vector and go through them in reverse emitting them, going + // through all of both arrays, as return will go through all scopes + for (auto topItr = deferDoubleStack.rbegin(); topItr != deferDoubleStack.rend(); topItr++) + for (auto iter = (*topItr).rbegin(); iter != (*topItr).rend(); iter++) + output += generate(*iter, enclosingObject, justFuncName, enclosingFunction).oneString(); + + std::string destructors = emitDestructors(reverse(flatten(distructDoubleStack)),enclosingObject); + if (children.size()) { + CCodeTriple expr = generate(children[0], enclosingObject, true, enclosingFunction); + output.preValue += expr.preValue; + std::string retTemp = "ret_temp" + getID(); + // use the function's return value so we do the right thing with references + output.preValue += ValueTypeToCType(enclosingFunction->getDataRef()->valueType->returnType, retTemp) + ";\n"; + if (enclosingFunction->getDataRef()->valueType->returnType->is_reference) + output.preValue += retTemp + " = &" + expr.value + ";\n"; + else if (methodExists(children[0]->getDataRef()->valueType, "copy_construct", std::vector{children[0]->getDataRef()->valueType->withIncreasedIndirection()})) + output.preValue += generateMethodIfExists(children[0]->getDataRef()->valueType, "copy_construct", "&"+retTemp + ", &" + expr.value, std::vector{children[0]->getDataRef()->valueType->withIncreasedIndirection()}); + else + output.preValue += retTemp + " = " + expr.value + ";\n"; + // move expr post to before return + output.value += expr.postValue; + output.value += destructors; + output.value += "return " + retTemp; + } else { + output.value += destructors; + output += "return"; + } + return output; + } + case break_statement: // handle everything that's been deferred all the way back to the loop's scope for (int i = deferDoubleStack.size()-1; i >= loopDeferStackDepth.top(); i--) for (auto iter = deferDoubleStack[i].rbegin(); iter != deferDoubleStack[i].rend(); iter++) @@ -593,7 +601,7 @@ CCodeTriple CGenerator::generate(NodeTree* from, NodeTree* enc // ok, emit destructors to where the loop ends output += emitDestructors(reverse(flatten(slice(distructDoubleStack,loopDistructStackDepth.top(),-1))),enclosingObject); return output + "break"; - case continue_statement: + case continue_statement: // handle everything that's been deferred all the way back to the loop's scope for (int i = deferDoubleStack.size()-1; i >= loopDeferStackDepth.top(); i--) for (auto iter = deferDoubleStack[i].rbegin(); iter != deferDoubleStack[i].rend(); iter++) @@ -601,21 +609,21 @@ CCodeTriple CGenerator::generate(NodeTree* from, NodeTree* enc // ok, emit destructors to where the loop ends output += emitDestructors(reverse(flatten(slice(distructDoubleStack,loopDistructStackDepth.top(),-1))),enclosingObject); return output + "continue"; - case defer_statement: + case defer_statement: deferDoubleStack.back().push_back(children[0]); return CCodeTriple("/*defer " + generate(children[0], enclosingObject, justFuncName, enclosingFunction).oneString() + "*/"); - case assignment_statement: - return generate(children[0], enclosingObject, justFuncName, enclosingFunction).oneString() + " = " + generate(children[1], enclosingObject, true, enclosingFunction); - case declaration_statement: + case assignment_statement: + return generate(children[0], enclosingObject, justFuncName, enclosingFunction).oneString() + " = " + generate(children[1], enclosingObject, true, enclosingFunction); + case declaration_statement: // adding declaration to the distructDoubleStack so that we can call their destructors when leaving scope (}, return, break, continue) // but only if we're inside an actual doublestack if ((distructDoubleStack.size())) distructDoubleStack.back().push_back(children[0]); - if (children.size() == 1) - return ValueTypeToCType(children[0]->getData().valueType, generate(children[0], enclosingObject, justFuncName, enclosingFunction).oneString()) + ";"; - else if (children[1]->getChildren().size() && children[1]->getChildren()[0]->getChildren().size() > 1 - && children[1]->getChildren()[0]->getChildren()[1] == children[0]) { + if (children.size() == 1) + return ValueTypeToCType(children[0]->getData().valueType, generate(children[0], enclosingObject, justFuncName, enclosingFunction).oneString()) + ";"; + 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]) // be sure to end value by passing oneString true @@ -642,13 +650,13 @@ CCodeTriple CGenerator::generate(NodeTree* from, NodeTree* enc return output; } } - case if_comp: + case if_comp: // Lol, this doesn't work because the string gets prefixed now - //if (generate(children[0], enclosingObject, enclosingFunction) == generatorString) - if (children[0]->getDataRef()->symbol.getName() == generatorString) - return generate(children[1], enclosingObject, justFuncName, enclosingFunction); - return CCodeTriple(""); - case simple_passthrough: + //if (generate(children[0], enclosingObject, enclosingFunction) == generatorString) + if (children[0]->getDataRef()->symbol.getName() == generatorString) + return generate(children[1], enclosingObject, justFuncName, enclosingFunction); + return CCodeTriple(""); + case simple_passthrough: { std::string pre_end_dec, end_assign; // Stuff is bit more interesting now! XXX @@ -693,212 +701,212 @@ CCodeTriple CGenerator::generate(NodeTree* from, NodeTree* enc else return strSlice(children.back()->getDataRef()->symbol.getName(), 3, -4); } - case function_call: - { - //NOTE: The first (0th) child of a function call node is the declaration of the function + case function_call: + { + //NOTE: The first (0th) child of a function call node is the declaration of the function - //Handle operators specially for now. Will later replace with - //Inlined functions in the standard library - // std::string name = data.symbol.getName(); - // std::cout << name << " == " << children[0]->getData().symbol.getName() << std::endl; - std::string name = children[0]->getDataRef()->symbol.getName(); - ASTType funcType = children[0]->getDataRef()->type; + //Handle operators specially for now. Will later replace with + //Inlined functions in the standard library + // std::string name = data.symbol.getName(); + // std::cout << name << " == " << children[0]->getData().symbol.getName() << std::endl; + std::string name = children[0]->getDataRef()->symbol.getName(); + ASTType funcType = children[0]->getDataRef()->type; - // UGLLLLYYYY - // But we have these here because some stuff has to be moved out of the giant nested blocks below and this is the way to do it - CCodeTriple functionCallSource; - bool doClosureInstead = false; + // UGLLLLYYYY + // But we have these here because some stuff has to be moved out of the giant nested blocks below and this is the way to do it + CCodeTriple functionCallSource; + bool doClosureInstead = false; - //std::cout << "Doing function: " << name << std::endl; - //Test for special functions only if what we're testing is, indeed, the definition, not a function call that returns a callable function pointer - if (funcType == function) { - if (name == "++" || name == "--") - return generate(children[1], enclosingObject, true, enclosingFunction) + name; - if ( (name == "*" || name == "&" || name == "!" || name == "-" || name == "+" ) && children.size() == 2) //Is dereference, not multiplication, address-of, or other unary operator - return name + "(" + generate(children[1], enclosingObject, true, enclosingFunction) + ")"; - if (name == "[]") - return "(" + generate(children[1], enclosingObject, true, enclosingFunction) + ")[" + generate(children[2],enclosingObject, true, enclosingFunction) + "]"; - if (name == "+" || name == "-" || name == "*" || name == "/" || name == "==" || name == ">=" || name == "<=" || name == "!=" - || name == "<" || name == ">" || name == "%" || name == "=" || name == "+=" || name == "-=" || name == "*=" || name == "/=") { - return "((" + generate(children[1], enclosingObject, true, enclosingFunction) + ")" + name + "(" + generate(children[2], enclosingObject, true, enclosingFunction) + "))"; - } else if (name == "&&" || name == "||") { - // b/c short circuiting, these have to be done seperately - CCodeTriple lhs = generate(children[1], enclosingObject, true, enclosingFunction); - CCodeTriple rhs = generate(children[2], enclosingObject, true, enclosingFunction); - output.preValue = lhs.preValue; - std::string shortcircuit_result = "shortcircuit_result" + getID(); - output.preValue += "bool " + shortcircuit_result + " = " + lhs.value + ";\n"; - output.preValue += lhs.postValue; - output.preValue += "if (" + std::string(name == "||" ? "!":"") + shortcircuit_result + ") { \n"; - output.preValue += rhs.preValue; - output.preValue += shortcircuit_result + " = " + rhs.value + ";\n"; - output.preValue += rhs.postValue; - output.preValue += "}\n"; - output.value = shortcircuit_result; - return output; - } else if (name == "." || name == "->") { - if (children.size() == 1) - return "/*dot operation with one child*/" + generate(children[0], enclosingObject, true, enclosingFunction).oneString() + "/*end one child*/"; - //If this is accessing an actual function, find the function in scope and take the appropriate action. Probabally an object method - if (children[2]->getDataRef()->type == function) { - 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) { - 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); - // Note that we only add scoping to the object, as this specifies our member function too -/*HERE*/ return function_header + prefixIfNeeded(scopePrefix(unaliasedTypeDef), CifyName(unaliasedTypeDef->getDataRef()->symbol.getName())) +"__" + + //std::cout << "Doing function: " << name << std::endl; + //Test for special functions only if what we're testing is, indeed, the definition, not a function call that returns a callable function pointer + if (funcType == function) { + if (name == "++" || name == "--") + return generate(children[1], enclosingObject, true, enclosingFunction) + name; + if ( (name == "*" || name == "&" || name == "!" || name == "-" || name == "+" ) && children.size() == 2) //Is dereference, not multiplication, address-of, or other unary operator + return name + "(" + generate(children[1], enclosingObject, true, enclosingFunction) + ")"; + if (name == "[]") + return "(" + generate(children[1], enclosingObject, true, enclosingFunction) + ")[" + generate(children[2],enclosingObject, true, enclosingFunction) + "]"; + if (name == "+" || name == "-" || name == "*" || name == "/" || name == "==" || name == ">=" || name == "<=" || name == "!=" + || name == "<" || name == ">" || name == "%" || name == "=" || name == "+=" || name == "-=" || name == "*=" || name == "/=") { + return "((" + generate(children[1], enclosingObject, true, enclosingFunction) + ")" + name + "(" + generate(children[2], enclosingObject, true, enclosingFunction) + "))"; + } else if (name == "&&" || name == "||") { + // b/c short circuiting, these have to be done seperately + CCodeTriple lhs = generate(children[1], enclosingObject, true, enclosingFunction); + CCodeTriple rhs = generate(children[2], enclosingObject, true, enclosingFunction); + output.preValue = lhs.preValue; + std::string shortcircuit_result = "shortcircuit_result" + getID(); + output.preValue += "bool " + shortcircuit_result + " = " + lhs.value + ";\n"; + output.preValue += lhs.postValue; + output.preValue += "if (" + std::string(name == "||" ? "!":"") + shortcircuit_result + ") { \n"; + output.preValue += rhs.preValue; + output.preValue += shortcircuit_result + " = " + rhs.value + ";\n"; + output.preValue += rhs.postValue; + output.preValue += "}\n"; + output.value = shortcircuit_result; + return output; + } else if (name == "." || name == "->") { + if (children.size() == 1) + return "/*dot operation with one child*/" + generate(children[0], enclosingObject, true, enclosingFunction).oneString() + "/*end one child*/"; + //If this is accessing an actual function, find the function in scope and take the appropriate action. Probabally an object method + if (children[2]->getDataRef()->type == function) { + 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) { + 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); + // Note that we only add scoping to the object, as this specifies our member function too + /*HERE*/ return function_header + prefixIfNeeded(scopePrefix(unaliasedTypeDef), CifyName(unaliasedTypeDef->getDataRef()->symbol.getName())) +"__" + CifyName(functionName + nameDecoration) + "(" + (name == "." ? "&" : "") + generate(children[1], enclosingObject, true, enclosingFunction) + ","; - //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 + //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, true, enclosingFunction) + ")" + name + functionName + ")"; + } } else { - //std::cout << "Is not in scope or not type" << std::endl; - return "((" + generate(children[1], enclosingObject, true, enclosingFunction) + ")" + name + functionName + ")"; + //std::cout << "Is not in scope or not type" << std::endl; + return "((" + generate(children[1], enclosingObject, true, enclosingFunction) + ")" + name + functionName + ")"; } } else { - //std::cout << "Is not in scope or not type" << std::endl; - return "((" + generate(children[1], enclosingObject, true, enclosingFunction) + ")" + name + functionName + ")"; - } - } else { - //return "((" + generate(children[1], enclosingObject, enclosingFunction) + ")" + name + generate(children[2], enclosingObject, enclosingFunction) + ")"; - return "((" + generate(children[1], enclosingObject, true, enclosingFunction) + ")" + name + generate(children[2], nullptr, true, enclosingFunction) + ")"; - } - } else { - // this could a closure literal. sigh, I know. - if (children[0]->getDataRef()->closedVariables.size()) { - functionCallSource = generate(children[0], enclosingObject, true, enclosingFunction); - doClosureInstead = true; + //return "((" + generate(children[1], enclosingObject, enclosingFunction) + ")" + name + generate(children[2], enclosingObject, enclosingFunction) + ")"; + return "((" + generate(children[1], enclosingObject, true, enclosingFunction) + ")" + name + generate(children[2], nullptr, true, enclosingFunction) + ")"; + } } else { - //It's a normal function call, not a special one or a method or anything. Name decorate. - std::vector*> functionDefChildren = children[0]->getChildren(); - //std::cout << "Decorating (none-special)" << name << " " << functionDefChildren.size() << std::endl; - std::string nameDecoration; - for (int i = 0; i < (functionDefChildren.size() > 0 ? functionDefChildren.size()-1 : 0); i++) - nameDecoration += "_" + ValueTypeToCTypeDecoration(functionDefChildren[i]->getData().valueType); - // it is possible that this is an object method from inside a closure - // in which case, recover the enclosing object from this - bool addClosedOver = false; - if (enclosingFunction && enclosingFunction->getDataRef()->closedVariables.size()) { - for (auto closedVar : enclosingFunction->getDataRef()->closedVariables) { - if (closedVar->getDataRef()->symbol.getName() == "this") { - enclosingObject = closedVar->getDataRef()->valueType->typeDefinition; - addClosedOver = true; + // this could a closure literal. sigh, I know. + if (children[0]->getDataRef()->closedVariables.size()) { + functionCallSource = generate(children[0], enclosingObject, true, enclosingFunction); + doClosureInstead = true; + } else { + //It's a normal function call, not a special one or a method or anything. Name decorate. + std::vector*> functionDefChildren = children[0]->getChildren(); + //std::cout << "Decorating (none-special)" << name << " " << functionDefChildren.size() << std::endl; + std::string nameDecoration; + for (int i = 0; i < (functionDefChildren.size() > 0 ? functionDefChildren.size()-1 : 0); i++) + nameDecoration += "_" + ValueTypeToCTypeDecoration(functionDefChildren[i]->getData().valueType); + // it is possible that this is an object method from inside a closure + // in which case, recover the enclosing object from this + bool addClosedOver = false; + if (enclosingFunction && enclosingFunction->getDataRef()->closedVariables.size()) { + for (auto closedVar : enclosingFunction->getDataRef()->closedVariables) { + if (closedVar->getDataRef()->symbol.getName() == "this") { + enclosingObject = closedVar->getDataRef()->valueType->typeDefinition; + addClosedOver = true; + } } } - } - //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 += function_header + prefixIfNeeded(scopePrefix(children[0]), CifyName(enclosingObject->getDataRef()->symbol.getName())) +"__"; - output += CifyName(name + nameDecoration) + "("; - output += std::string(addClosedOver ? "(*closed_variables->this)" : "this") + (children.size() > 1 ? "," : ""); - } else { - output += function_header + prefixIfNeeded(scopePrefix(children[0]), CifyName(name + nameDecoration)) + "("; + //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 += function_header + prefixIfNeeded(scopePrefix(children[0]), CifyName(enclosingObject->getDataRef()->symbol.getName())) +"__"; + output += CifyName(name + nameDecoration) + "("; + output += std::string(addClosedOver ? "(*closed_variables->this)" : "this") + (children.size() > 1 ? "," : ""); + } else { + output += function_header + prefixIfNeeded(scopePrefix(children[0]), CifyName(name + nameDecoration)) + "("; + } } } - } - } else { - //This part handles cases where our definition isn't the function definition (that is, it is probabally the return from another function) - //It's probabally the result of an access function call (. or ->) to access an object method. - //OR a function value! - // - //THIS IS UUUUUGLLYYY too. We moved the closure part out to after the generation of the params becuase it needs to use them twice - functionCallSource = generate(children[0], enclosingObject, true, enclosingFunction); - if (functionCallSource.value[functionCallSource.value.size()-1] == ',') //If it's a member method, it's already started the parameter list. - output += children.size() > 1 ? functionCallSource : CCodeTriple(functionCallSource.preValue, functionCallSource.value.substr(0, functionCallSource.value.size()-1), functionCallSource.postValue); - else { - doClosureInstead = true; - } - } - CCodeTriple parameters; - // see if we should copy_construct / referencize all the parameters - for (int i = 1; i < children.size(); i++) { //children[0] is the declaration - Type* func_param_type = children[0]->getDataRef()->valueType->parameterTypes[i-1]; - // ok, if our param is a reference returned by another function, we don't actually want this type to be a reference if it is now. - Type *param_type = children[i]->getDataRef()->valueType->withoutReference(); - // don't copy_construct references - if (func_param_type->is_reference) { - parameters += "&" + generate(children[i], enclosingObject, true, enclosingFunction); - } else if (methodExists(children[i]->getDataRef()->valueType, "copy_construct", std::vector{param_type->withIncreasedIndirection()})) { - std::string tmpParamName = "param" + getID(); - CCodeTriple paramValue = generate(children[i], enclosingObject, true, enclosingFunction); - parameters.preValue += paramValue.preValue; - parameters.preValue += ValueTypeToCType(param_type, tmpParamName) + ";\n"; - parameters.preValue += generateMethodIfExists(param_type, "copy_construct", "&"+tmpParamName + ", &" + paramValue.value, std::vector{children[i]->getDataRef()->valueType->withIncreasedIndirection()}); - parameters.value += tmpParamName; - parameters.postValue += paramValue.postValue; } else { - parameters += generate(children[i], enclosingObject, true, enclosingFunction); + //This part handles cases where our definition isn't the function definition (that is, it is probabally the return from another function) + //It's probabally the result of an access function call (. or ->) to access an object method. + //OR a function value! + // + //THIS IS UUUUUGLLYYY too. We moved the closure part out to after the generation of the params becuase it needs to use them twice + functionCallSource = generate(children[0], enclosingObject, true, enclosingFunction); + if (functionCallSource.value[functionCallSource.value.size()-1] == ',') //If it's a member method, it's already started the parameter list. + output += children.size() > 1 ? functionCallSource : CCodeTriple(functionCallSource.preValue, functionCallSource.value.substr(0, functionCallSource.value.size()-1), functionCallSource.postValue); + else { + doClosureInstead = true; + } } - if (i < children.size()-1) - parameters += ", "; - } - if (doClosureInstead) { - Type* funcType = children[0]->getDataRef()->valueType; - Type* retType = funcType->returnType; - bool doRet = retType->baseType != void_type || retType->getIndirection(); - std::string tmpName = "functionValueTmp" + getID(); - std::string retTmpName = "closureRetTemp" + getID(); - output += CCodeTriple(parameters.preValue + functionCallSource.preValue + ValueTypeToCType(funcType, tmpName) + " = " + functionCallSource.value + ";\n" - + (doRet ? ValueTypeToCType(retType, retTmpName) + ";\n" : "") - + "if (" + tmpName + ".data) { " + (doRet ? (retTmpName + " =") : "") + " (("+ ValueTypeToCTypeDecoration(funcType,ClosureFunctionPointerTypeWithClosedParam) +") (" + tmpName + ".func))(" + tmpName + ".data" + (children.size() > 1 ? ", " : "") + parameters.value + "); }\n" - + "else { " + (doRet ? (retTmpName + " = ") : "") + " (("+ ValueTypeToCTypeDecoration(funcType,ClosureFunctionPointerTypeWithoutClosedParam) +") (" + tmpName + ".func))(" + parameters.value + "); }\n", - (doRet ? retTmpName : ""), - parameters.postValue + functionCallSource.postValue); - } else { - output += parameters + ") "; - } - // see if we should add a destructer call to this postValue - Type* retType = children[0]->getDataRef()->valueType->returnType; - if (retType->baseType != void_type) { - // we always use return temps now :( (for psudo-pod objects that still have methods called on them, like range(1,3).for_each(...) - std::string retTempName = "return_temp" + getID(); - output.preValue += ValueTypeToCType(retType, retTempName) + " = " + output.value + ";\n"; - output.value = retTempName; - if (retType->is_reference) - output.value = "(*" + output.value + ")"; - else if (methodExists(retType, "destruct", std::vector())) { - output.postValue = generateMethodIfExists(retType, "destruct", "&"+retTempName, std::vector()) + ";\n" + output.postValue; + CCodeTriple parameters; + // see if we should copy_construct / referencize all the parameters + for (int i = 1; i < children.size(); i++) { //children[0] is the declaration + Type* func_param_type = children[0]->getDataRef()->valueType->parameterTypes[i-1]; + // ok, if our param is a reference returned by another function, we don't actually want this type to be a reference if it is now. + Type *param_type = children[i]->getDataRef()->valueType->withoutReference(); + // don't copy_construct references + if (func_param_type->is_reference) { + parameters += "&" + generate(children[i], enclosingObject, true, enclosingFunction); + } else if (methodExists(children[i]->getDataRef()->valueType, "copy_construct", std::vector{param_type->withIncreasedIndirection()})) { + std::string tmpParamName = "param" + getID(); + CCodeTriple paramValue = generate(children[i], enclosingObject, true, enclosingFunction); + parameters.preValue += paramValue.preValue; + parameters.preValue += ValueTypeToCType(param_type, tmpParamName) + ";\n"; + parameters.preValue += generateMethodIfExists(param_type, "copy_construct", "&"+tmpParamName + ", &" + paramValue.value, std::vector{children[i]->getDataRef()->valueType->withIncreasedIndirection()}); + parameters.value += tmpParamName; + parameters.postValue += paramValue.postValue; + } else { + parameters += generate(children[i], enclosingObject, true, enclosingFunction); + } + if (i < children.size()-1) + parameters += ", "; } + if (doClosureInstead) { + Type* funcType = children[0]->getDataRef()->valueType; + Type* retType = funcType->returnType; + bool doRet = retType->baseType != void_type || retType->getIndirection(); + std::string tmpName = "functionValueTmp" + getID(); + std::string retTmpName = "closureRetTemp" + getID(); + output += CCodeTriple(parameters.preValue + functionCallSource.preValue + ValueTypeToCType(funcType, tmpName) + " = " + functionCallSource.value + ";\n" + + (doRet ? ValueTypeToCType(retType, retTmpName) + ";\n" : "") + + "if (" + tmpName + ".data) { " + (doRet ? (retTmpName + " =") : "") + " (("+ ValueTypeToCTypeDecoration(funcType,ClosureFunctionPointerTypeWithClosedParam) +") (" + tmpName + ".func))(" + tmpName + ".data" + (children.size() > 1 ? ", " : "") + parameters.value + "); }\n" + + "else { " + (doRet ? (retTmpName + " = ") : "") + " (("+ ValueTypeToCTypeDecoration(funcType,ClosureFunctionPointerTypeWithoutClosedParam) +") (" + tmpName + ".func))(" + parameters.value + "); }\n", + (doRet ? retTmpName : ""), + parameters.postValue + functionCallSource.postValue); + } else { + output += parameters + ") "; + } + // see if we should add a destructer call to this postValue + Type* retType = children[0]->getDataRef()->valueType->returnType; + if (retType->baseType != void_type) { + // we always use return temps now :( (for psudo-pod objects that still have methods called on them, like range(1,3).for_each(...) + std::string retTempName = "return_temp" + getID(); + output.preValue += ValueTypeToCType(retType, retTempName) + " = " + output.value + ";\n"; + output.value = retTempName; + if (retType->is_reference) + output.value = "(*" + output.value + ")"; + else if (methodExists(retType, "destruct", std::vector())) { + output.postValue = generateMethodIfExists(retType, "destruct", "&"+retTempName, std::vector()) + ";\n" + output.postValue; + } + } + return output; } - return output; - } - case value: - { - // ok, we now check for it being a multiline string and escape all returns if it is (so that multiline strings work) - //if (data.symbol.getName()[0] == '"') { - if (data.symbol.getName()[0] == '"' && strSlice(data.symbol.getName(), 0, 3) == "\"\"\"") { - //bool multiline_str = strSlice(data.symbol.getName(), 0, 3) == "\"\"\""; - //std::string innerString = multiline_str - //? strSlice(data.symbol.getName(), 3, -4) - //: strSlice(data.symbol.getName(), 1, -2); - std::string innerString = strSlice(data.symbol.getName(), 3, -4); - std::string newStr; - for (auto character: innerString) - if (character == '\n') - newStr += "\\n"; - else if (character == '"') - newStr += "\\\""; - else - newStr += character; - return "\"" + newStr + "\""; + case value: + { + // ok, we now check for it being a multiline string and escape all returns if it is (so that multiline strings work) + //if (data.symbol.getName()[0] == '"') { + if (data.symbol.getName()[0] == '"' && strSlice(data.symbol.getName(), 0, 3) == "\"\"\"") { + //bool multiline_str = strSlice(data.symbol.getName(), 0, 3) == "\"\"\""; + //std::string innerString = multiline_str + //? strSlice(data.symbol.getName(), 3, -4) + //: strSlice(data.symbol.getName(), 1, -2); + std::string innerString = strSlice(data.symbol.getName(), 3, -4); + std::string newStr; + for (auto character: innerString) + if (character == '\n') + newStr += "\\n"; + else if (character == '"') + newStr += "\\\""; + else + newStr += character; + return "\"" + newStr + "\""; + } + return data.symbol.getName(); } - return data.symbol.getName(); - } - default: - std::cout << "Nothing!" << std::endl; - } - for (int i = 0; i < children.size(); i++) - output += generate(children[i], enclosingObject, justFuncName, enclosingFunction).oneString(); + default: + std::cout << "Nothing!" << std::endl; + } + for (int i = 0; i < children.size(); i++) + output += generate(children[i], enclosingObject, justFuncName, enclosingFunction).oneString(); - return output; + return output; } NodeTree* CGenerator::getMethodsObjectType(NodeTree* scope, std::string functionName) { //check the thing @@ -911,24 +919,24 @@ NodeTree* CGenerator::getMethodsObjectType(NodeTree* scope, st 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(); - std::vector*> children = from->getChildren(); - std::string nameDecoration, parameters; + 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(); + std::vector*> children = from->getChildren(); + std::string nameDecoration, parameters; if (!children.size()) { //problem std::cerr << " no children " << std::endl; } - 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); + 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, function_header + prefixIfNeeded(scopePrefix(from), CifyName(enclosingObject->getDataRef()->symbol.getName())) + "__" + - CifyName(data.symbol.getName()) + nameDecoration) + "(" + ValueTypeToCType(&enclosingObjectType, "this") + parameters + ")"; + 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 // @@ -1015,16 +1023,16 @@ std::string CGenerator::closureStructType(std::set*> closedVar std::string CGenerator::ValueTypeToCType(Type *type, std::string declaration, ClosureTypeSpecialType closureSpecial) { return ValueTypeToCTypeThingHelper(type, " " + declaration, closureSpecial); } std::string CGenerator::ValueTypeToCTypeDecoration(Type *type, ClosureTypeSpecialType closureSpecial) { return CifyName(ValueTypeToCTypeThingHelper(type, "", closureSpecial)); } std::string CGenerator::ValueTypeToCTypeThingHelper(Type *type, std::string declaration, ClosureTypeSpecialType closureSpecial) { - std::string return_type; + std::string return_type; bool do_ending = true; - switch (type->baseType) { - case none: - if (type->typeDefinition) - return_type = prefixIfNeeded(scopePrefix(type->typeDefinition), CifyName(type->typeDefinition->getDataRef()->symbol.getName())); - else - return_type = "none"; - break; - case function_type: + switch (type->baseType) { + case none: + if (type->typeDefinition) + return_type = prefixIfNeeded(scopePrefix(type->typeDefinition), CifyName(type->typeDefinition->getDataRef()->symbol.getName())); + else + return_type = "none"; + break; + case function_type: { std::string indr_str; for (int i = 0; i < type->getIndirection(); i++) @@ -1080,90 +1088,90 @@ std::string CGenerator::ValueTypeToCTypeThingHelper(Type *type, std::string decl } do_ending = false; } - break; - case void_type: - return_type = "void"; - break; - case boolean: - return_type = "bool"; - break; - case integer: - return_type = "int"; - break; - case floating: - return_type = "float"; - break; - case double_percision: - return_type = "double"; - break; - case character: - return_type = "char"; - break; - default: - return_type = "unknown_ValueType"; - break; - } + break; + case void_type: + return_type = "void"; + break; + case boolean: + return_type = "bool"; + break; + case integer: + return_type = "int"; + break; + case floating: + return_type = "float"; + break; + case double_percision: + return_type = "double"; + break; + case character: + return_type = "char"; + break; + default: + return_type = "unknown_ValueType"; + break; + } if (!do_ending) return return_type; - for (int i = 0; i < type->getIndirection(); i++) - return_type += "*"; + for (int i = 0; i < type->getIndirection(); i++) + return_type += "*"; if (type->is_reference) - return_type += " /*ref*/ *"; + return_type += " /*ref*/ *"; return return_type + declaration; } std::string CGenerator::CifyName(std::string name) { - std::string operatorsToReplace[] = { "+", "plus", - "-", "minus", - "*", "star", - "/", "div", - "%", "mod", - "^", "carat", - "&", "amprsd", - "|", "pipe", - "~", "tilde", - "!", "exlmtnpt", - ",", "comma", - "=", "eq", - "++", "dbplus", - "--", "dbminus", - "<<", "dbleft", - ">>", "dbright", - "::", "scopeop", - ":", "colon", - "==", "dbq", - "!=", "notequals", - "&&", "doubleamprsnd", - "||", "doublepipe", - "+=", "plusequals", - "-=", "minusequals", - "/=", "divequals", - "%=", "modequals", - "^=", "caratequals", - "&=", "amprsdequals", - "|=", "pipeequals", - "*=", "starequals", - "<<=", "doublerightequals", - "<", "lt", - ">", "gt", - ">>=", "doubleleftequals", - "(", "openparen", - ")", "closeparen", - "[", "obk", - "]", "cbk", - " ", "space", - ".", "dot", - "->", "arrow" }; - int length = sizeof(operatorsToReplace)/sizeof(std::string); - //std::cout << "Length is " << length << std::endl; - for (int i = 0; i < length; i+= 2) { - size_t foundPos = name.find(operatorsToReplace[i]); - while(foundPos != std::string::npos) { - name = strSlice(name, 0, foundPos) + "_" + operatorsToReplace[i+1] + "_" + strSlice(name, foundPos+operatorsToReplace[i].length(), -1); - foundPos = name.find(operatorsToReplace[i]); - } - } - return name; + std::string operatorsToReplace[] = { "+", "plus", + "-", "minus", + "*", "star", + "/", "div", + "%", "mod", + "^", "carat", + "&", "amprsd", + "|", "pipe", + "~", "tilde", + "!", "exlmtnpt", + ",", "comma", + "=", "eq", + "++", "dbplus", + "--", "dbminus", + "<<", "dbleft", + ">>", "dbright", + "::", "scopeop", + ":", "colon", + "==", "dbq", + "!=", "notequals", + "&&", "doubleamprsnd", + "||", "doublepipe", + "+=", "plusequals", + "-=", "minusequals", + "/=", "divequals", + "%=", "modequals", + "^=", "caratequals", + "&=", "amprsdequals", + "|=", "pipeequals", + "*=", "starequals", + "<<=", "doublerightequals", + "<", "lt", + ">", "gt", + ">>=", "doubleleftequals", + "(", "openparen", + ")", "closeparen", + "[", "obk", + "]", "cbk", + " ", "space", + ".", "dot", + "->", "arrow" }; + int length = sizeof(operatorsToReplace)/sizeof(std::string); + //std::cout << "Length is " << length << std::endl; + for (int i = 0; i < length; i+= 2) { + size_t foundPos = name.find(operatorsToReplace[i]); + while(foundPos != std::string::npos) { + name = strSlice(name, 0, foundPos) + "_" + operatorsToReplace[i+1] + "_" + strSlice(name, foundPos+operatorsToReplace[i].length(), -1); + foundPos = name.find(operatorsToReplace[i]); + } + } + return name; } // Generate the scope prefix, that is "file_class_" for a method, etc // What do we still need to handle? Packages! But we don't have thoes yet.... diff --git a/src/Type.cpp b/src/Type.cpp index 3da76a6..a9d3029 100644 --- a/src/Type.cpp +++ b/src/Type.cpp @@ -199,7 +199,7 @@ std::string Type::toString(bool showTraits) { if (is_reference) typeString = "ref " + typeString; for (int i = 0; i < indirection; i++) - typeString = "*" + typeString; + typeString += "*"; if (indirection < 0) typeString += "negative indirection: " + intToString(indirection); if (traits.size() && showTraits) { @@ -240,6 +240,11 @@ Type Type::withIncreasedIndirection() { newOne->increaseIndirection(); return *newOne; } +Type *Type::withIncreasedIndirectionPtr() { + Type *newOne = clone(); + newOne->increaseIndirection(); + return newOne; +} Type Type::withDecreasedIndirection() { Type *newOne = clone(); newOne->decreaseIndirection(); diff --git a/tests/test_adt.krak b/tests/test_adt.krak index 9846883..b82a570 100644 --- a/tests/test_adt.krak +++ b/tests/test_adt.krak @@ -1,4 +1,4 @@ -import io:* +/*import io:**/ adt options { option0, @@ -11,12 +11,13 @@ adt maybe_int { } fun handle_possibility(it: maybe_int) { - if (it == maybe_int::no_int()) - println("no int") + if (it == maybe_int::no_int()) { + /*println("no int")*/ + } /*if (it == maybe_int::an_int) {*/ else { - print("an int: ") - println(it.an_int) + /*print("an int: ")*/ + /*println(it.an_int)*/ } } @@ -32,10 +33,12 @@ fun can_pass(it: options): options { fun main():int { var it: options = can_pass(options::option0()) - if (it == options::option0()) - println("nope") - if (it == options::option1()) - println("option1") + if (it == options::option0()) { + /*println("nope")*/ + } + if (it == options::option1()) { + /*println("option1")*/ + } var possibility = give_maybe(false) handle_possibility(possibility)