Fix nested closures and related bugs

This commit is contained in:
Nathan Braswell
2015-07-05 02:34:45 -04:00
parent d44ce47d1e
commit cfadf7cebb
13 changed files with 101 additions and 56 deletions

View File

@@ -19,15 +19,15 @@ ASTTransformation::ASTTransformation(Importer *importerIn) {
languageLevelOperators["&"].push_back(addToScope("~enclosing_scope", builtin_trans_unit, new NodeTree<ASTData>("function", ASTData(function, Symbol("&", true), NULL)))); languageLevelOperators["&"].push_back(addToScope("~enclosing_scope", builtin_trans_unit, new NodeTree<ASTData>("function", ASTData(function, Symbol("&", true), NULL))));
languageLevelOperators["--"].push_back(addToScope("~enclosing_scope", builtin_trans_unit, new NodeTree<ASTData>("function", ASTData(function, Symbol("--", true), NULL)))); languageLevelOperators["--"].push_back(addToScope("~enclosing_scope", builtin_trans_unit, new NodeTree<ASTData>("function", ASTData(function, Symbol("--", true), NULL))));
languageLevelOperators["++"].push_back(addToScope("~enclosing_scope", builtin_trans_unit, new NodeTree<ASTData>("function", ASTData(function, Symbol("++", true), NULL)))); languageLevelOperators["++"].push_back(addToScope("~enclosing_scope", builtin_trans_unit, new NodeTree<ASTData>("function", ASTData(function, Symbol("++", true), NULL))));
languageLevelOperators["=="].push_back(addToScope("~enclosing_scope", builtin_trans_unit, new NodeTree<ASTData>("function", ASTData(function, Symbol("==", true), new Type(boolean))))); languageLevelOperators["=="].push_back(addToScope("~enclosing_scope", builtin_trans_unit, new NodeTree<ASTData>("function", ASTData(function, Symbol("==", true), new Type(std::vector<Type*>(), new Type(boolean))))));
languageLevelOperators["!="].push_back(addToScope("~enclosing_scope", builtin_trans_unit, new NodeTree<ASTData>("function", ASTData(function, Symbol("!=", true), new Type(boolean))))); languageLevelOperators["!="].push_back(addToScope("~enclosing_scope", builtin_trans_unit, new NodeTree<ASTData>("function", ASTData(function, Symbol("!=", true), new Type(std::vector<Type*>(), new Type(boolean))))));
languageLevelOperators["<="].push_back(addToScope("~enclosing_scope", builtin_trans_unit, new NodeTree<ASTData>("function", ASTData(function, Symbol("<=", true), new Type(boolean))))); languageLevelOperators["<="].push_back(addToScope("~enclosing_scope", builtin_trans_unit, new NodeTree<ASTData>("function", ASTData(function, Symbol("<=", true), new Type(std::vector<Type*>(), new Type(boolean))))));
languageLevelOperators[">="].push_back(addToScope("~enclosing_scope", builtin_trans_unit, new NodeTree<ASTData>("function", ASTData(function, Symbol(">=", true), new Type(boolean))))); languageLevelOperators[">="].push_back(addToScope("~enclosing_scope", builtin_trans_unit, new NodeTree<ASTData>("function", ASTData(function, Symbol(">=", true), new Type(std::vector<Type*>(), new Type(boolean))))));
languageLevelOperators["<"].push_back(addToScope("~enclosing_scope", builtin_trans_unit, new NodeTree<ASTData>("function", ASTData(function, Symbol("<", true), new Type(boolean))))); languageLevelOperators["<"].push_back(addToScope("~enclosing_scope", builtin_trans_unit, new NodeTree<ASTData>("function", ASTData(function, Symbol("<", true), new Type(std::vector<Type*>(), new Type(boolean))))));
languageLevelOperators[">"].push_back(addToScope("~enclosing_scope", builtin_trans_unit, new NodeTree<ASTData>("function", ASTData(function, Symbol(">", true), new Type(boolean))))); languageLevelOperators[">"].push_back(addToScope("~enclosing_scope", builtin_trans_unit, new NodeTree<ASTData>("function", ASTData(function, Symbol(">", true), new Type(std::vector<Type*>(), new Type(boolean))))));
languageLevelOperators["&&"].push_back(addToScope("~enclosing_scope", builtin_trans_unit, new NodeTree<ASTData>("function", ASTData(function, Symbol("&&", true), new Type(boolean))))); languageLevelOperators["&&"].push_back(addToScope("~enclosing_scope", builtin_trans_unit, new NodeTree<ASTData>("function", ASTData(function, Symbol("&&", true), new Type(std::vector<Type*>(), new Type(boolean))))));
languageLevelOperators["||"].push_back(addToScope("~enclosing_scope", builtin_trans_unit, new NodeTree<ASTData>("function", ASTData(function, Symbol("||", true), new Type(boolean))))); languageLevelOperators["||"].push_back(addToScope("~enclosing_scope", builtin_trans_unit, new NodeTree<ASTData>("function", ASTData(function, Symbol("||", true), new Type(std::vector<Type*>(), new Type(boolean))))));
languageLevelOperators["!"].push_back(addToScope("~enclosing_scope", builtin_trans_unit, new NodeTree<ASTData>("function", ASTData(function, Symbol("!", true), new Type(boolean))))); languageLevelOperators["!"].push_back(addToScope("~enclosing_scope", builtin_trans_unit, new NodeTree<ASTData>("function", ASTData(function, Symbol("!", true), new Type(std::vector<Type*>(), new Type(boolean))))));
languageLevelOperators["*="].push_back(addToScope("~enclosing_scope", builtin_trans_unit, new NodeTree<ASTData>("function", ASTData(function, Symbol("*=", true), NULL)))); languageLevelOperators["*="].push_back(addToScope("~enclosing_scope", builtin_trans_unit, new NodeTree<ASTData>("function", ASTData(function, Symbol("*=", true), NULL))));
languageLevelOperators["="].push_back(addToScope("~enclosing_scope", builtin_trans_unit, new NodeTree<ASTData>("function", ASTData(function, Symbol("=", true), NULL)))); languageLevelOperators["="].push_back(addToScope("~enclosing_scope", builtin_trans_unit, new NodeTree<ASTData>("function", ASTData(function, Symbol("=", true), NULL))));
languageLevelOperators["+="].push_back(addToScope("~enclosing_scope", builtin_trans_unit, new NodeTree<ASTData>("function", ASTData(function, Symbol("+=", true), NULL)))); languageLevelOperators["+="].push_back(addToScope("~enclosing_scope", builtin_trans_unit, new NodeTree<ASTData>("function", ASTData(function, Symbol("+=", true), NULL))));
@@ -947,10 +947,17 @@ std::set<NodeTree<ASTData>*> ASTTransformation::findVariablesToClose(NodeTree<AS
) { ) {
// if this is a method we know that it is a method of our current enclosing object (as we already know that we're not on the right side of . or ->, see below) // if this is a method we know that it is a method of our current enclosing object (as we already know that we're not on the right side of . or ->, see below)
// we should add our enclosing object, this, to our closed over variables // we should add our enclosing object, this, to our closed over variables
// also, if this is a lambda, we should close over what it needs to close over too...
if (stat->getDataRef()->type == function) { if (stat->getDataRef()->type == function) {
auto statEnclosingScope = stat->getDataRef()->scope["~enclosing_scope"][0]; auto statEnclosingScope = stat->getDataRef()->scope["~enclosing_scope"][0];
if (statEnclosingScope && statEnclosingScope->getDataRef()->valueType && statEnclosingScope->getDataRef()->valueType->typeDefinition) if (statEnclosingScope && statEnclosingScope->getDataRef()->valueType && statEnclosingScope->getDataRef()->valueType->typeDefinition)
closed.insert(generateThis(scope)); closed.insert(generateThis(scope));
if (stat->getDataRef()->closedVariables.size()) {
for (auto item : stat->getDataRef()->closedVariables) {
auto recClosed = findVariablesToClose(func, item, scope);
closed.insert(recClosed.begin(), recClosed.end());
}
}
} }
return closed; return closed;
} }

View File

@@ -352,7 +352,9 @@ CCodeTriple CGenerator::generate(NodeTree<ASTData>* from, NodeTree<ASTData>* enc
if (enclosingObject && enclosingObject->getDataRef()->scope.find(varName) != enclosingObject->getDataRef()->scope.end()) if (enclosingObject && enclosingObject->getDataRef()->scope.find(varName) != enclosingObject->getDataRef()->scope.end())
preName += "this->"; preName += "this->";
varName = (varName == "this") ? varName : scopePrefix(var) + varName; varName = (varName == "this") ? varName : scopePrefix(var) + varName;
output.preValue += "." + varName + " = &" + preName + varName; // so that we can close over things that have been closed over by an enclosing closure
output.preValue += "." + varName + " = &/*woo*/" + generate(var, enclosingObject, justFuncName, enclosingFunction).oneString() + "/*woo*/";
//output.preValue += "." + varName + " = &" + preName + varName;
} }
output.preValue += "};\n"; output.preValue += "};\n";
output += "("+ ValueTypeToCType(data.valueType, "") +"){(void*)" + funcName + ", &" + tmpStruct + "}"; output += "("+ ValueTypeToCType(data.valueType, "") +"){(void*)" + funcName + ", &" + tmpStruct + "}";
@@ -667,31 +669,37 @@ CCodeTriple CGenerator::generate(NodeTree<ASTData>* from, NodeTree<ASTData>* enc
return "((" + generate(children[1], enclosingObject, true, enclosingFunction) + ")" + name + generate(children[2], nullptr, true, enclosingFunction) + ")"; return "((" + generate(children[1], enclosingObject, true, enclosingFunction) + ")" + name + generate(children[2], nullptr, true, enclosingFunction) + ")";
} }
} else { } else {
//It's a normal function call, not a special one or a method or anything. Name decorate. // this could a closure literal. sigh, I know.
std::vector<NodeTree<ASTData>*> functionDefChildren = children[0]->getChildren(); if (children[0]->getDataRef()->closedVariables.size()) {
std::cout << "Decorating (none-special)" << name << " " << functionDefChildren.size() << std::endl; functionCallSource = generate(children[0], enclosingObject, true, enclosingFunction);
std::string nameDecoration; doClosureInstead = true;
for (int i = 0; i < (functionDefChildren.size() > 0 ? functionDefChildren.size()-1 : 0); i++) } else {
nameDecoration += "_" + ValueTypeToCTypeDecoration(functionDefChildren[i]->getData().valueType); //It's a normal function call, not a special one or a method or anything. Name decorate.
// it is possible that this is an object method from inside a closure std::vector<NodeTree<ASTData>*> functionDefChildren = children[0]->getChildren();
// in which case, recover the enclosing object from this std::cout << "Decorating (none-special)" << name << " " << functionDefChildren.size() << std::endl;
bool addClosedOver = false; std::string nameDecoration;
if (enclosingFunction && enclosingFunction->getDataRef()->closedVariables.size()) { for (int i = 0; i < (functionDefChildren.size() > 0 ? functionDefChildren.size()-1 : 0); i++)
for (auto closedVar : enclosingFunction->getDataRef()->closedVariables) { nameDecoration += "_" + ValueTypeToCTypeDecoration(functionDefChildren[i]->getData().valueType);
if (closedVar->getDataRef()->symbol.getName() == "this") { // it is possible that this is an object method from inside a closure
enclosingObject = closedVar->getDataRef()->valueType->typeDefinition; // in which case, recover the enclosing object from this
addClosedOver = true; bool addClosedOver = false;
if (enclosingFunction && enclosingFunction->getDataRef()->closedVariables.size()) {
for (auto closedVar : enclosingFunction->getDataRef()->closedVariables) {
if (closedVar->getDataRef()->symbol.getName() == "this") {
enclosingObject = closedVar->getDataRef()->valueType->typeDefinition;
addClosedOver = true;
}
} }
} }
} //Check to see if we're inside of an object and this is a method call
//Check to see if we're inside of an object and this is a method call bool isSelfObjectMethod = enclosingObject && contains(enclosingObject->getChildren(), children[0]);
bool isSelfObjectMethod = enclosingObject && contains(enclosingObject->getChildren(), children[0]); if (isSelfObjectMethod) {
if (isSelfObjectMethod) { output += function_header + scopePrefix(children[0]) + CifyName(enclosingObject->getDataRef()->symbol.getName()) +"__";
output += function_header + scopePrefix(children[0]) + CifyName(enclosingObject->getDataRef()->symbol.getName()) +"__"; output += CifyName(name + nameDecoration) + "(";
output += CifyName(name + nameDecoration) + "("; output += std::string(addClosedOver ? "(*closed_variables->this)" : "this") + (children.size() > 1 ? "," : "");
output += std::string(addClosedOver ? "(*closed_variables->this)" : "this") + (children.size() > 1 ? "," : ""); } else {
} else { output += function_header + scopePrefix(children[0]) + CifyName(name + nameDecoration) + "(";
output += function_header + scopePrefix(children[0]) + CifyName(name + nameDecoration) + "("; }
} }
} }
} else { } else {

View File

@@ -34,17 +34,23 @@ fun load_grammer(path: string::string): grammer {
/*io::print("parts: ")*/ /*io::print("parts: ")*/
/*parts.for_each(fun(i :string::string){ io::print(i); io::print(" "); })*/ /*parts.for_each(fun(i :string::string){ io::print(i); io::print(" "); })*/
/*io::println()*/ /*io::println()*/
gram.rules.add(rule(symbol::symbol(parts[0], true), /*gram.rules.add(rule(symbol::symbol(parts[0], true),*/
parts.slice(1,-1).map(fun(i: string::string):symbol::symbol { /*parts.slice(1,-1).map(fun(i: string::string):symbol::symbol {*/
return symbol::symbol(i, true); /*return symbol::symbol(i, true);*/
}) /*})*/
)) /*))*/
var rightSide = vector::vector<symbol::symbol>()
parts.slice(1,-1).for_each( fun(part: string::string) {
if (part == "|") {
gram.rules.add(rule(symbol::symbol(parts[0], false), rightSide))
rightSide = vector::vector<symbol::symbol>()
} else {
rightSide.add(symbol::symbol(part, part[0] == '"'))
}
})
gram.rules.add(rule(symbol::symbol(parts[0], false), rightSide))
}) })
/*gram.rules.add(rule(symbol::symbol("test", true), vector::vector(symbol::symbol("rhs", true))))*/
/*gram.rules.add(rule(symbol::symbol("lhs", true), vector::vector(symbol::symbol("rhs2", true))))*/
/*gram.regexs.add(regex::regex("reg"))*/
return gram return gram
} }

View File

@@ -68,6 +68,10 @@ obj string (Object) {
fun operator==(other: string): bool { fun operator==(other: string): bool {
return length() == other.length() && !util::range(length()).any_true(fun(i: int):bool { return data[i] != other[i]; } ) return length() == other.length() && !util::range(length()).any_true(fun(i: int):bool { return data[i] != other[i]; } )
} }
fun operator==(other: *char): bool {
var str.construct(other) : string
return *this == str
}
fun operator+(str: *char): string { fun operator+(str: *char): string {
var newStr.construct(str):string var newStr.construct(str):string

View File

@@ -1,4 +1,6 @@
# comment # comment
a = b ; a = b ;
b = "c" ; b = "c" ;
b = "c" "d" ; b = c "d" ;
c = "a" | d ;
d = "hasreturn" ;

View File

@@ -5,3 +5,5 @@ Spam
We'll find out. We'll find out.
34 34
woo not woo not
true
false

View File

@@ -1,4 +1,6 @@
import io; import io:*
import string:*
fun main(): int { fun main(): int {
io::println("Spam"); io::println("Spam");
var x: int = 4; var x: int = 4;
@@ -18,4 +20,6 @@ fun main(): int {
var boolean = false var boolean = false
if ( z > 20 && !boolean) if ( z > 20 && !boolean)
io::println("woo not") io::println("woo not")
io::println(string("ab")[0] == 'a')
io::println('b' == 'a')
} }

View File

@@ -1,2 +1,5 @@
4 4
7 7
129
222
129

View File

@@ -35,8 +35,21 @@ fun main():int {
var it: ToClose var it: ToClose
it.testMethod() it.testMethod()
it.testVariable() it.testVariable()
//var a = 7
//mem::safe_recursive_delete(&a, fun(it: int*): set::set<int*> { return set::set(it); } ) var a = 129
var b = 222
fun() {
fun() {
println(a)
}()
}()
var c = fun() {
println(b)
fun() {
println(a)
}()
}
c()
return 0 return 0
} }

View File

@@ -3,8 +3,8 @@ import grammer:*
import string:* import string:*
fun main():int { fun main():int {
var a = load_grammer(string("../krakenGrammer.kgm")) /*var a = load_grammer(string("../krakenGrammer.kgm"))*/
/*var a = load_grammer(string("grammer.kgm"))*/ var a = load_grammer(string("grammer.kgm"))
println(a.to_string()) println(a.to_string())
return 0 return 0
} }

View File

@@ -1,8 +0,0 @@
import io:*
fun main():int {
var wa: fun():*int
var wb: *fun():int
var wc: *fun():*int
return 0
}

View File

@@ -9,5 +9,7 @@ a
now win! now win!
true true
false false
true
false
2 2
lines lines

View File

@@ -22,6 +22,8 @@ fun main(): int {
io::println(newWay) io::println(newWay)
io::println( string::string("yes") == string::string("yes") ) io::println( string::string("yes") == string::string("yes") )
io::println( string::string("no") == string::string("yes") ) io::println( string::string("no") == string::string("yes") )
io::println( string::string("yes") == "yes")
io::println( string::string("no") == "yes")
string::string("2\nlines").lines().for_each(fun(i: string::string) io::println(i);) string::string("2\nlines").lines().for_each(fun(i: string::string) io::println(i);)
return 0; return 0;
} }