diff --git a/include/ASTTransformation.h b/include/ASTTransformation.h index 920a53d..dddfcbb 100644 --- a/include/ASTTransformation.h +++ b/include/ASTTransformation.h @@ -34,11 +34,16 @@ class ASTTransformation: public NodeTransformation { NodeTree* secondPassDeclaration(NodeTree* from, NodeTree* scope, std::map templateTypeReplacements); NodeTree* secondPassFunction(NodeTree* from, NodeTree* scope, std::map templateTypeReplacements); - //The third pass finishes up by doing all function bodies + //The third pass does all the function bodies void thirdPass(NodeTree* ast, NodeTree* parseTree); NodeTree* searchScopeForFunctionDef(NodeTree* scope, NodeTree* parseTree, std::map templateTypeReplacements); void thirdPassFunction(NodeTree* from, NodeTree* functionDef, std::map templateTypeReplacements); + //The fourth pass finishes instantiation of templated objects + //it used to be a part of the third pass, but it was split out because it has to be done in a loop + //with all the other asts until none change anymore (it returns a bool if it instantiated a new one) + bool fourthPass(NodeTree* ast, NodeTree* parseTree); + virtual NodeTree* transform(NodeTree* from); NodeTree* transform(NodeTree* from, NodeTree* scope, std::vector types, bool limitToFunction, std::map templateTypeReplacements); std::vector*> transformChildren(std::vector*> children, std::set skipChildren, NodeTree* scope, std::vector types, bool limitToFunction, std::map templateTypeReplacements); diff --git a/include/Type.h b/include/Type.h index f95c5ed..673dcaf 100644 --- a/include/Type.h +++ b/include/Type.h @@ -46,6 +46,7 @@ class Type { NodeTree* typeDefinition; NodeTree* templateDefinition; std::map templateTypeReplacement; + bool templateInstantiated; std::set traits; std::vector parameterTypes; Type *returnType; diff --git a/src/ASTTransformation.cpp b/src/ASTTransformation.cpp index db5c8fd..33b9eb7 100644 --- a/src/ASTTransformation.cpp +++ b/src/ASTTransformation.cpp @@ -285,12 +285,15 @@ void ASTTransformation::thirdPass(NodeTree* ast, NodeTree* pars thirdPassFunction(i, searchScopeForFunctionDef(ast, i, std::map()), std::map()); } } +} +bool ASTTransformation::fourthPass(NodeTree* ast, NodeTree* parseTree) { + topScope = ast; //Top scope is maintained for templates, which need to add themselves to the top scope from where ever they are instantiated + bool changed = false; // We do these here, in a loop, so that we can do mututally recursive definitions // even inside of class templates. As its methods may cause partial instantiation of // other class templates, we need to do this until the size no longer changes. std::vector*> classTemplates; - std::set finishedClassTemplateTypes; int lastSize = 0; while (lastSize != ast->getDataRef()->scope.size()) { lastSize = ast->getDataRef()->scope.size(); @@ -298,9 +301,10 @@ void ASTTransformation::thirdPass(NodeTree* ast, NodeTree* pars for (auto i : ast->getDataRef()->scope) { // we actually keep track of the template type replacements now, and need them after they're instantiated, so we use a set to check if we've done it now if (i.second[0]->getDataRef()->type == type_def && i.second[0]->getDataRef()->valueType->templateTypeReplacement.size() - && finishedClassTemplateTypes.find(i.second[0]->getDataRef()->valueType) == finishedClassTemplateTypes.end()) { + && !i.second[0]->getDataRef()->valueType->templateInstantiated) { classTemplates.push_back(i.second[0]); std::cout << "Saving " << i.second[0]->getDataRef()->toString() << " to instantiate." << std::endl; + changed = true; } } for (auto i : classTemplates) { @@ -309,9 +313,10 @@ void ASTTransformation::thirdPass(NodeTree* ast, NodeTree* pars for (NodeTree* j : classTemplateType->templateDefinition->getChildren()) if (j->getDataRef()->getName() == "function" && j->getChildren()[1]->getDataRef()->getName() != "template_dec") thirdPassFunction(j, searchScopeForFunctionDef(i, j, classTemplateType->templateTypeReplacement), classTemplateType->templateTypeReplacement); //do member method - finishedClassTemplateTypes.insert(classTemplateType); + classTemplateType->templateInstantiated = true; } } + return changed; } //This function finds the right AST definition in a scope given its parseTree @@ -1552,6 +1557,7 @@ Type* ASTTransformation::typeFromTypeNode(NodeTree* typeNode, NodeTreegetDataRef()->toString() << std::endl; templateTopScope->getDataRef()->scope[fullyInstantiatedName].push_back(typeDefinition); templateTopScope->addChild(typeDefinition); // Add this object the the highest scope's diff --git a/src/CGenerator.cpp b/src/CGenerator.cpp index da59402..8b0344b 100644 --- a/src/CGenerator.cpp +++ b/src/CGenerator.cpp @@ -419,6 +419,7 @@ CCodeTriple CGenerator::generate(NodeTree* from, NodeTree* enc 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*>()); @@ -426,7 +427,12 @@ CCodeTriple CGenerator::generate(NodeTree* from, NodeTree* enc // 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, true, enclosingFunction).oneString() + ") {\n\t"; + // 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 += + "}"; @@ -436,6 +442,7 @@ CCodeTriple CGenerator::generate(NodeTree* from, NodeTree* enc // 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()); @@ -761,8 +768,11 @@ std::string CGenerator::generateObjectMethod(NodeTree* enclosingObject, enclosingObjectType.increaseIndirection(); std::vector*> children = from->getChildren(); std::string nameDecoration, parameters; - // note how we get around children.size() being an unsigned type - for (int i = 0; i+1 < children.size(); i++) { + 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); @@ -774,7 +784,7 @@ std::string CGenerator::generateObjectMethod(NodeTree* enclosingObject, // Note that we always wrap out child in {}, as we now allow one statement functions without a codeblock // std::string output; - output += functionSignature + " {\n" + generate(children[children.size()-1], enclosingObject).oneString(); + output += functionSignature + " {\n" + generate(children.back(), enclosingObject).oneString(); output += emitDestructors(reverse(distructDoubleStack.back()), enclosingObject); output += "}\n"; //Pass in the object so we can properly handle access to member stuff distructDoubleStack.pop_back(); @@ -837,10 +847,12 @@ std::string CGenerator::closureStructType(std::set*> closedVar std::string typedefString = "typedef struct { "; // note the increased indirection b/c we're using references to what we closed over for (auto var : closedVariables) { - auto tmp = var->getDataRef()->valueType->withIncreasedIndirection(); + // unfortunatly we can't just do it with increased indirection b/c closing over function values + // will actually change the underlying function's type. We cheat and just add a * + //auto tmp = var->getDataRef()->valueType->withIncreasedIndirection(); std::string varName = var->getDataRef()->symbol.getName(); varName = (varName == "this") ? varName : scopePrefix(var) + varName; - typedefString += ValueTypeToCType(&tmp, varName) + ";"; + typedefString += ValueTypeToCType(var->getDataRef()->valueType, "*"+varName) + ";"; } std::string structName = "closureStructType" + getID(); typedefString += " } " + structName + ";\n"; diff --git a/src/Importer.cpp b/src/Importer.cpp index fbd3cfe..1c60730 100644 --- a/src/Importer.cpp +++ b/src/Importer.cpp @@ -105,8 +105,18 @@ void Importer::import(std::string fileName) { std::cout << "\n\nSecond pass for: " << i.name << std::endl, ASTTransformer->secondPass(i.ast, i.syntaxTree); //function prototypes, and identifiers (as we now have all type defs) std::cout << "\n\n =====THIRD PASS===== \n\n" << std::endl; - for (importTriplet i : importedTrips) //Third pass finishes up by doing all function bodies - std::cout << "\n\nFourth pass for: " << i.name << std::endl, ASTTransformer->thirdPass(i.ast, i.syntaxTree); //With that, we're done + for (importTriplet i : importedTrips) //Third pass does all function bodies + std::cout << "\n\nThird pass for: " << i.name << std::endl, ASTTransformer->thirdPass(i.ast, i.syntaxTree); + + std::cout << "\n\n =====FOURTH PASS===== \n\n" << std::endl; + bool changed = true; + while (changed) { + changed = false; + for (importTriplet i : importedTrips) { //Fourth pass finishes up by doing all template classes + std::cout << "\n\nFourth pass for: " << i.name << std::endl; + changed = changed ? changed : ASTTransformer->fourthPass(i.ast, i.syntaxTree); + } + } //Note that class template instantiation can happen in the second or third passes and that function template instantion //can happen in the third pass. diff --git a/src/Type.cpp b/src/Type.cpp index 52f3be0..ad01dde 100644 --- a/src/Type.cpp +++ b/src/Type.cpp @@ -6,6 +6,7 @@ Type::Type() { typeDefinition = nullptr; templateDefinition = nullptr; returnType = nullptr; + templateInstantiated = false; } Type::Type(ValueType typeIn, int indirectionIn) { @@ -14,6 +15,7 @@ Type::Type(ValueType typeIn, int indirectionIn) { typeDefinition = nullptr; templateDefinition = nullptr; returnType = nullptr; + templateInstantiated = false; } Type::Type(ValueType typeIn, std::set traitsIn) { @@ -23,6 +25,7 @@ Type::Type(ValueType typeIn, std::set traitsIn) { typeDefinition = nullptr; templateDefinition = nullptr; returnType = nullptr; + templateInstantiated = false; } Type::Type(NodeTree* typeDefinitionIn, int indirectionIn) { @@ -31,6 +34,7 @@ Type::Type(NodeTree* typeDefinitionIn, int indirectionIn) { typeDefinition = typeDefinitionIn; templateDefinition = nullptr; returnType = nullptr; + templateInstantiated = false; } Type::Type(NodeTree* typeDefinitionIn, std::set traitsIn) { @@ -40,6 +44,7 @@ Type::Type(NodeTree* typeDefinitionIn, std::set traitsIn) traits = traitsIn; templateDefinition = nullptr; returnType = nullptr; + templateInstantiated = false; } Type::Type(ValueType typeIn, NodeTree* typeDefinitionIn, int indirectionIn, std::set traitsIn) { @@ -49,6 +54,7 @@ Type::Type(ValueType typeIn, NodeTree* typeDefinitionIn, int indirectio traits = traitsIn; templateDefinition = nullptr; returnType = nullptr; + templateInstantiated = false; } Type::Type(ValueType typeIn, NodeTree* typeDefinitionIn, int indirectionIn, std::set traitsIn, std::vector parameterTypesIn, Type* returnTypeIn) { @@ -59,6 +65,7 @@ Type::Type(ValueType typeIn, NodeTree* typeDefinitionIn, int indirectio templateDefinition = nullptr; parameterTypes = parameterTypesIn; returnType = returnTypeIn; + templateInstantiated = false; } Type::Type(std::vector parameterTypesIn, Type* returnTypeIn) { baseType = function_type; @@ -67,6 +74,7 @@ Type::Type(std::vector parameterTypesIn, Type* returnTypeIn) { templateDefinition = nullptr; parameterTypes = parameterTypesIn; returnType = returnTypeIn; + templateInstantiated = false; } Type::Type(ValueType typeIn, NodeTree* templateDefinitionIn, std::set traitsIn) { @@ -76,6 +84,7 @@ Type::Type(ValueType typeIn, NodeTree* templateDefinitionIn, std::set { return set::set(it); } ) + mem::safe_recursive_delete(begin, fun(it: regexState*): set::set { return set::from_vector(it->next_states); } ) } fun operator=(other: regex):void { diff --git a/stdlib/set.krak b/stdlib/set.krak index 6cc9493..f9b889e 100644 --- a/stdlib/set.krak +++ b/stdlib/set.krak @@ -12,6 +12,12 @@ fun set(item: T): set { return toRet } +fun from_vector(items: vector::vector): set { + var toRet.construct() : set + items.do( fun(item: T) toRet.add(item); ) + return toRet +} + obj set { var data: vector::vector fun construct() { @@ -29,6 +35,9 @@ obj set { return false return !data.any_true( fun(item: T): bool return !rhs.contains(item); ) } + fun operator!=(rhs: set): bool { + return ! (*this == rhs) + } fun destruct() { data.destruct() } diff --git a/tests/test_close_over_members.krak b/tests/test_close_over_members.krak index ffb6d42..1929fc2 100644 --- a/tests/test_close_over_members.krak +++ b/tests/test_close_over_members.krak @@ -1,4 +1,6 @@ import io:* +import set +import mem fun runFunc(func: fun():void) { func() @@ -18,10 +20,23 @@ obj ToClose { } } +obj One (Object) { + fun construct(): One* { + return this + } + fun destruct() { + var a:One + mem::safe_recursive_delete(&a, fun(it: One*): set::set { return set::set(it); } ) + } +} + + fun main():int { var it: ToClose it.testMethod() it.testVariable() + //var a = 7 + //mem::safe_recursive_delete(&a, fun(it: int*): set::set { return set::set(it); } ) return 0 }