diff --git a/include/ASTTransformation.h b/include/ASTTransformation.h index dd87356..bbf367b 100644 --- a/include/ASTTransformation.h +++ b/include/ASTTransformation.h @@ -43,6 +43,7 @@ class ASTTransformation: public NodeTransformation { NodeTree* transform(NodeTree* from, NodeTree* scope, std::vector types, std::map templateTypeReplacements); std::vector*> transformChildren(std::vector*> children, std::set skipChildren, NodeTree* scope, std::vector types, std::map templateTypeReplacements); std::vector mapNodesToTypes(std::vector*> nodes); + std::vector mapNodesToTypePointers(std::vector*> nodes); std::string concatSymbolTree(NodeTree* root); NodeTree* doFunction(NodeTree* scope, std::string lookup, std::vector*> nodes, std::map templateTypeReplacements); diff --git a/include/CGenerator.h b/include/CGenerator.h index 8c8a91d..eb2eaed 100644 --- a/include/CGenerator.h +++ b/include/CGenerator.h @@ -26,9 +26,9 @@ class CGenerator { bool isUnderTranslationUnit(NodeTree* from, NodeTree* typeDefinition); NodeTree* highestScope(NodeTree* node); std::pair generateTranslationUnit(std::string name, std::map*> ASTs); - std::string generate(NodeTree* from, NodeTree* enclosingObject = NULL); + std::string generate(NodeTree* from, NodeTree* enclosingObject = NULL, bool justFuncName = false); std::string generateAliasChains(std::map*> ASTs, NodeTree* definition); - static std::string ValueTypeToCType(Type *type); + static std::string ValueTypeToCType(Type *type, std::string); static std::string ValueTypeToCTypeDecoration(Type *type); static std::string ValueTypeToCTypeThingHelper(Type *type, std::string ptrStr); static std::string CifyName(std::string name); diff --git a/include/Type.h b/include/Type.h index a47fa7b..82aeb1a 100644 --- a/include/Type.h +++ b/include/Type.h @@ -14,7 +14,7 @@ class ASTData; #include "ASTData.h" #include "util.h" -enum ValueType {none, template_type, template_type_type, void_type, boolean, integer, floating, double_percision, character }; +enum ValueType {none, template_type, template_type_type, void_type, boolean, integer, floating, double_percision, character, function_type }; class Type { @@ -25,6 +25,8 @@ class Type { Type(NodeTree* typeDefinitionIn, int indirectionIn = 0); Type(NodeTree* typeDefinitionIn, std::set traitsIn); Type(ValueType typeIn, NodeTree* typeDefinitionIn, int indirectionIn, std::set traitsIn); + Type(ValueType typeIn, NodeTree* typeDefinitionIn, int indirectionIn, std::set traitsIn, std::vector parameterTypesIn, Type* returnTypeIn); + Type(std::vector parameterTypesIn, Type* returnTypeIn); Type(ValueType typeIn, NodeTree* templateDefinitionIn, std::set traitsIn = std::set()); ~Type(); bool const operator==(const Type &other)const; @@ -42,6 +44,8 @@ class Type { NodeTree* templateDefinition; std::map templateTypeReplacement; std::set traits; + std::vector parameterTypes; + Type *returnType; private: int indirection; }; diff --git a/src/ASTTransformation.cpp b/src/ASTTransformation.cpp index a746695..5d1f6bc 100644 --- a/src/ASTTransformation.cpp +++ b/src/ASTTransformation.cpp @@ -259,13 +259,9 @@ NodeTree* ASTTransformation::secondPassFunction(NodeTree* from, //We only do the parameter nodes. We don't do the body yet, as this is the secondPass auto transChildren = transformChildren(slice(children,1,-3, 2), std::set(), functionDef, std::vector(), templateTypeReplacements); - // std::cout << "REGULAR function " << functionName << " has " << transChildren.size() << " parameters: "; - // for (auto i : transChildren) - // std::cout << "||" << i->getDataRef()->toString() << "|| "; - // std::cout << "DoneList" << std::endl; - - functionDef->addChildren(transChildren); + // Swap the function type over to be the correct type (a function with parameter and return types, etc) + functionDef->getDataRef()->valueType = new Type(mapNodesToTypePointers(transChildren), functionDef->getDataRef()->valueType); return functionDef; } @@ -351,7 +347,6 @@ NodeTree* ASTTransformation::searchScopeForFunctionDef(NodeTree* from, NodeTree* functionDef, std::map templateTypeReplacements) { - //NodeTree* codeBlock = from->getChildren()[from->getChildren().size()-1]; NodeTree* codeBlock = from->getChildren().back(); functionDef->addChild(transform(codeBlock, functionDef, std::vector(), templateTypeReplacements)); } @@ -386,7 +381,7 @@ NodeTree* ASTTransformation::transform(NodeTree* from, NodeTree // pass NodeTree* perenOp = functionLookup(typeDefinition, "operator", types); if (perenOp) { - NodeTree* dotFunctionCall = new NodeTree(".", ASTData(function_call, Symbol(".", true))); + NodeTree* dotFunctionCall = new NodeTree(".", ASTData(function_call, Symbol(".", true), perenOp->getDataRef()->valueType)); dotFunctionCall->addChild(languageLevelOperators["."][0]); //function definition dotFunctionCall->addChild(possibleObj); // The object whose method we're calling dotFunctionCall->addChild(perenOp); //The method we're calling @@ -440,9 +435,6 @@ NodeTree* ASTTransformation::transform(NodeTree* from, NodeTree } newNode->getDataRef()->valueType = objectType; //Type is self-referential since this is the definition } - // ?? why not this? - //scope->getDataRef()->scope[typeAlias].push_back(newNode); - //newNode->getDataRef()->scope["~enclosing_scope"].push_back(scope); addToScope("~enclosing_scope", scope, newNode); @@ -477,21 +469,18 @@ NodeTree* ASTTransformation::transform(NodeTree* from, NodeTree for (auto child: children) std::cout << "Function child: " << child->getDataRef()->toString() << std::endl; newNode = new NodeTree(name, ASTData(function, Symbol(functionName, true), typeFromTypeNode(children[children.size()-2], scope, templateTypeReplacements))); - skipChildren.insert(0); - skipChildren.insert(children.size()-1); addToScope(functionName, newNode, scope); addToScope("~enclosing_scope", scope, newNode); scope = newNode; - // auto transChildren = transformChildren(children, skipChildren, scope, types); - // std::cout << functionName << " "; - // for (auto i : transChildren) - // std::cout << "||" << i->getDataRef()->toString() << "|| "; - // std::cout << "??||" << std::endl; - // newNode->addChildren(transChildren); - // return newNode; + auto parameters = transformChildren(getNodes("typed_parameter", children), skipChildren, scope, types, templateTypeReplacements); + newNode->addChildren(parameters); + // update type with actual type + newNode->getDataRef()->valueType = new Type(mapNodesToTypePointers(parameters), newNode->getDataRef()->valueType); + newNode->addChild(transform(getNode("code_block", children), scope, types, templateTypeReplacements)); + std::cout << "finished function" << functionName << std::endl; + return newNode; - std::cout << "finished function (kinda, not children) " << functionName << std::endl; } else if (name == "code_block") { newNode = new NodeTree(name, ASTData(code_block)); addToScope("~enclosing_scope", scope, newNode); @@ -519,11 +508,7 @@ NodeTree* ASTTransformation::transform(NodeTree* from, NodeTree throw "LOOKUP ERROR: " + functionCallString; } newNode = function; - // newNode = new NodeTree(functionCallString, ASTData(function_call, function->getDataRef()->valueType)); - // newNode->addChild(function); // First child of function call is a link to the function - // newNode->addChildren(transformedChildren); } else { - //std::cout << children.size() << std::endl; // XXX What the heck is this if (children.size() == 0) return new NodeTree(); @@ -591,7 +576,6 @@ NodeTree* ASTTransformation::transform(NodeTree* from, NodeTree return transform(children[0], scope, types, templateTypeReplacements); //Just a promoted child, so do it instead } } else if (name == "statement") { - //XXX newNode = new NodeTree(name, ASTData(statement)); } else if (name == "if_statement") { newNode = new NodeTree(name, ASTData(if_statement)); @@ -688,13 +672,11 @@ NodeTree* ASTTransformation::transform(NodeTree* from, NodeTree } else if (name == "if_comp") { newNode = new NodeTree(name, ASTData(if_comp)); newNode->addChild(addToScope("~enclosing_scope", scope, new NodeTree("identifier", ASTData(identifier, Symbol(concatSymbolTree(children[0]),true))))); - std::cout << "XXX scope is " << scope << std::endl; addToScope("~enclosing_scope", scope, newNode); skipChildren.insert(0); //Don't do the identifier. The identifier lookup will fail. That's why we do it here. } else if (name == "simple_passthrough") { newNode = new NodeTree(name, ASTData(simple_passthrough)); addToScope("~enclosing_scope", scope, newNode); - std::cout << "XXX scope is " << scope << std::endl; } else if (name == "passthrough_params") { newNode = new NodeTree(name, ASTData(passthrough_params)); addToScope("~enclosing_scope", scope, newNode); @@ -726,7 +708,8 @@ NodeTree* ASTTransformation::transform(NodeTree* from, NodeTree std::cout << i->getName() << " "; std::cout << std::endl; newNode->addChild(function); - newNode->getDataRef()->valueType = function->getDataRef()->valueType; + // note that we now get the return type from the function call's type + newNode->getDataRef()->valueType = function->getDataRef()->valueType->returnType; newNode->addChildren(transformedChildren); return newNode; } else if (name == "parameter") { @@ -790,6 +773,16 @@ std::vector*> ASTTransformation::transformChildren(std::vector return transformedChildren; } +//Extract types from already transformed nodes +std::vector ASTTransformation::mapNodesToTypePointers(std::vector*> nodes) { + std::vector types; + for (auto i : nodes) { + std::cout << i->getDataRef()->toString() << std::endl; + types.push_back((i->getDataRef()->valueType)); + } + return types; +} + //Extract types from already transformed nodes std::vector ASTTransformation::mapNodesToTypes(std::vector*> nodes) { std::vector types; @@ -831,7 +824,7 @@ NodeTree* ASTTransformation::doFunction(NodeTree* scope, std:: std::cout << "Early method level operator was found" << std::endl; //return operatorMethod; NodeTree* newNode = new NodeTree(lookupOp, ASTData(function_call, Symbol(lookupOp, true))); - NodeTree* dotFunctionCall = new NodeTree(".", ASTData(function_call, Symbol(".", true))); + NodeTree* dotFunctionCall = new NodeTree(".", ASTData(function_call, Symbol(".", true), operatorMethod->getDataRef()->valueType)); dotFunctionCall->addChild(languageLevelOperators["."][0]); //function definition dotFunctionCall->addChild(nodes[0]); // The object whose method we're calling dotFunctionCall->addChild(operatorMethod); //The method we're calling @@ -840,7 +833,7 @@ NodeTree* ASTTransformation::doFunction(NodeTree* scope, std:: //Set the value of this function call - newNode->getDataRef()->valueType = operatorMethod->getDataRef()->valueType; + newNode->getDataRef()->valueType = operatorMethod->getDataRef()->valueType->returnType; return newNode; } std::cout << "Early method level operator was NOT found" << std::endl; @@ -874,7 +867,9 @@ NodeTree* ASTTransformation::doFunction(NodeTree* scope, std:: newNode->getDataRef()->valueType = newType, std::cout << "Operator " + lookup << " is altering indirection from " << oldTypes[0].toString() << " to " << newType->toString() << std::endl; } else { - newNode->getDataRef()->valueType = function->getDataRef()->valueType, std::cout << "Some other ||" << lookup << "||" << std::endl; + std::cout << "Some other ||" << lookup << "||" << std::endl; + if (function->getDataRef()->valueType) + newNode->getDataRef()->valueType = function->getDataRef()->valueType->returnType; } // Set the value of this function call if it has not already been set @@ -1496,13 +1491,14 @@ NodeTree* ASTTransformation::findOrInstantiateFunctionTemplate(std::vec addToScope(fullyInstantiatedName, instantiatedFunction, templateTopScope); templateTopScope->addChild(instantiatedFunction); // Add this object the the highest scope's - std::set skipChildren; - skipChildren.insert(0); - skipChildren.insert(1); - skipChildren.insert(templateSyntaxTree->getChildren().size()-3); - skipChildren.insert(templateSyntaxTree->getChildren().size()-2); std::cout << "About to do children of " << functionName << " to " << fullyInstantiatedName << std::endl; - instantiatedFunction->addChildren(transformChildren(templateSyntaxTree->getChildren(), skipChildren, instantiatedFunction, std::vector(), newTemplateTypeReplacement)); + + std::set skipChildren; + auto parameters = transformChildren(getNodes("typed_parameter", templateSyntaxTree->getChildren()), skipChildren, instantiatedFunction, std::vector(), newTemplateTypeReplacement); + instantiatedFunction->addChildren(parameters); + // update type with actual type + instantiatedFunction->getDataRef()->valueType = new Type(mapNodesToTypePointers(parameters), instantiatedFunction->getDataRef()->valueType); + instantiatedFunction->addChild(transform(getNode("code_block", templateSyntaxTree->getChildren()), instantiatedFunction, std::vector(), newTemplateTypeReplacement)); std::cout << "Fully Instantiated function " << functionName << " to " << fullyInstantiatedName << std::endl; return instantiatedFunction; diff --git a/src/CGenerator.cpp b/src/CGenerator.cpp index 2894780..c9e7e14 100644 --- a/src/CGenerator.cpp +++ b/src/CGenerator.cpp @@ -174,8 +174,8 @@ std::pair CGenerator::generateTranslationUnit(std::str ASTData declarationData = declaration->getData(); switch(declarationData.type) { case identifier: - variableDeclarations += ValueTypeToCType(declarationData.valueType) + " " + scopePrefix(declaration) + declarationData.symbol.getName() + "; /*identifier*/\n"; - variableExternDeclarations += "extern " + ValueTypeToCType(declarationData.valueType) + " " + declarationData.symbol.getName() + "; /*extern identifier*/\n"; + variableDeclarations += ValueTypeToCType(declarationData.valueType, scopePrefix(declaration) + declarationData.symbol.getName()) + "; /*identifier*/\n"; + variableExternDeclarations += "extern " + ValueTypeToCType(declarationData.valueType, declarationData.symbol.getName()) + "; /*extern identifier*/\n"; break; case function: { @@ -184,16 +184,15 @@ std::pair CGenerator::generateTranslationUnit(std::str else if (decChildren.size() == 0) //Not a real function, must be a built in passthrough functionPrototypes += "/* built in function: " + declarationData.symbol.toString() + " */\n"; else { - functionPrototypes += "\n" + ValueTypeToCType(declarationData.valueType) + " "; std::string nameDecoration, parameters; for (int j = 0; j < decChildren.size()-1; j++) { if (j > 0) parameters += ", "; - parameters += ValueTypeToCType(decChildren[j]->getData().valueType) + " " + generate(decChildren[j], nullptr); + parameters += ValueTypeToCType(decChildren[j]->getData().valueType, generate(decChildren[j], nullptr)); nameDecoration += "_" + ValueTypeToCTypeDecoration(decChildren[j]->getData().valueType); } - functionPrototypes += ((declarationData.symbol.getName() == "main") ? "" : scopePrefix(declaration)) + - CifyName(declarationData.symbol.getName() + nameDecoration) + + functionPrototypes += "\n" + ValueTypeToCType(declarationData.valueType->returnType, ((declarationData.symbol.getName() == "main") ? "" : scopePrefix(declaration)) + + CifyName(declarationData.symbol.getName() + nameDecoration)) + "(" + parameters + "); /*func*/\n"; // generate function std::cout << "Generating " << scopePrefix(declaration) + @@ -212,9 +211,9 @@ std::pair CGenerator::generateTranslationUnit(std::str if (declarationData.valueType->typeDefinition) continue; // Aliases of objects are done with the thing it alises // Otherwise, we're actually a renaming of a primitive, can generate here - plainTypedefs += "typedef " + ValueTypeToCType(declarationData.valueType) + " " + + plainTypedefs += "typedef " + ValueTypeToCType(declarationData.valueType, scopePrefix(declaration) + - CifyName(declarationData.symbol.getName()) + ";\n"; + CifyName(declarationData.symbol.getName())) + ";\n"; plainTypedefs += generateAliasChains(ASTs, declaration); } else { plainTypedefs += "typedef struct __struct_dummy_" + @@ -249,7 +248,7 @@ std::pair CGenerator::generateTranslationUnit(std::str } //The enclosing object is for when we're generating the inside of object methods. They allow us to check scope lookups against the object we're in -std::string CGenerator::generate(NodeTree* from, NodeTree* enclosingObject) { +std::string CGenerator::generate(NodeTree* from, NodeTree* enclosingObject, bool justFuncName) { ASTData data = from->getData(); std::vector*> children = from->getChildren(); std::string output; @@ -288,17 +287,18 @@ std::string CGenerator::generate(NodeTree* from, NodeTree* enc { if (data.valueType->baseType == template_type) return "/* template function: " + data.symbol.getName() + " */"; - output += "\n" + ValueTypeToCType(data.valueType) + " "; std::string nameDecoration, parameters; for (int j = 0; j < children.size()-1; j++) { if (j > 0) parameters += ", "; - parameters += ValueTypeToCType(children[j]->getData().valueType) + " " + generate(children[j], enclosingObject); + parameters += ValueTypeToCType(children[j]->getData().valueType, generate(children[j], enclosingObject, justFuncName)); nameDecoration += "_" + ValueTypeToCTypeDecoration(children[j]->getData().valueType); } - - output += ((data.symbol.getName() == "main") ? "" : scopePrefix(from)) + - CifyName(data.symbol.getName() + nameDecoration) + "(" + parameters + ")\n" + generate(children[children.size()-1], enclosingObject); + // this is for using functions as values + if (justFuncName) + return ((data.symbol.getName() == "main") ? "" : scopePrefix(from)) + CifyName(data.symbol.getName() + nameDecoration); + output += "\n" + ValueTypeToCType(data.valueType->returnType, ((data.symbol.getName() == "main") ? "" : scopePrefix(from)) + + CifyName(data.symbol.getName() + nameDecoration)) + "(" + parameters + ")\n" + generate(children[children.size()-1], enclosingObject, justFuncName); return output; } case code_block: @@ -308,10 +308,10 @@ std::string CGenerator::generate(NodeTree* from, NodeTree* enc // 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); + output += generate(children[i], enclosingObject, justFuncName); // 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); + output += generate(*iter, enclosingObject, justFuncName); deferDoubleStack.pop_back(); tabLevel--; output += tabs() + "}"; @@ -322,31 +322,31 @@ std::string CGenerator::generate(NodeTree* from, NodeTree* enc case boolean_expression: output += " " + data.symbol.getName() + " "; case statement: - return tabs() + generate(children[0], enclosingObject) + ";\n"; + return tabs() + generate(children[0], enclosingObject, justFuncName) + ";\n"; case if_statement: - output += "if (" + generate(children[0], enclosingObject) + ")\n\t"; + output += "if (" + generate(children[0], enclosingObject, true) + ")\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. if (children[1]->getChildren()[0]->getDataRef()->type == code_block) { std::cout << "Then statement is a block, emitting the block not the statement so no trailing semicolon" << std::endl; - output += generate(children[1]->getChildren()[0], enclosingObject); + output += generate(children[1]->getChildren()[0], enclosingObject, justFuncName); } else { // ALSO we always emit blocks now, to handle cases like defer when several statements need to be // run in C even though it is a single Kraken statement std::cout << "Then statement is a simple statement, regular emitting the statement so trailing semicolon" << std::endl; - output += "{ " + generate(children[1], enclosingObject) + " }"; + output += "{ " + generate(children[1], enclosingObject, justFuncName) + " }"; } // Always emit blocks here too if (children.size() > 2) - output += " else { " + generate(children[2], enclosingObject) + " }"; + output += " else { " + generate(children[2], enclosingObject, justFuncName) + " }"; return output; case while_loop: // 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()); - output += "while (" + generate(children[0], enclosingObject) + ")\n\t" + generate(children[1], enclosingObject); + output += "while (" + generate(children[0], enclosingObject, true) + ")\n\t" + generate(children[1], enclosingObject, justFuncName); // and pop it off again loopDeferStackDepth.pop(); return output; @@ -356,7 +356,7 @@ std::string CGenerator::generate(NodeTree* from, NodeTree* enc // 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) - output += "for (" + strSlice(generate(children[0], enclosingObject),0,-3) + generate(children[1], enclosingObject) + ";" + strSlice(generate(children[2], enclosingObject),0,-3) + ")\n\t" + generate(children[3], enclosingObject); + output += "for (" + strSlice(generate(children[0], enclosingObject, true),0,-3) + generate(children[1], enclosingObject, true) + ";" + strSlice(generate(children[2], enclosingObject, true),0,-3) + ")\n\t" + generate(children[3], enclosingObject, justFuncName); // and pop it off again loopDeferStackDepth.pop(); return output; @@ -365,43 +365,43 @@ std::string CGenerator::generate(NodeTree* from, NodeTree* enc // 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); + output += generate(*iter, enclosingObject, justFuncName); if (children.size()) - return "return " + generate(children[0], enclosingObject); + return "return " + generate(children[0], enclosingObject, true); else return "return"; 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++) - output += generate(*iter, enclosingObject); + output += generate(*iter, enclosingObject, justFuncName); return output + "break"; 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++) - output += generate(*iter, enclosingObject); + output += generate(*iter, enclosingObject, justFuncName); return output + "continue"; case defer_statement: deferDoubleStack.back().push_back(children[0]); - return "/*defer " + generate(children[0], enclosingObject) + "*/"; + return "/*defer " + generate(children[0], enclosingObject, justFuncName) + "*/"; case assignment_statement: - return generate(children[0], enclosingObject) + " = " + generate(children[1], enclosingObject); + return generate(children[0], enclosingObject, justFuncName) + " = " + generate(children[1], enclosingObject, true); case declaration_statement: if (children.size() == 1) - return ValueTypeToCType(children[0]->getData().valueType) + " " + generate(children[0], enclosingObject) + ";"; + return ValueTypeToCType(children[0]->getData().valueType, generate(children[0], enclosingObject, justFuncName)) + ";"; else if (children[1]->getChildren().size() && children[1]->getChildren()[0]->getChildren().size() > 1 && children[1]->getChildren()[0]->getChildren()[1] == children[0]) { //That is, if we're a declaration with an init position call (Object a.construct()) //We can tell if our function call (children[1])'s access operation([0])'s lhs ([1]) is the thing we just declared (children[0]) - return ValueTypeToCType(children[0]->getData().valueType) + " " + generate(children[0], enclosingObject) + "; " + generate(children[1]) + "/*Init Position Call*/"; + return ValueTypeToCType(children[0]->getData().valueType, generate(children[0], enclosingObject, justFuncName)) + "; " + generate(children[1]) + "/*Init Position Call*/"; } else - return ValueTypeToCType(children[0]->getData().valueType) + " " + generate(children[0], enclosingObject) + " = " + generate(children[1], enclosingObject) + ";"; + return ValueTypeToCType(children[0]->getData().valueType, generate(children[0], enclosingObject, justFuncName)) + " = " + generate(children[1], enclosingObject, true) + ";"; case if_comp: // Lol, this doesn't work because the string gets prefixed now //if (generate(children[0], enclosingObject) == generatorString) if (children[0]->getDataRef()->symbol.getName() == generatorString) - return generate(children[1], enclosingObject); + return generate(children[1], enclosingObject, justFuncName); return ""; case simple_passthrough: { @@ -414,17 +414,17 @@ std::string CGenerator::generate(NodeTree* from, NodeTree* enc for (auto assign : in_or_out->getChildren()) { auto assignChildren = assign->getChildren(); if (in_or_out->getDataRef()->type == in_passthrough_params) - pre_passthrough += ValueTypeToCType(assignChildren[0]->getDataRef()->valueType) + " " + assignChildren[1]->getDataRef()->symbol.getName() + " = " + generate(assignChildren[0], enclosingObject) + ";\n"; + pre_passthrough += ValueTypeToCType(assignChildren[0]->getDataRef()->valueType, assignChildren[1]->getDataRef()->symbol.getName()) + " = " + generate(assignChildren[0], enclosingObject) + ";\n"; else if (in_or_out->getDataRef()->type == out_passthrough_params) - post_passthrough += generate(assignChildren[0], enclosingObject) + " = " + assignChildren[1]->getDataRef()->symbol.getName() + ";\n"; + post_passthrough += generate(assignChildren[0], enclosingObject, justFuncName) + " = " + assignChildren[1]->getDataRef()->symbol.getName() + ";\n"; else - linkerString += " " + strSlice(generate(in_or_out, enclosingObject), 1, -2) + " "; + linkerString += " " + strSlice(generate(in_or_out, enclosingObject, justFuncName), 1, -2) + " "; } } } // The actual passthrough string is the last child now, as we might // have passthrough_params be the first child - return pre_passthrough + strSlice(generate(children.back(), enclosingObject), 3, -4) + post_passthrough; + return pre_passthrough + strSlice(generate(children.back(), enclosingObject, justFuncName), 3, -4) + post_passthrough; } case function_call: { @@ -440,19 +440,19 @@ std::string CGenerator::generate(NodeTree* from, NodeTree* enc //Test for specail 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) + name; + return generate(children[1], enclosingObject, true) + 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) + ")"; + return name + "(" + generate(children[1], enclosingObject, true) + ")"; if (name == "[]") - return "(" + generate(children[1], enclosingObject) + ")[" +generate(children[2],enclosingObject) + "]"; + 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 == "&&") { std::cout << "THIS IS IT NAME: " << name << std::endl; - return "((" + generate(children[1], enclosingObject) + ")" + name + "(" + generate(children[2], enclosingObject) + "))"; + return "((" + generate(children[1], enclosingObject, true) + ")" + name + "(" + generate(children[2], enclosingObject, true) + "))"; } else if (name == "." || name == "->") { if (children.size() == 1) - return "/*dot operation with one child*/" + generate(children[0], enclosingObject) + "/*end one child*/"; + return "/*dot operation with one child*/" + generate(children[0], enclosingObject, true) + "/*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(); @@ -468,20 +468,20 @@ std::string CGenerator::generate(NodeTree* from, NodeTree* enc nameDecoration += "_" + ValueTypeToCTypeDecoration(functionDefChildren[i]->getData().valueType); // Note that we only add scoping to the object, as this specifies our member function too /*HERE*/ return scopePrefix(unaliasedTypeDef) + CifyName(unaliasedTypeDef->getDataRef()->symbol.getName()) +"__" + - CifyName(functionName + nameDecoration) + "(" + (name == "." ? "&" : "") + generate(children[1], enclosingObject) + ","; + CifyName(functionName + nameDecoration) + "(" + (name == "." ? "&" : "") + generate(children[1], enclosingObject, true) + ","; //The comma lets the upper function call know we already started the param list //Note that we got here from a function call. We just pass up this special case and let them finish with the perentheses } else { std::cout << "Is not in scope or not type" << std::endl; - return "((" + generate(children[1], enclosingObject) + ")" + name + functionName + ")"; + return "((" + generate(children[1], enclosingObject, true) + ")" + name + functionName + ")"; } } else { std::cout << "Is not in scope or not type" << std::endl; - return "((" + generate(children[1], enclosingObject) + ")" + name + functionName + ")"; + return "((" + generate(children[1], enclosingObject, true) + ")" + name + functionName + ")"; } } else { //return "((" + generate(children[1], enclosingObject) + ")" + name + generate(children[2], enclosingObject) + ")"; - return "((" + generate(children[1], enclosingObject) + ")" + name + generate(children[2]) + ")"; + return "((" + generate(children[1], enclosingObject, true) + ")" + name + generate(children[2], nullptr, true) + ")"; } } else { //It's a normal function call, not a special one or a method or anything. Name decorate. @@ -503,7 +503,7 @@ std::string CGenerator::generate(NodeTree* from, NodeTree* enc } 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. - std::string functionCallSource = generate(children[0], enclosingObject); + std::string functionCallSource = generate(children[0], enclosingObject, true); if (functionCallSource[functionCallSource.size()-1] == ',') //If it's a member method, it's already started the parameter list. output += children.size() > 1 ? functionCallSource : functionCallSource.substr(0, functionCallSource.size()-1); else @@ -511,9 +511,9 @@ std::string CGenerator::generate(NodeTree* from, NodeTree* enc } for (int i = 1; i < children.size(); i++) //children[0] is the declaration if (i < children.size()-1) - output += generate(children[i], enclosingObject) + ", "; + output += generate(children[i], enclosingObject, true) + ", "; else - output += generate(children[i], enclosingObject); + output += generate(children[i], enclosingObject, true); output += ") "; return output; } @@ -524,7 +524,7 @@ std::string CGenerator::generate(NodeTree* from, NodeTree* enc std::cout << "Nothing!" << std::endl; } for (int i = 0; i < children.size(); i++) - output += generate(children[i], enclosingObject); + output += generate(children[i], enclosingObject, justFuncName); return output; } @@ -543,21 +543,21 @@ std::string CGenerator::generateObjectMethod(NodeTree* enclosingObject, std::vector*> children = from->getChildren(); std::string nameDecoration, parameters; for (int i = 0; i < children.size()-1; i++) { - parameters += ", " + ValueTypeToCType(children[i]->getData().valueType) + " " + generate(children[i]); + parameters += ", " + ValueTypeToCType(children[i]->getData().valueType, generate(children[i])); nameDecoration += "_" + ValueTypeToCTypeDecoration(children[i]->getData().valueType); } - std::string functionSignature = "\n" + ValueTypeToCType(data.valueType) + " " + scopePrefix(from) + CifyName(enclosingObject->getDataRef()->symbol.getName()) +"__" - + CifyName(data.symbol.getName()) + nameDecoration + "(" + ValueTypeToCType(&enclosingObjectType) - + " this" + parameters + ")"; + 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"; return functionSignature + "\n" + generate(children[children.size()-1], enclosingObject); //Pass in the object so we can properly handle access to member stuff } -std::string CGenerator::ValueTypeToCType(Type *type) { return ValueTypeToCTypeThingHelper(type, "*"); } -std::string CGenerator::ValueTypeToCTypeDecoration(Type *type) { return ValueTypeToCTypeThingHelper(type, "_P__"); } -std::string CGenerator::ValueTypeToCTypeThingHelper(Type *type, std::string ptrStr) { +std::string CGenerator::ValueTypeToCType(Type *type, std::string declaration) { return ValueTypeToCTypeThingHelper(type, " " + declaration); } +std::string CGenerator::ValueTypeToCTypeDecoration(Type *type) { return CifyName(ValueTypeToCTypeThingHelper(type, "")); } +std::string CGenerator::ValueTypeToCTypeThingHelper(Type *type, std::string declaration) { std::string return_type; + bool do_ending = true; switch (type->baseType) { case none: if (type->typeDefinition) @@ -565,6 +565,25 @@ std::string CGenerator::ValueTypeToCTypeThingHelper(Type *type, std::string ptrS else return_type = "none"; break; + case function_type: + { + std::string indr_str; + for (int i = 0; i < type->getIndirection(); i++) + indr_str += "*"; + return_type = ValueTypeToCTypeThingHelper(type->returnType, ""); + if (type->getIndirection()) + return_type += " (" + indr_str + "(*" + declaration + "))("; + else + return_type += " (*" + declaration + ")("; + if (type->parameterTypes.size() == 0) + return_type += "void"; + else + for (int i = 0; i < type->parameterTypes.size(); i++) + return_type += (i != 0 ? ", " : "") + ValueTypeToCTypeThingHelper(type->parameterTypes[i], ""); + return_type += ")"; + do_ending = false; + } + break; case void_type: return_type = "void"; break; @@ -587,9 +606,11 @@ std::string CGenerator::ValueTypeToCTypeThingHelper(Type *type, std::string ptrS return_type = "unknown_ValueType"; break; } + if (!do_ending) + return return_type; for (int i = 0; i < type->getIndirection(); i++) - return_type += ptrStr; - return return_type; + return_type += "*"; + return return_type + declaration; } std::string CGenerator::CifyName(std::string name) { @@ -610,6 +631,7 @@ std::string CGenerator::CifyName(std::string name) { "<<", "doubleleft", ">>", "doubleright", "::", "scopeop", + ":", "colon", "==", "doubleequals", "!=", "notequals", "&&", "doubleamprsnd", diff --git a/src/Type.cpp b/src/Type.cpp index a6988e6..19d2b3d 100644 --- a/src/Type.cpp +++ b/src/Type.cpp @@ -3,30 +3,30 @@ Type::Type() { indirection = 0; baseType = none; - typeDefinition = NULL; - templateDefinition = NULL; + typeDefinition = nullptr; + templateDefinition = nullptr; } Type::Type(ValueType typeIn, int indirectionIn) { indirection = indirectionIn; baseType = typeIn; - typeDefinition = NULL; - templateDefinition = NULL; + typeDefinition = nullptr; + templateDefinition = nullptr; } Type::Type(ValueType typeIn, std::set traitsIn) { indirection = 0; baseType = typeIn; traits = traitsIn; - typeDefinition = NULL; - templateDefinition = NULL; + typeDefinition = nullptr; + templateDefinition = nullptr; } Type::Type(NodeTree* typeDefinitionIn, int indirectionIn) { indirection = indirectionIn; baseType = none; typeDefinition = typeDefinitionIn; - templateDefinition = NULL; + templateDefinition = nullptr; } Type::Type(NodeTree* typeDefinitionIn, std::set traitsIn) { @@ -34,7 +34,7 @@ Type::Type(NodeTree* typeDefinitionIn, std::set traitsIn) baseType = none; typeDefinition = typeDefinitionIn; traits = traitsIn; - templateDefinition = NULL; + templateDefinition = nullptr; } Type::Type(ValueType typeIn, NodeTree* typeDefinitionIn, int indirectionIn, std::set traitsIn) { @@ -42,13 +42,31 @@ Type::Type(ValueType typeIn, NodeTree* typeDefinitionIn, int indirectio indirection = indirectionIn; typeDefinition = typeDefinitionIn; traits = traitsIn; - templateDefinition = NULL; + templateDefinition = nullptr; +} + +Type::Type(ValueType typeIn, NodeTree* typeDefinitionIn, int indirectionIn, std::set traitsIn, std::vector parameterTypesIn, Type* returnTypeIn) { + baseType = typeIn; + indirection = indirectionIn; + typeDefinition = typeDefinitionIn; + traits = traitsIn; + templateDefinition = nullptr; + parameterTypes = parameterTypesIn; + returnType = returnTypeIn; +} +Type::Type(std::vector parameterTypesIn, Type* returnTypeIn) { + baseType = function_type; + indirection = 0; + typeDefinition = nullptr; + templateDefinition = nullptr; + parameterTypes = parameterTypesIn; + returnType = returnTypeIn; } Type::Type(ValueType typeIn, NodeTree* templateDefinitionIn, std::set traitsIn) { indirection = 0; baseType = typeIn; - typeDefinition = NULL; + typeDefinition = nullptr; templateDefinition = templateDefinitionIn; traits = traitsIn; } @@ -98,6 +116,12 @@ std::string Type::toString(bool showTraits) { case character: typeString = "char"; break; + case function_type: + typeString = "function("; + for (Type *param : parameterTypes) + typeString += param->toString(); + typeString += "): " + returnType->toString(); + break; default: if (typeDefinition) typeString = typeDefinition->getDataRef()->symbol.getName(); @@ -117,7 +141,7 @@ std::string Type::toString(bool showTraits) { } Type* Type::clone() { - return new Type(baseType, typeDefinition, indirection, traits); + return new Type(baseType, typeDefinition, indirection, traits, parameterTypes, returnType); } int Type::getIndirection() { diff --git a/tests/test_functionsValues.expected_results b/tests/test_functionsValues.expected_results new file mode 100644 index 0000000..ec63514 --- /dev/null +++ b/tests/test_functionsValues.expected_results @@ -0,0 +1 @@ +9 diff --git a/tests/test_functionsValues.krak b/tests/test_functionsValues.krak new file mode 100644 index 0000000..4d17122 --- /dev/null +++ b/tests/test_functionsValues.krak @@ -0,0 +1,13 @@ +import io:* + +fun test(): void { + println(9) +} + +fun main(): int { + var val = test + val() + return 0 +} + +