diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..85f38a8 --- /dev/null +++ b/.gitignore @@ -0,0 +1,6 @@ +_site +build +*.comp +stats +*.swp +*.png diff --git a/include/.ASTData.h.swp b/include/.ASTData.h.swp new file mode 100644 index 0000000..ea4dd95 Binary files /dev/null and b/include/.ASTData.h.swp differ diff --git a/include/ASTTransformation.h b/include/ASTTransformation.h index af5290a..e063b83 100644 --- a/include/ASTTransformation.h +++ b/include/ASTTransformation.h @@ -47,6 +47,7 @@ class ASTTransformation: public NodeTransformation { NodeTree* functionLookup(NodeTree* scope, std::string lookup, std::vector types); NodeTree* templateFunctionLookup(NodeTree* scope, std::string lookup, std::vector templateInstantiationTypes, std::vector types); std::vector*> scopeLookup(NodeTree* scope, std::string lookup, bool includeModules = false); + std::vector*> scopeLookup(NodeTree* scope, std::string lookup, bool includeModules, std::vector*> visited); Type* typeFromTypeNode(NodeTree* typeNode, NodeTree* scope, std::map templateTypeReplacements); NodeTree* templateClassLookup(NodeTree* scope, std::string name, std::vector templateInstantiationTypes); diff --git a/krakenGrammer.kgm b/krakenGrammer.kgm index a9af015..732a2eb 100644 --- a/krakenGrammer.kgm +++ b/krakenGrammer.kgm @@ -2,7 +2,7 @@ Goal = translation_unit ; translation_unit = interpreter_directive WS unorderd_list_part WS ; unorderd_list_part = import WS unorderd_list_part | function WS unorderd_list_part | type_def WS ";" WS unorderd_list_part | if_comp WS unorderd_list_part | simple_passthrough WS unorderd_list_part | declaration_statement WS ";" WS unorderd_list_part | import | function | type_def WS ";" | if_comp | simple_passthrough | declaration_statement WS ";" ; -type = type WS "\*" | "void" | "int" | "float" | "double" | "char" | identifier | identifier WS template_inst ; +type = type WS "\*" | "void" | "int" | "float" | "double" | "char" | scoped_identifier | scoped_identifier WS template_inst ; dec_type = "\|" WS type WS "\|" ; template_inst = "<" WS type_list WS ">" ; @@ -12,8 +12,8 @@ template_dec = "template" WS "<" WS template_param_list WS ">" ; template_param_list = template_param_list WS "," WS template_param | template_param ; template_param = identifier WS traits | identifier ; -import = "import" WS identifier WS ";" ; - +import = "import" WS identifier WS ";" | "import" WS identifier WS ":" WS "\*" WS ";" | "import" WS identifier WS ":" WS import_list WS ";" ; +import_list = identifier | identifier WS "," WS import_list ; interpreter_directive = "#!" WS path | ; path = path path_part | path_part ; @@ -37,6 +37,7 @@ triple_quoted_string = "\"\"\"((\"\"(`|1|2|3|4|5|6|7|8|9|0|-|=| |q|w|e|r|t|y|u|i |z|x|c|v|b|n|m|,|.|/|~|!|@|#|$|%|^|&|\*|\(|\)|_|\+|Q|W|E|R|T|Y|U|I|O|P|{|}|\||A|S|D|F|G|H|J|K|L|:|Z|X|C|V|B|N|M|<|>|\?| )+))*\"\"\"" ; identifier = alpha | alpha alphanumeric ; +scoped_identifier = scoped_identifier WS "::" WS identifier | identifier ; #Note that to prevent confilct with nested templates (T>) it is a nonterminal contructed as follows right_shift = ">" ">" ; @@ -56,7 +57,7 @@ type_def = "typedef" WS identifier WS type | "typedef" WS template_dec WS identi declaration_block = declaration_statement WS ";" WS declaration_block | function WS declaration_block | declaration_statement WS ";" | function | ; traits = "\(" WS trait_list WS "\)" ; -trait_list = trait_list WS "," WS identifier | identifier ; +trait_list = trait_list WS "," WS scoped_identifier | scoped_identifier ; #Older rule for stuff with visibility labels - this should be added sometime #type_def = "typedef" WS identifier WS type | "typedef" WS template_dec WS identifier WS "{" WS class_innerds WS "}" | "typedef" WS identifier WS "{" WS class_innerds WS "}" | "typedef" WS template_dec WS identifier WS "{" WS declaration_block WS "}" | "typedef" WS identifier WS "{" WS declaration_block WS "}" ; @@ -87,7 +88,7 @@ expression = expression WS "<<" WS term | expression WS right_shift WS shiftand shiftand = shiftand WS "-" WS term | shiftand WS "\+" WS term | term ; term = term WS forward_slash WS factor | term WS "\*" WS factor | term WS "%" WS factor | factor ; factor = "\+\+" WS unarad | unarad WS "\+\+" | "--" WS unarad | unarad WS "--" | "\+" WS unarad | "-" WS unarad | "!" WS unarad | "~" WS unarad | "\(" WS type WS "\)" WS unarad | "\*" WS unarad | "&" WS unarad | unarad ; -unarad = number | identifier | identifier WS template_inst | function_call | bool | string | character | "\(" WS boolean_expression WS "\)" | access_operation | unarad WS "[" WS expression WS "]" ; +unarad = number | scoped_identifier | scoped_identifier WS template_inst | function_call | bool | string | character | "\(" WS boolean_expression WS "\)" | access_operation | unarad WS "[" WS expression WS "]" ; number = integer | floating_literal ; access_operation = unarad "." identifier | unarad "->" identifier ; diff --git a/src/.ASTTransformation.cpp.swp b/src/.ASTTransformation.cpp.swp new file mode 100644 index 0000000..12f0889 Binary files /dev/null and b/src/.ASTTransformation.cpp.swp differ diff --git a/src/ASTTransformation.cpp b/src/ASTTransformation.cpp index c883adf..fae16d4 100644 --- a/src/ASTTransformation.cpp +++ b/src/ASTTransformation.cpp @@ -78,15 +78,38 @@ NodeTree* ASTTransformation::firstPass(std::string fileName, NodeTree* i : children) { if (i->getDataRef()->getName() == "import") { - std::string toImport = concatSymbolTree(i->getChildren()[0]); - translationUnit->addChild(new NodeTree("import", ASTData(import, Symbol(toImport, true)))); + auto importChildren = i->getChildren(); + std::string toImport = concatSymbolTree(importChildren[0]); + auto importNode = new NodeTree("import", ASTData(import, Symbol(toImport, true))); + translationUnit->addChild(importNode); //Do the imported file too NodeTree* outsideTranslationUnit = importer->importFirstPass(toImport + ".krak"); translationUnit->getDataRef()->scope[toImport].push_back(outsideTranslationUnit); //Put this transation_unit in the scope as it's files name - //Now add it to scope - for (auto i = outsideTranslationUnit->getDataRef()->scope.begin(); i != outsideTranslationUnit->getDataRef()->scope.end(); i++) - for (auto j : i->second) - translationUnit->getDataRef()->scope[i->first].push_back(j); + // Now go through and handle anything like import asdf: a; or import asdf: a,b; or import asdf: *; + // We do this by looping through the children and adding links to them as the scope in the import node. If it's *, we add the entire translationUnit link. + // Note that import affects scope in two ways: + // (1) The other file's translationUnit is added to our translationUnit's scope under it's name + // (2) The import node's scope contains the nodes indicated by the qualifiers after the import (i.e. the import a:b; or import a:*;) + for (auto importQualifer : slice(importChildren, 1, -1)) { // Not the first child, that's the name of the file + auto name = concatSymbolTree(importQualifer); + if (name == "*") { + std::vector*> tmp; + tmp.push_back(outsideTranslationUnit); + importNode->getDataRef()->scope["*"] = tmp; + } else { + bool found = false; + for (auto outsideScopeEntry : outsideTranslationUnit->getDataRef()->scope) { + if (name == outsideScopeEntry.first) { + importNode->getDataRef()->scope[outsideScopeEntry.first] = outsideScopeEntry.second; + found = true; + } + } + // If it's not found yet, put it in as a empty vector for pass 3. + // This makes sure that it does appear in the scope map, which is what we iterate through later. + if (!found) + importNode->getDataRef()->scope[name] = std::vector*>(); + } + } } } @@ -223,13 +246,17 @@ void ASTTransformation::thirdPass(NodeTree* ast) { NodeTree* outsideTranslationUnit = importer->getUnit(toImport + ".krak"); //Now add all functions to scope std::cout << "Trying to re-import from " << toImport << std::endl; - for (auto i = outsideTranslationUnit->getDataRef()->scope.begin(); i != outsideTranslationUnit->getDataRef()->scope.end(); i++) { - std::cout << "Looking through " << i->first << std::endl; - for (auto j : i->second) - if (j->getDataRef()->type == function || j->getDataRef()->type == identifier) - std::cout << "Copying " << i->first << std::endl, ast->getDataRef()->scope[i->first].push_back(j); + for (auto j = outsideTranslationUnit->getDataRef()->scope.begin(); j != outsideTranslationUnit->getDataRef()->scope.end(); j++) { + std::cout << "Looking at " << j->first << std::endl; + // If we're supposed to import this... (meaning that this name is in the scope already) + if (i->getDataRef()->scope.find(j->first) == i->getDataRef()->scope.end()) + continue; + std::cout << "Looking through " << j->first << std::endl; + for (auto k : j->second) + if (k->getDataRef()->type == function || k->getDataRef()->type == identifier) + std::cout << "Copying " << j->first << std::endl, i->getDataRef()->scope[j->first].push_back(k); else - std::cout << "Not Copying " << i->first << std::endl; + std::cout << "Not Copying " << j->first << std::endl; } } } @@ -332,7 +359,7 @@ NodeTree* ASTTransformation::transform(NodeTree* from, NodeTree std::vector*> children = from->getChildren(); std::set skipChildren; - if (name == "identifier") { + if (name == "identifier" || name == "scoped_identifier") { //Make sure we get the entire name std::string lookupName = concatSymbolTree(from); std::cout << "Looking up: " << lookupName << std::endl; @@ -350,6 +377,7 @@ NodeTree* ASTTransformation::transform(NodeTree* from, NodeTree } newNode = possibleMatches[0]; } + return newNode; } else if (name == "type_def") { //If it is an alisis of a type std::string typeAlias; @@ -416,6 +444,8 @@ NodeTree* ASTTransformation::transform(NodeTree* from, NodeTree return newNode; } functionName = concatSymbolTree(children[1]); + for (auto child: children) + std::cout << "Function child: " << child->getDataRef()->toString() << std::endl; newNode = new NodeTree(name, ASTData(function, Symbol(functionName, true), typeFromTypeNode(children[0], scope, templateTypeReplacements))); skipChildren.insert(0); skipChildren.insert(1); @@ -795,11 +825,19 @@ NodeTree* ASTTransformation::functionLookup(NodeTree* scope, s //We subtract one from the children to get the type size only if there is at least one child AND // the last node is actually a body node, as it may not have been generated yet if we're in the body //and this function is recursive or if this is a non-instantiated template function - if (types.size() != ((children.size() > 0 && children[children.size()-1]->getDataRef()->type == code_block) ? children.size()-1 : children.size())) { - std::cout << "Type sizes do not match between two " << lookup << "(" << types.size() << "," << ((children.size() > 0 && children[children.size()-1]->getDataRef()->type == code_block) ? children.size()-1 : children.size()) << "), types are: "; + int numTypes = (children.size() > 0 && children[children.size()-1]->getDataRef()->type == code_block) ? children.size()-1 : children.size(); + if (types.size() != numTypes) { + std::cout << "Type sizes do not match between two " << lookup << "(" << types.size() << "," << numTypes << "), types are: "; for (auto j : types) std::cout << j.toString() << " "; std::cout << std::endl; + std::cout << "Versus" << std::endl; + for (int j = 0; j < numTypes; j++) { + std::cout << " vs " << children[j]->getDataRef()->valueType->toString() << std::endl; + } + for (auto child: children) + std::cout << "\t" << child->getDataRef()->toString() << std::endl; + std::cout << std::endl; continue; } bool typesMatch = true; @@ -1005,7 +1043,15 @@ std::map ASTTransformation::makeTemplateFunctionTypeMap(Node return typeMap; } +// We need recursion protection std::vector*> ASTTransformation::scopeLookup(NodeTree* scope, std::string lookup, bool includeModules) { + return scopeLookup(scope, lookup, includeModules, std::vector*>()); +} + +std::vector*> ASTTransformation::scopeLookup(NodeTree* scope, std::string lookup, bool includeModules, std::vector*> visited) { + std::cout << "Scp[e looking up " << lookup << std::endl; + // Don't visit this node again when looking for the smae lookup. Note that we don't prevent coming back for the scope operator, as that should be able to come back. + visited.push_back(scope); //We first check to see if it's one of the special reserved identifiers (only this, for now) and return early if it is. auto LLElementIterator = languageLevelReservedWords.find(lookup); if (LLElementIterator != languageLevelReservedWords.end()) { @@ -1013,6 +1059,20 @@ std::vector*> ASTTransformation::scopeLookup(NodeTree return LLElementIterator->second; } std::vector*> matches; + // First, we check for scope operator (::) but only if occurs before a "<" as this would signal the beginning of a template instatiation inside type + // If we find it, we look up the left side of the :: and then use the resuts as the scope for looking up the right side, recursively. + size_t scopeOpPos = lookup.find("::"); + size_t angleBrktPos = lookup.find("<"); + if (scopeOpPos != std::string::npos && (angleBrktPos == std::string::npos || scopeOpPos < angleBrktPos)) { + std::cout << "Has :: operator, doing left then right" << std::endl; + for (auto scopeMatch : scopeLookup(scope, strSlice(lookup, 0, scopeOpPos), true)) { + std::cout << "Trying right side with found left side " << scopeMatch->getDataRef()->toString() << std::endl; + auto addMatches = scopeLookup(scopeMatch, strSlice(lookup, scopeOpPos+2, -1), includeModules); + matches.insert(matches.end(), addMatches.begin(), addMatches.end()); + } + return matches; + } + std::map*>> scopeMap = scope->getDataRef()->scope; auto possibleMatches = scopeMap.find(lookup); if (possibleMatches != scopeMap.end()) { @@ -1021,11 +1081,33 @@ std::vector*> ASTTransformation::scopeLookup(NodeTree matches.push_back(i); std::cout << "Found " << possibleMatches->second.size() << " match(s) at " << scope->getDataRef()->toString() << std::endl; } - // Add results from our enclosing scope, if it exists + // Add results from our enclosing scope, if it exists. + // If it doesn't we should be at the top of a translation unit, and we should check the scope of import statements. auto enclosingIterator = scopeMap.find("~enclosing_scope"); if (enclosingIterator != scopeMap.end()) { - std::vector*> upperResult = scopeLookup(enclosingIterator->second[0], lookup); + std::vector*> upperResult = scopeLookup(enclosingIterator->second[0], lookup, includeModules, visited); matches.insert(matches.end(), upperResult.begin(), upperResult.end()); + } else { + // Ok, let's iterate through and check for imports + for (auto child : scope->getChildren()) { + if (child->getDataRef()->type == import) { + auto importScope = child->getDataRef()->scope; + // Check if there is a match named explicily in the import's scope (i.e. looking for a and the import is import somefile: a;) + // If so, add it's members to our matches + auto importLookupItr = importScope.find(lookup); + if (importLookupItr != importScope.end()) { + auto addMatches = importLookupItr->second; + matches.insert(matches.end(), addMatches.begin(), addMatches.end()); + } + // Check if there is an uncionditional import to follow (i.e. import somefile: *;) + // If so, continue the search in that scope + auto importStarItr = importScope.find("*"); + if (importStarItr != importScope.end()) { + auto addMatches = scopeLookup(importStarItr->second[0], lookup, includeModules, visited); + matches.insert(matches.end(), addMatches.begin(), addMatches.end()); + } + } + } } return matches; } diff --git a/src/Importer.cpp b/src/Importer.cpp index 7d6ac37..36b84d2 100644 --- a/src/Importer.cpp +++ b/src/Importer.cpp @@ -10,7 +10,8 @@ Importer::Importer(Parser* parserIn, std::vector includePaths) { removeSymbols.push_back(Symbol("WS", false)); removeSymbols.push_back(Symbol("\\(", true)); removeSymbols.push_back(Symbol("\\)", true)); - removeSymbols.push_back(Symbol("::", true)); + //removeSymbols.push_back(Symbol("::", true)); + removeSymbols.push_back(Symbol(":", true)); removeSymbols.push_back(Symbol(";", true)); removeSymbols.push_back(Symbol("{", true)); removeSymbols.push_back(Symbol("}", true)); @@ -26,6 +27,7 @@ Importer::Importer(Parser* parserIn, std::vector includePaths) { removeSymbols.push_back(Symbol("template", true)); removeSymbols.push_back(Symbol("\\|", true)); + //collapseSymbols.push_back(Symbol("scoped_identifier", false)); collapseSymbols.push_back(Symbol("opt_typed_parameter_list", false)); collapseSymbols.push_back(Symbol("opt_parameter_list", false)); collapseSymbols.push_back(Symbol("opt_import_list", false)); diff --git a/tests/newScoping.expected_results b/tests/newScoping.expected_results new file mode 100644 index 0000000..1e96910 --- /dev/null +++ b/tests/newScoping.expected_results @@ -0,0 +1,13 @@ +Qualified io! +7 +9 +11 +Qualified Container! +Even template functions qualified! + +Unqualified io! +8 +10 +12 +Unqualified Container! +Even template functions unqualified! diff --git a/tests/newScoping.krak b/tests/newScoping.krak new file mode 100644 index 0000000..9a081af --- /dev/null +++ b/tests/newScoping.krak @@ -0,0 +1,32 @@ +import io; +import scopeQualified; +import scopeUnqualified : * ; + +|int| main() { + io::println("Qualified io!"); + + // Defined in scopeQualified + io::println(scopeQualified::qualified_variable); + io::println(scopeQualified::qualified_func()); + |scopeQualified::qualified_class| qClass.construct(11); + io::println(qClass.get()); + + |scopeQualified::qualified_container| sayQualified.construct("Qualified Container!"); + io::println(sayQualified.get()); + io::println(scopeQualified::qualified_id("Even template functions qualified!")); + + io::println(); + + io::println("Unqualified io!"); + // Defined in scopeUnqualified + io::println(unqualifed_variable); + io::println(unqualified_func()); + |unqualified_class| uqClass.construct(12); + io::println(uqClass.get()); + + |unqualified_container| sayUnqualified.construct("Unqualified Container!"); + io::println(sayUnqualified.get()); + io::println(unqualified_id("Even template functions unqualified!")); + + return 0; +} diff --git a/tests/scopeQualified.krak b/tests/scopeQualified.krak new file mode 100644 index 0000000..c862136 --- /dev/null +++ b/tests/scopeQualified.krak @@ -0,0 +1,27 @@ +|int| qualified_variable = 7; +|int| qualified_func() { return 9; } + +typedef qualified_class { + |int| number; + |qualified_class*| construct(|int| num) { + number = num; + return this; + } + |int| get() { + return number; + } +}; + +typedef template qualified_container { + |T| data; + |qualified_container*| construct(|T| dataIn) { + data = dataIn; + } + |T| get() { + return data; + } +}; + +template |T| qualified_id(|T| it) { + return it; +} diff --git a/tests/scopeUnqualified.krak b/tests/scopeUnqualified.krak new file mode 100644 index 0000000..8e0035b --- /dev/null +++ b/tests/scopeUnqualified.krak @@ -0,0 +1,27 @@ +|int| unqualifed_variable = 8; +|int| unqualified_func() { return 10; } + +typedef unqualified_class { + |int| number; + |qualified_class*| construct(|int| num) { + number = num; + return this; + } + |int| get() { + return number; + } +}; + +typedef template unqualified_container { + |T| data; + |unqualified_container*| construct(|T| dataIn) { + data = dataIn; + } + |T| get() { + return data; + } +}; + +template |T| unqualified_id(|T| it) { + return it; +}