From a4f2febfd5aa9e078c01a83a89c70f1da5227c63 Mon Sep 17 00:00:00 2001 From: Nathan Braswell Date: Mon, 3 Aug 2015 18:37:42 -0400 Subject: [PATCH] some bug fixes, templated operator method overloading --- include/ASTTransformation.h | 3 + src/ASTTransformation.cpp | 26 +++- src/CGenerator.cpp | 22 +-- stdlib/grammer.krak | 137 ++++++++++++------ stdlib/set.krak | 6 + stdlib/symbol.krak | 3 + stdlib/vector.krak | 10 ++ tests/test_grammer.krak | 1 + ...emplate_operator_overload.expected_results | 1 + tests/test_template_operator_overload.krak | 14 ++ 10 files changed, 164 insertions(+), 59 deletions(-) create mode 100644 tests/test_template_operator_overload.expected_results create mode 100644 tests/test_template_operator_overload.krak diff --git a/include/ASTTransformation.h b/include/ASTTransformation.h index dddfcbb..1a6d70f 100644 --- a/include/ASTTransformation.h +++ b/include/ASTTransformation.h @@ -64,7 +64,10 @@ class ASTTransformation: public NodeTransformation { NodeTree* templateClassLookup(NodeTree* scope, std::string name, std::vector templateInstantiationTypes); void unifyType(NodeTree *syntaxType, Type type, std::map* templateTypeMap, std::map typeMap); void unifyTemplateFunction(NodeTree* templateFunction, std::vector types, std::vector* templateInstantiationTypes, std::map typeMap); + NodeTree* tryToFindOrInstantiateFunctionTemplate(std::string functionName, NodeTree* scope, std::vector types, std::map templateTypeReplacements); + NodeTree* findOrInstantiateFunctionTemplate(std::string functionName, NodeTree* scope, std::vector types, std::map templateTypeReplacements); NodeTree* findOrInstantiateFunctionTemplate(std::vector*> children, NodeTree* scope, std::vector types, std::map templateTypeReplacements); + NodeTree* findOrInstantiateFunctionTemplate(std::string functionName, std::vector*> children, NodeTree* scope, std::vector types, std::map templateTypeReplacements); std::map makeTemplateFunctionTypeMap(NodeTree* templateNode, std::vector types, std::map scopeTypeMap); std::vector>> makeTemplateNameTraitPairs(NodeTree* templateNode); diff --git a/src/ASTTransformation.cpp b/src/ASTTransformation.cpp index 0b9a6b9..f4a711c 100644 --- a/src/ASTTransformation.cpp +++ b/src/ASTTransformation.cpp @@ -852,8 +852,12 @@ NodeTree* ASTTransformation::doFunction(NodeTree* scope, std:: NodeTree* operatorMethod = NULL; // make sure this isn't a pointer, also. Silly vector bug - if (nodes[0]->getDataRef()->valueType && !nodes[0]->getDataRef()->valueType->getIndirection() && nodes[0]->getDataRef()->valueType->typeDefinition) + if (nodes[0]->getDataRef()->valueType && !nodes[0]->getDataRef()->valueType->getIndirection() && nodes[0]->getDataRef()->valueType->typeDefinition) { operatorMethod = functionLookup(nodes[0]->getDataRef()->valueType->typeDefinition, lookupOp, mapNodesToTypes(slice(nodes,1,-1))); + // we're also gonna check to see if this is an operator template method + if (!operatorMethod) + operatorMethod = tryToFindOrInstantiateFunctionTemplate(lookupOp, nodes[0]->getDataRef()->valueType->typeDefinition, mapNodesToTypes(slice(nodes,1,-1)), templateTypeReplacements); + } if (operatorMethod) { //Ok, so we construct std::cout << "Early method level operator was found" << std::endl; @@ -1634,10 +1638,26 @@ Type* ASTTransformation::typeFromTypeNode(NodeTree* typeNode, NodeTree), or just the name (func), or even with just +// a string as the name if, for example, we're generating the name from an operator overload (which we do) (operator+) +NodeTree* ASTTransformation::tryToFindOrInstantiateFunctionTemplate(std::string functionName, NodeTree* scope, std::vector types, std::map templateTypeReplacements) { + try { + return findOrInstantiateFunctionTemplate(functionName, std::vector*>(), scope, types, templateTypeReplacements); + } catch (const char *ex) { + return nullptr; + } +} NodeTree* ASTTransformation::findOrInstantiateFunctionTemplate(std::vector*> children, NodeTree* scope, std::vector types, std::map templateTypeReplacements) { + return findOrInstantiateFunctionTemplate("", children, scope, types, templateTypeReplacements); +} +NodeTree* ASTTransformation::findOrInstantiateFunctionTemplate(std::string functionName, NodeTree* scope, std::vector types, std::map templateTypeReplacements) { + return findOrInstantiateFunctionTemplate(functionName, std::vector*>(), scope, types, templateTypeReplacements); +} +NodeTree* ASTTransformation::findOrInstantiateFunctionTemplate(std::string functionName, std::vector*> children, NodeTree* scope, std::vector types, std::map templateTypeReplacements) { //First look to see if we can find this already instantiated std::cout << "\n\nFinding or instantiating templated function\n\n" << std::endl; - std::string functionName = concatSymbolTree(children[0]); + if (children.size()) + functionName = concatSymbolTree(children[0]); std::string fullyInstantiatedName; std::string scopelessFullyInstantiatedName; std::vector templateActualTypes; @@ -1659,7 +1679,7 @@ NodeTree* ASTTransformation::findOrInstantiateFunctionTemplate(std::vec // Note that as a part o finferring the instantiation we already find the template, so we make that // condtitional too (templateDefinition) std::string instTypeString = ""; - if (children.size() == 1) { + if (children.size() <= 1) { // templateFunctionLookup adds the actual types to templateActualTypes if it's currently empty templateDefinition = templateFunctionLookup(scope, functionName, &templateActualTypes, types, scopeTypeMap); for (auto instType : templateActualTypes) diff --git a/src/CGenerator.cpp b/src/CGenerator.cpp index d513f23..3bd8410 100644 --- a/src/CGenerator.cpp +++ b/src/CGenerator.cpp @@ -287,17 +287,8 @@ CCodeTriple CGenerator::generate(NodeTree* from, NodeTree* enc return CCodeTriple("/* never reached import? */\n"); case identifier: { - //but first, if we're this, we should just emit. (assuming enclosing object) (note that technically this would fall through, but for errors) - if (data.symbol.getName() == "this") { - if (enclosingObject) - return CCodeTriple("this"); - std::cerr << "Error: this used in non-object scope" << std::endl; - throw "Error: this used in non-object scope"; - } - //If we're in an object method, and our enclosing scope is that object, we're a member of the object and should use the this reference. - std::string preName; - std::string postName; - //std::string preName = "/*ident*/"; + std::string preName = ""; + std::string postName = ""; // check for this being a closed over variable // first, get declaring function, if it exists if (enclosingFunction) { @@ -309,6 +300,15 @@ CCodeTriple CGenerator::generate(NodeTree* from, NodeTree* enc } } } + // enclosing function comes first now, we might have a double closure that both close over the this pointer of an object + //but first, if we're this, we should just emit. (assuming enclosing object) (note that technically this would fall through, but for errors) + if (data.symbol.getName() == "this") { + if (enclosingObject || enclosingFunction) + return CCodeTriple(preName + "this" + postName); + std::cerr << "Error: this used in non-object scope" << std::endl; + throw "Error: this used in non-object scope"; + } + //If we're in an object method, and our enclosing scope is that object, we're a member of the object and should use the this reference. if (enclosingObject && enclosingObject->getDataRef()->scope.find(data.symbol.getName()) != enclosingObject->getDataRef()->scope.end()) preName += "this->"; // dereference references, but only if inside a function diff --git a/stdlib/grammer.krak b/stdlib/grammer.krak index eb2f3fd..5470999 100644 --- a/stdlib/grammer.krak +++ b/stdlib/grammer.krak @@ -104,18 +104,21 @@ obj grammer (Object) { var non_terminals: set::set var terminals: vector::vector> var first_set_map: map::map> + var state_automata: state fun construct(): *grammer { rules.construct() non_terminals.construct() terminals.construct() first_set_map.construct() + state_automata.construct() } fun copy_construct(old: *grammer) { rules.copy_construct(&old->rules) non_terminals.copy_construct(&old->non_terminals) terminals.copy_construct(&old->terminals) first_set_map.copy_construct(&old->first_set_map) + state_automata.copy_construct(&old->state_automata) } fun operator=(other: grammer) { destruct() @@ -126,6 +129,7 @@ obj grammer (Object) { non_terminals.destruct() terminals.destruct() first_set_map.destruct() + state_automata.destruct() } fun calculate_first_set() { @@ -137,62 +141,74 @@ obj grammer (Object) { non_terminals.for_each( fun(non_terminal: symbol::symbol) first_set_map[non_terminal] = set::set() ) - var first_helper = fun(rhs: vector::vector): set::set { - var toRet = set::set() - if (rhs.size) { - for (var i = 0; i < rhs.size; i++;) { - var lookahead = first_set_map[rhs[i]] - if (lookahead.contains(symbol::null_symbol())) { - // remove the null if this is not the last in the rule - if (i != rhs.size-1) - lookahead.remove(symbol::null_symbol()) - toRet.add(lookahead) - } else { - toRet.add(lookahead) - break - } - } - } else { - toRet.add(symbol::null_symbol()) - } - return toRet - } var changed = true while (changed) { - /*io::println("//////////current state of map/////////////")*/ - first_set_map.keys.for_each(fun(sym: symbol::symbol) { - /*io::print("for ")*/ - /*io::println(sym.to_string())*/ - /*io::println("map is:")*/ - /*first_set_map[sym].for_each(fun(look: symbol::symbol) {*/ - /*io::print("lookahead: "); io::println(look.to_string())*/ - /*})*/ - }) changed = false rules.for_each( fun(r: rule) { - var rule_lookahead = first_helper(r.rhs) + var rule_lookahead = first_vector(r.rhs) if (!changed) { - /*io::println(r.to_string())*/ changed = !first_set_map[r.lhs].contains(rule_lookahead) - /*io::print("changed: "); io::println(changed)*/ - /*io::print("\tcurrent lookahead is sized:")*/ - /*io::println(first_set_map[r.lhs].size())*/ - /*io::println("\tcurrent lookahead is:")*/ - /*first_set_map[r.lhs].for_each(fun(look: symbol::symbol) {*/ - /*io::print("\t\tlookahead: "); io::println(look.to_string())*/ - /*})*/ - /*io::println()*/ - /*io::print("\rule lookahead is sized:")*/ - /*io::println(rule_lookahead.size())*/ - /*io::println("\trule lookahead is:")*/ - /*rule_lookahead.for_each(fun(look: symbol::symbol) {*/ - /*io::print("\t\tlookahead: "); io::println(look.to_string())*/ - /*})*/ } first_set_map[r.lhs].add(rule_lookahead) }) } } + fun first_vector(rhs: vector::vector): set::set { + var toRet = set::set() + if (rhs.size) { + for (var i = 0; i < rhs.size; i++;) { + var lookahead = first_set_map[rhs[i]] + if (lookahead.contains(symbol::null_symbol())) { + // remove the null if this is not the last in the rule + if (i != rhs.size-1) + lookahead.remove(symbol::null_symbol()) + toRet.add(lookahead) + } else { + toRet.add(lookahead) + break + } + } + } else { + toRet.add(symbol::null_symbol()) + } + return toRet + } + + fun calculate_state_automaton() { + } + + fun closure(initial: vector::vector): vector::vector { + var continueIt = true + while (continueIt) { + continueIt = false + initial.for_each(fun(i: rule) { + rules.for_each(fun(r: rule) { + // if i is |a::=c . Bb, a|, we're doing each B::=... in rules + if (r.lhs != i.next()) + return + // add r with lookahead + var newLookahead = first_vector(r.after_next()) + if (newLookahead.contains(symbol::null_symbol())) { + newLookahead.remove(symbol::null_symbol()) + newLookahead.add(i.lookahead) + } + for (var index = 0; index < initial.size; index++;) { + if (initial[index].equals_but_lookahead(r)) { + initial[index].lookahead += newLookahead + continueIt = true + return; // continuing rule-for_each + } + } + var newRule = r.with_lookahead(newLookahead) + if (!initial.contains(newRule)) { + continueIt = true + initial.add(newRule) + } + }) + }) + } + return initial + } fun to_string(): string::string { var result = string::string("grammer rules:") @@ -201,6 +217,8 @@ obj grammer (Object) { non_terminals.for_each( fun(i : symbol::symbol) { result += string::string("\n\t") + i.to_string(); } ) result += "\nterminals:" terminals.for_each( fun(i : util::pair) { result += string::string("\n\t") + i.first.to_string() + ": " + i.second.regexString; } ) + result += "\nstate:" + result += state_automata.to_string() return result } } @@ -234,12 +252,34 @@ obj rule (Object) { destruct() copy_construct(&other) } + //fun operator==(other: ref rule):bool { + fun operator==(other: rule):bool { + return lhs == other.lhs && rhs == other.rhs && + position == other.position && lookahead == other.lookahead + } + fun equals_but_lookahead(other: ref rule):bool { + return lhs == other.lhs && rhs == other.rhs && + position == other.position + } fun destruct() { lhs.destruct() rhs.destruct() lookahead.destruct() } + fun next(): symbol::symbol { + return rhs[position] + } + fun after_next(): vector::vector { + return rhs.slice(position + 1, -1) + } + fun with_lookahead(newLookahead: set::set): rule { + var toRet = rule(lhs, rhs) + toRet.position = position + toRet.lookahead = newLookahead + return toRet + } + fun to_string(): string::string { var result = lhs.name + " -> " rhs.for_each( fun(i : symbol::symbol) { result += i.to_string() + ", "; } ) @@ -255,6 +295,10 @@ obj state (Object) { kernel.construct() rest.construct() } + fun construct(kernelIn: ref vector::vector, restIn: ref vector::vector): *state { + kernel.copy_construct(&kernelIn) + rest.copy_construct(&restIn) + } fun copy_construct(other: *state) { kernel.copy_construct(&other->kernel) rest.copy_construct(&other->rest) @@ -267,5 +311,8 @@ obj state (Object) { kernel.destruct() rest.destruct() } + fun to_string(): string::string { + return string::string("woo a state") + } } diff --git a/stdlib/set.krak b/stdlib/set.krak index bbe4ad2..08848f5 100644 --- a/stdlib/set.krak +++ b/stdlib/set.krak @@ -50,6 +50,12 @@ obj set (Object) { fun contains(item: T): bool { return data.find(item) != -1 } + fun operator+=(item: T) { + add(item) + } + fun operator+=(items: set) { + add(items) + } fun add(item: T) { if (!contains(item)) data.add(item) diff --git a/stdlib/symbol.krak b/stdlib/symbol.krak index 61a3cd6..2a47a86 100644 --- a/stdlib/symbol.krak +++ b/stdlib/symbol.krak @@ -57,6 +57,9 @@ obj symbol (Object) { fun operator==(other: symbol): bool { return data == other.data && name == other.name && terminal == other.terminal; } + fun operator!=(other: symbol): bool { + return !(*this == other); + } fun to_string(): string::string { var terminalString: *char if (terminal) diff --git a/stdlib/vector.krak b/stdlib/vector.krak index 0f6ff14..8154331 100644 --- a/stdlib/vector.krak +++ b/stdlib/vector.krak @@ -124,6 +124,16 @@ obj vector (Object) { return find(item) != -1 } + // yep + fun operator==(other:vector):bool { + if (size != other.size) + return false + for (var i = 0; i < size; i++;) + if (!(data[i] == other.data[i])) // it's !(==) because we want equality if our members are equal, and overloading etc + return false + return true + } + fun set(index: int, dataIn: T): void { if (index < 0 || index >= size) return; diff --git a/tests/test_grammer.krak b/tests/test_grammer.krak index a535897..908fc41 100644 --- a/tests/test_grammer.krak +++ b/tests/test_grammer.krak @@ -46,6 +46,7 @@ fun main():int { println("woo lexing:") range(8).for_each(fun(i: int) { println(lex.next().to_string()); } ) /*range(80).for_each(fun(i: int) { println(lex.next().to_string()); } )*/ + println(a.to_string()) return 0 } diff --git a/tests/test_template_operator_overload.expected_results b/tests/test_template_operator_overload.expected_results new file mode 100644 index 0000000..153d194 --- /dev/null +++ b/tests/test_template_operator_overload.expected_results @@ -0,0 +1 @@ +works diff --git a/tests/test_template_operator_overload.krak b/tests/test_template_operator_overload.krak new file mode 100644 index 0000000..de3f1a0 --- /dev/null +++ b/tests/test_template_operator_overload.krak @@ -0,0 +1,14 @@ +import io:* + +obj it { + fun operator+(other: U): it { + println(other) + return *this + } +} + +fun main():int { + var i: it + i + "works" + return 0 +}