Initial work for functions as values. Actually works, but you can't write out the type and thus can only declare function pointer variables with type inference.
This commit is contained in:
@@ -43,6 +43,7 @@ class ASTTransformation: public NodeTransformation<Symbol,ASTData> {
|
||||
NodeTree<ASTData>* transform(NodeTree<Symbol>* from, NodeTree<ASTData>* scope, std::vector<Type> types, std::map<std::string, Type*> templateTypeReplacements);
|
||||
std::vector<NodeTree<ASTData>*> transformChildren(std::vector<NodeTree<Symbol>*> children, std::set<int> skipChildren, NodeTree<ASTData>* scope, std::vector<Type> types, std::map<std::string, Type*> templateTypeReplacements);
|
||||
std::vector<Type> mapNodesToTypes(std::vector<NodeTree<ASTData>*> nodes);
|
||||
std::vector<Type*> mapNodesToTypePointers(std::vector<NodeTree<ASTData>*> nodes);
|
||||
std::string concatSymbolTree(NodeTree<Symbol>* root);
|
||||
NodeTree<ASTData>* doFunction(NodeTree<ASTData>* scope, std::string lookup, std::vector<NodeTree<ASTData>*> nodes, std::map<std::string, Type*> templateTypeReplacements);
|
||||
|
||||
|
||||
@@ -26,9 +26,9 @@ class CGenerator {
|
||||
bool isUnderTranslationUnit(NodeTree<ASTData>* from, NodeTree<ASTData>* typeDefinition);
|
||||
NodeTree<ASTData>* highestScope(NodeTree<ASTData>* node);
|
||||
std::pair<std::string, std::string> generateTranslationUnit(std::string name, std::map<std::string, NodeTree<ASTData>*> ASTs);
|
||||
std::string generate(NodeTree<ASTData>* from, NodeTree<ASTData>* enclosingObject = NULL);
|
||||
std::string generate(NodeTree<ASTData>* from, NodeTree<ASTData>* enclosingObject = NULL, bool justFuncName = false);
|
||||
std::string generateAliasChains(std::map<std::string, NodeTree<ASTData>*> ASTs, NodeTree<ASTData>* 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);
|
||||
|
||||
@@ -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<ASTData>* typeDefinitionIn, int indirectionIn = 0);
|
||||
Type(NodeTree<ASTData>* typeDefinitionIn, std::set<std::string> traitsIn);
|
||||
Type(ValueType typeIn, NodeTree<ASTData>* typeDefinitionIn, int indirectionIn, std::set<std::string> traitsIn);
|
||||
Type(ValueType typeIn, NodeTree<ASTData>* typeDefinitionIn, int indirectionIn, std::set<std::string> traitsIn, std::vector<Type*> parameterTypesIn, Type* returnTypeIn);
|
||||
Type(std::vector<Type*> parameterTypesIn, Type* returnTypeIn);
|
||||
Type(ValueType typeIn, NodeTree<Symbol>* templateDefinitionIn, std::set<std::string> traitsIn = std::set<std::string>());
|
||||
~Type();
|
||||
bool const operator==(const Type &other)const;
|
||||
@@ -42,6 +44,8 @@ class Type {
|
||||
NodeTree<Symbol>* templateDefinition;
|
||||
std::map<std::string, Type*> templateTypeReplacement;
|
||||
std::set<std::string> traits;
|
||||
std::vector<Type*> parameterTypes;
|
||||
Type *returnType;
|
||||
private:
|
||||
int indirection;
|
||||
};
|
||||
|
||||
@@ -259,13 +259,9 @@ NodeTree<ASTData>* ASTTransformation::secondPassFunction(NodeTree<Symbol>* 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<int>(), functionDef, std::vector<Type>(), 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<ASTData>* ASTTransformation::searchScopeForFunctionDef(NodeTree<ASTData
|
||||
//It is used in the third pass to finish things up
|
||||
//Note that it may instantiate class OR function templates, which need to be fully instantiated
|
||||
void ASTTransformation::thirdPassFunction(NodeTree<Symbol>* from, NodeTree<ASTData>* functionDef, std::map<std::string, Type*> templateTypeReplacements) {
|
||||
//NodeTree<Symbol>* codeBlock = from->getChildren()[from->getChildren().size()-1];
|
||||
NodeTree<Symbol>* codeBlock = from->getChildren().back();
|
||||
functionDef->addChild(transform(codeBlock, functionDef, std::vector<Type>(), templateTypeReplacements));
|
||||
}
|
||||
@@ -386,7 +381,7 @@ NodeTree<ASTData>* ASTTransformation::transform(NodeTree<Symbol>* from, NodeTree
|
||||
// pass
|
||||
NodeTree<ASTData>* perenOp = functionLookup(typeDefinition, "operator", types);
|
||||
if (perenOp) {
|
||||
NodeTree<ASTData>* dotFunctionCall = new NodeTree<ASTData>(".", ASTData(function_call, Symbol(".", true)));
|
||||
NodeTree<ASTData>* dotFunctionCall = new NodeTree<ASTData>(".", 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<ASTData>* ASTTransformation::transform(NodeTree<Symbol>* 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<ASTData>* ASTTransformation::transform(NodeTree<Symbol>* from, NodeTree
|
||||
for (auto child: children)
|
||||
std::cout << "Function child: " << child->getDataRef()->toString() << std::endl;
|
||||
newNode = new NodeTree<ASTData>(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<ASTData>(name, ASTData(code_block));
|
||||
addToScope("~enclosing_scope", scope, newNode);
|
||||
@@ -519,11 +508,7 @@ NodeTree<ASTData>* ASTTransformation::transform(NodeTree<Symbol>* from, NodeTree
|
||||
throw "LOOKUP ERROR: " + functionCallString;
|
||||
}
|
||||
newNode = function;
|
||||
// newNode = new NodeTree<ASTData>(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<ASTData>();
|
||||
@@ -591,7 +576,6 @@ NodeTree<ASTData>* ASTTransformation::transform(NodeTree<Symbol>* 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<ASTData>(name, ASTData(statement));
|
||||
} else if (name == "if_statement") {
|
||||
newNode = new NodeTree<ASTData>(name, ASTData(if_statement));
|
||||
@@ -688,13 +672,11 @@ NodeTree<ASTData>* ASTTransformation::transform(NodeTree<Symbol>* from, NodeTree
|
||||
} else if (name == "if_comp") {
|
||||
newNode = new NodeTree<ASTData>(name, ASTData(if_comp));
|
||||
newNode->addChild(addToScope("~enclosing_scope", scope, new NodeTree<ASTData>("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<ASTData>(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<ASTData>(name, ASTData(passthrough_params));
|
||||
addToScope("~enclosing_scope", scope, newNode);
|
||||
@@ -726,7 +708,8 @@ NodeTree<ASTData>* ASTTransformation::transform(NodeTree<Symbol>* 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<NodeTree<ASTData>*> ASTTransformation::transformChildren(std::vector
|
||||
return transformedChildren;
|
||||
}
|
||||
|
||||
//Extract types from already transformed nodes
|
||||
std::vector<Type*> ASTTransformation::mapNodesToTypePointers(std::vector<NodeTree<ASTData>*> nodes) {
|
||||
std::vector<Type*> 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<Type> ASTTransformation::mapNodesToTypes(std::vector<NodeTree<ASTData>*> nodes) {
|
||||
std::vector<Type> types;
|
||||
@@ -831,7 +824,7 @@ NodeTree<ASTData>* ASTTransformation::doFunction(NodeTree<ASTData>* scope, std::
|
||||
std::cout << "Early method level operator was found" << std::endl;
|
||||
//return operatorMethod;
|
||||
NodeTree<ASTData>* newNode = new NodeTree<ASTData>(lookupOp, ASTData(function_call, Symbol(lookupOp, true)));
|
||||
NodeTree<ASTData>* dotFunctionCall = new NodeTree<ASTData>(".", ASTData(function_call, Symbol(".", true)));
|
||||
NodeTree<ASTData>* dotFunctionCall = new NodeTree<ASTData>(".", 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<ASTData>* ASTTransformation::doFunction(NodeTree<ASTData>* 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<ASTData>* ASTTransformation::doFunction(NodeTree<ASTData>* 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<ASTData>* ASTTransformation::findOrInstantiateFunctionTemplate(std::vec
|
||||
addToScope(fullyInstantiatedName, instantiatedFunction, templateTopScope);
|
||||
templateTopScope->addChild(instantiatedFunction); // Add this object the the highest scope's
|
||||
|
||||
std::set<int> 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<Type>(), newTemplateTypeReplacement));
|
||||
|
||||
std::set<int> skipChildren;
|
||||
auto parameters = transformChildren(getNodes("typed_parameter", templateSyntaxTree->getChildren()), skipChildren, instantiatedFunction, std::vector<Type>(), 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<Type>(), newTemplateTypeReplacement));
|
||||
|
||||
std::cout << "Fully Instantiated function " << functionName << " to " << fullyInstantiatedName << std::endl;
|
||||
return instantiatedFunction;
|
||||
|
||||
@@ -174,8 +174,8 @@ std::pair<std::string, std::string> 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<std::string, std::string> 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<std::string, std::string> 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<std::string, std::string> 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<ASTData>* from, NodeTree<ASTData>* enclosingObject) {
|
||||
std::string CGenerator::generate(NodeTree<ASTData>* from, NodeTree<ASTData>* enclosingObject, bool justFuncName) {
|
||||
ASTData data = from->getData();
|
||||
std::vector<NodeTree<ASTData>*> children = from->getChildren();
|
||||
std::string output;
|
||||
@@ -288,17 +287,18 @@ std::string CGenerator::generate(NodeTree<ASTData>* from, NodeTree<ASTData>* 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<ASTData>* from, NodeTree<ASTData>* enc
|
||||
// we push on a new vector to hold deferred statements
|
||||
deferDoubleStack.push_back(std::vector<NodeTree<ASTData>*>());
|
||||
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<ASTData>* from, NodeTree<ASTData>* 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<ASTData>* from, NodeTree<ASTData>* 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<ASTData>* from, NodeTree<ASTData>* 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<ASTData>* from, NodeTree<ASTData>* 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<ASTData>* from, NodeTree<ASTData>* 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<ASTData>* from, NodeTree<ASTData>* 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<ASTData>* from, NodeTree<ASTData>* 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<ASTData>* from, NodeTree<ASTData>* 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<ASTData>* from, NodeTree<ASTData>* 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<ASTData>* enclosingObject,
|
||||
std::vector<NodeTree<ASTData>*> 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;
|
||||
}
|
||||
for (int i = 0; i < type->getIndirection(); i++)
|
||||
return_type += ptrStr;
|
||||
if (!do_ending)
|
||||
return return_type;
|
||||
for (int i = 0; i < type->getIndirection(); i++)
|
||||
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",
|
||||
|
||||
46
src/Type.cpp
46
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<std::string> traitsIn) {
|
||||
indirection = 0;
|
||||
baseType = typeIn;
|
||||
traits = traitsIn;
|
||||
typeDefinition = NULL;
|
||||
templateDefinition = NULL;
|
||||
typeDefinition = nullptr;
|
||||
templateDefinition = nullptr;
|
||||
}
|
||||
|
||||
Type::Type(NodeTree<ASTData>* typeDefinitionIn, int indirectionIn) {
|
||||
indirection = indirectionIn;
|
||||
baseType = none;
|
||||
typeDefinition = typeDefinitionIn;
|
||||
templateDefinition = NULL;
|
||||
templateDefinition = nullptr;
|
||||
}
|
||||
|
||||
Type::Type(NodeTree<ASTData>* typeDefinitionIn, std::set<std::string> traitsIn) {
|
||||
@@ -34,7 +34,7 @@ Type::Type(NodeTree<ASTData>* typeDefinitionIn, std::set<std::string> traitsIn)
|
||||
baseType = none;
|
||||
typeDefinition = typeDefinitionIn;
|
||||
traits = traitsIn;
|
||||
templateDefinition = NULL;
|
||||
templateDefinition = nullptr;
|
||||
}
|
||||
|
||||
Type::Type(ValueType typeIn, NodeTree<ASTData>* typeDefinitionIn, int indirectionIn, std::set<std::string> traitsIn) {
|
||||
@@ -42,13 +42,31 @@ Type::Type(ValueType typeIn, NodeTree<ASTData>* typeDefinitionIn, int indirectio
|
||||
indirection = indirectionIn;
|
||||
typeDefinition = typeDefinitionIn;
|
||||
traits = traitsIn;
|
||||
templateDefinition = NULL;
|
||||
templateDefinition = nullptr;
|
||||
}
|
||||
|
||||
Type::Type(ValueType typeIn, NodeTree<ASTData>* typeDefinitionIn, int indirectionIn, std::set<std::string> traitsIn, std::vector<Type*> parameterTypesIn, Type* returnTypeIn) {
|
||||
baseType = typeIn;
|
||||
indirection = indirectionIn;
|
||||
typeDefinition = typeDefinitionIn;
|
||||
traits = traitsIn;
|
||||
templateDefinition = nullptr;
|
||||
parameterTypes = parameterTypesIn;
|
||||
returnType = returnTypeIn;
|
||||
}
|
||||
Type::Type(std::vector<Type*> parameterTypesIn, Type* returnTypeIn) {
|
||||
baseType = function_type;
|
||||
indirection = 0;
|
||||
typeDefinition = nullptr;
|
||||
templateDefinition = nullptr;
|
||||
parameterTypes = parameterTypesIn;
|
||||
returnType = returnTypeIn;
|
||||
}
|
||||
|
||||
Type::Type(ValueType typeIn, NodeTree<Symbol>* templateDefinitionIn, std::set<std::string> 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() {
|
||||
|
||||
1
tests/test_functionsValues.expected_results
Normal file
1
tests/test_functionsValues.expected_results
Normal file
@@ -0,0 +1 @@
|
||||
9
|
||||
13
tests/test_functionsValues.krak
Normal file
13
tests/test_functionsValues.krak
Normal file
@@ -0,0 +1,13 @@
|
||||
import io:*
|
||||
|
||||
fun test(): void {
|
||||
println(9)
|
||||
}
|
||||
|
||||
fun main(): int {
|
||||
var val = test
|
||||
val()
|
||||
return 0
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user