diff --git a/include/ASTTransformation.h b/include/ASTTransformation.h index 955ccca..18f4e43 100644 --- a/include/ASTTransformation.h +++ b/include/ASTTransformation.h @@ -4,6 +4,9 @@ #include #include +#include +#include + #include "Type.h" #include "ASTData.h" #include "NodeTransformation.h" @@ -18,6 +21,7 @@ class ASTTransformation: public NodeTransformation { //First pass defines all type_defs (objects and ailises) NodeTree* firstPass(std::string fileName, NodeTree* parseTree); + std::set parseTraits(NodeTree* traitsNode); //Second pass defines data inside objects, outside declaration statements, and function prototpyes (since we have type_defs now) void secondPass(NodeTree* ast, NodeTree* parseTree); @@ -39,10 +43,15 @@ class ASTTransformation: public NodeTransformation { std::vector mapNodesToTypes(std::vector*> nodes); std::string concatSymbolTree(NodeTree* root); NodeTree* doFunction(NodeTree* scope, std::string lookup, std::vector*> nodes, std::map templateTypeReplacements); - NodeTree* scopeLookup(NodeTree* scope, std::string lookup, std::vector types = std::vector()); + + 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); Type* typeFromTypeNode(NodeTree* typeNode, NodeTree* scope, std::map templateTypeReplacements, bool instantiateTemplates); NodeTree* findOrInstantiateFunctionTemplate(std::vector*> children, NodeTree* scope, std::vector types, std::map templateTypeReplacements); + std::map makeTemplateFunctionTypeMap(NodeTree* templateNode, std::vector types); + std::vector>> makeTemplateFunctionNameTraitPairs(NodeTree* templateNode); private: Importer * importer; std::map*>> languageLevelReservedWords; diff --git a/include/Type.h b/include/Type.h index 5b31c6c..a56286e 100644 --- a/include/Type.h +++ b/include/Type.h @@ -5,12 +5,9 @@ #define NULL ((void*)0) #endif -#ifndef SEGFAULT -#define SEGFAULT (*((char*)0)), std::cout << "\t\t\t\tNEGATIVE*************************************************************************" << std::endl; -#endif - #include #include +#include //Circular dependency class ASTData; @@ -23,12 +20,12 @@ enum ValueType {none, template_type, template_type_type, void_type, boolean, int class Type { public: Type(); - Type(ValueType typeIn, int indirectionIn); - Type(ValueType typeIn); - Type(NodeTree* typeDefinitionIn); - Type(NodeTree* typeDefinitionIn, int indirectionIn); - Type(ValueType typeIn, NodeTree* typeDefinitionIn, int indirectionIn); - Type(ValueType typeIn, NodeTree* templateDefinitionIn); + Type(ValueType typeIn, int indirectionIn = 0); + Type(ValueType typeIn, std::set traitsIn); //Mostly for template type type's + Type(NodeTree* typeDefinitionIn, int indirectionIn = 0); + Type(NodeTree* typeDefinitionIn, std::set traitsIn); + Type(ValueType typeIn, NodeTree* typeDefinitionIn, int indirectionIn, std::set traitsIn); + Type(ValueType typeIn, NodeTree* templateDefinitionIn, std::set traitsIn = std::set()); ~Type(); bool const operator==(const Type &other)const; bool const operator!=(const Type &other)const; @@ -39,13 +36,13 @@ class Type { void increaseIndirection(); void decreaseIndirection(); void modifyIndirection(int mod); - void check(); ValueType baseType; NodeTree* typeDefinition; NodeTree* templateDefinition; std::map templateTypeReplacement; - private: + std::set traits; + private: int indirection; }; diff --git a/krakenGrammer.kgm b/krakenGrammer.kgm index 7b81fe9..e7cb9de 100644 --- a/krakenGrammer.kgm +++ b/krakenGrammer.kgm @@ -12,7 +12,8 @@ type_list = type_list WS "," WS type | type ; # # template_dec = "template" WS "<" WS template_param_list WS ">" ; -template_param_list = template_param_list WS "," WS identifier | identifier ; +template_param_list = template_param_list WS "," WS template_param | template_param ; +template_param = identifier WS traits | identifier ; import = "import" WS identifier WS ";" ; @@ -40,7 +41,9 @@ triple_quoted_string = "\"\"\"((\"\"(`|1|2|3|4|5|6|7|8|9|0|-|=| |q|w|e|r|t|y|u|i identifier = alpha | alpha alphanumeric ; -overloadable_operator = "\+" | "-" | "\*" | "/" | "%" | "^" | "&" | "\|" | "~" | "!" | "," | "=" | "\+\+" | "--" | "<<" | ">>" | "==" | "!=" | "&&" | "\|\|" | "\+=" | "-=" | "/=" | "%=" | "^=" | "&=" | "\|=" | "\*=" | "<<=" | ">>=" | "->" ; +#Note that to prevent confilct with nested templates (T>) it is a nonterminal contructed as follows +right_shift = ">" ">" ; +overloadable_operator = "\+" | "-" | "\*" | "/" | "%" | "^" | "&" | "\|" | "~" | "!" | "," | "=" | "\+\+" | "--" | "<<" | right_shift | "==" | "!=" | "&&" | "\|\|" | "\+=" | "-=" | "/=" | "%=" | "^=" | "&=" | "\|=" | "\*=" | "<<=" | ">>=" | "->" ; func_identifier = identifier | identifier overloadable_operator ; function = template_dec WS type WS func_identifier WS "\(" WS opt_typed_parameter_list WS "\)" WS code_block | type WS func_identifier WS "\(" WS opt_typed_parameter_list WS "\)" WS code_block ; @@ -52,10 +55,17 @@ opt_parameter_list = parameter_list | ; parameter_list = parameter_list WS "," WS parameter | parameter ; parameter = boolean_expression ; -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 "}" ; -class_innerds = visibility_block WS class_innerds | visibility_block ; -visibility_block = "public:" WS declaration_block | "protected:" WS declaration_block | "private:" WS declaration_block ; -declaration_block = declaration_statement WS ";" WS declaration_block | function WS declaration_block | declaration_statement WS ";" | function ; +type_def = "typedef" WS identifier WS type | "typedef" WS template_dec WS identifier WS "{" WS declaration_block WS "}" | "typedef" WS identifier WS "{" WS declaration_block WS "}" | "typedef" WS template_dec WS identifier WS traits WS "{" WS declaration_block WS "}" | "typedef" WS identifier WS traits WS "{" WS declaration_block WS "}" ; + +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 ; + +#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 "}" ; +#class_innerds = visibility_block WS class_innerds | visibility_block ; +#visibility_block = "public:" WS declaration_block | "protected:" WS declaration_block | "private:" WS declaration_block ; + if_statement = "if" WS "\(" WS boolean_expression WS "\)" WS statement | "if" WS "\(" WS boolean_expression WS "\)" WS statement WS "else" WS statement ; @@ -76,12 +86,12 @@ and_boolean_expression = and_boolean_expression "&&" bool_exp | bool_exp ; bool_exp = expression WS comparator WS expression | bool | expression ; comparator = "==" | "<=" | ">=" | "!=" | "<" | ">" ; -expression = expression WS "<<" WS term | expression WS ">>" WS shiftand | shiftand ; +expression = expression WS "<<" WS term | expression WS right_shift WS shiftand | 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 "]" ; -number = integer | float | double ; +number = integer | floating_literal ; access_operation = unarad "." identifier | unarad "->" identifier ; assignment_statement = factor WS "=" WS boolean_expression | factor WS "\+=" WS boolean_expression | factor WS "-=" WS boolean_expression | factor WS "\*=" WS boolean_expression | factor WS "/=" WS boolean_expression ; @@ -91,8 +101,7 @@ alphanumeric = alphanumeric numeric | alphanumeric alpha | numeric | alpha ; hexadecimal = "0x(1|2|3|4|5|6|7|8|9|a|b|c|d|e|f)+" ; sign = "\+|-" WS | ; integer = sign numeric | sign hexadecimal | "null" ; -float = sign numeric "." numeric "f" ; -double = sign numeric "." numeric | sign numeric "." numeric "d" ; +floating_literal = sign numeric "." numeric | sign numeric "." numeric alpha ; bool = "true" | "false" | "True" | "False" ; character = "'(`|1|2|3|4|5|6|7|8|9|0|-|=| |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|,|.|/|~|!|@|#|$|%|^|&|\*|\(|\)|_|\+|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|<|>|\?| )'" ; diff --git a/src/ASTTransformation.cpp b/src/ASTTransformation.cpp index 63ecabb..33a456c 100644 --- a/src/ASTTransformation.cpp +++ b/src/ASTTransformation.cpp @@ -42,7 +42,7 @@ NodeTree* ASTTransformation::firstPass(std::string fileName, NodeTree* translationUnit = new NodeTree("translation_unit", ASTData(translation_unit)); std::vector*> children = parseTree->getChildren(); importer->registerAST(fileName, translationUnit, parseTree); //Register ourselves with the importer. - //This puts us in the scope and the list of ASTs that go through all the passes + //This puts us in the scope and the list of ASTs that go through all the passes //Go through and define all types (type_defs whether they are classes or ailises, as well as including non-instantiated templates) for (NodeTree* i : children) { @@ -54,10 +54,19 @@ NodeTree* ASTTransformation::firstPass(std::string fileName, NodeTreegetChildren()[0]); NodeTree* firstDec = new NodeTree("type_def", ASTData(type_def, Symbol(name, true, name))); //If this is a template, go ahead and set it up. Pass 2 needs templates set up so it can (partially) instantiate them. - if (i->getChildren()[0]->getData().getName() == "template_dec") - firstDec->getDataRef()->valueType = new Type(template_type, i); //So we give this typedef its name without any template types and make its type template_type, and point to this from node. //Then, when this template is instantiated, it will run transform on from with the types filled in. + auto typedefChildren = i->getChildren(); + if (typedefChildren[0]->getData().getName() == "template_dec") { + if (typedefChildren.size() > 2 && typedefChildren[2]->getData().getName() == "traits") + firstDec->getDataRef()->valueType = new Type(template_type, i, parseTraits(i->getChildren()[2])); + else + firstDec->getDataRef()->valueType = new Type(template_type, i); + } + else if (typedefChildren.size() > 1 && typedefChildren[1]->getData().getName() == "traits") + firstDec->getDataRef()->valueType = new Type(firstDec, parseTraits(i->getChildren()[1])); + else if (typedefChildren.size() == 1 || typedefChildren[1]->getData().getName() != "type") //We don't make the type for alises, because the second pass will assign it the type it points to + firstDec->getDataRef()->valueType = new Type(firstDec); translationUnit->addChild(firstDec); translationUnit->getDataRef()->scope[name].push_back(firstDec); @@ -84,6 +93,14 @@ NodeTree* ASTTransformation::firstPass(std::string fileName, NodeTree ASTTransformation::parseTraits(NodeTree* traitsNode) { + std::set traits; + //Every other one b/c comma separated + for (auto i : slice(traitsNode->getChildren(), 0, -1, 2)) + traits.insert(concatSymbolTree(i)); + return traits; +} + //Second pass defines data inside objects, outside declaration statements, and function prototypes (since we have type_defs now) void ASTTransformation::secondPass(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 @@ -97,10 +114,10 @@ void ASTTransformation::secondPass(NodeTree* ast, NodeTree* par continue; //We've already set upt the class templates std::vector*> typedefChildren = i->getChildren(); std::string name = concatSymbolTree(typedefChildren[0]); - NodeTree* typeDef = ast->getDataRef()->scope[name][0]; //No overloaded types + NodeTree* typeDef = ast->getDataRef()->scope[name][0]; //No overloaded types (besides uninstantiated templates, which can have multiple versions based on types or specilizations) - //It's an alias - if (typedefChildren[1]->getData().getName() == "type") { + //It's an alias. Note that if typedefChildren.size() == 1 it's because its a regular class with no body, i.e. {} + if (typedefChildren.size() > 1 && typedefChildren[1]->getData().getName() == "type") { Type* aliasedType = typeFromTypeNode(typedefChildren[1], ast, std::map(), false); //false - don't fully instantiate templates typeDef->getDataRef()->valueType = aliasedType; typeDef->getDataRef()->scope["~enclosing_scope"][0] = aliasedType->typeDefinition; //So that object lookups find the right member. Note that this overrides translation_unit as a parent scope @@ -109,7 +126,6 @@ void ASTTransformation::secondPass(NodeTree* ast, NodeTree* par continue; } //Do the inside of classes here - typeDef->getDataRef()->valueType = new Type(typeDef); secondPassDoClassInsides(typeDef, typedefChildren, std::map()); } else if (i->getDataRef()->getName() == "function") { //Do prototypes of functions @@ -160,11 +176,14 @@ NodeTree* ASTTransformation::secondPassFunction(NodeTree* from, functionDef = new NodeTree("function", ASTData(function, Symbol(functionName, true), new Type(template_type, from))); scope->getDataRef()->scope[functionName].push_back(functionDef); functionDef->getDataRef()->scope["~enclosing_scope"].push_back(scope); - std::map yetToBeInstantiatedTemplateTypes; //So that template types (like T) that have not been placed yet are found and given -/*MULTHERE*/ //a special Type() - baseType = template_type_type - for (auto i : slice(children[0]->getChildren(), 1, -1, 2)) //skip commas - yetToBeInstantiatedTemplateTypes[concatSymbolTree(i)] = new Type(template_type_type); //This may have to be combined with templateTypeReplacements if we do templated member functions inside of templated classes - + std::map yetToBeInstantiatedTemplateTypes; //So that template types (like T) that have not been placed yet are found and given + //a special Type() - baseType = template_type_type + for (auto i : slice(children[0]->getChildren(), 1, -1, 2)) {//skip commas + if (i->getChildren().size() == 1) + yetToBeInstantiatedTemplateTypes[concatSymbolTree(i)] = new Type(template_type_type); //This may have to be combined with templateTypeReplacements if we do templated member functions inside of templated classes + else //has traits + yetToBeInstantiatedTemplateTypes[concatSymbolTree(i->getChildren()[0])] = new Type(template_type_type, parseTraits(i->getChildren()[1])); //This may have to be combined with templateTypeReplacements if we do templated member functions inside of templated classes + } auto transChildren = transformChildren(slice(children,3,-2), std::set(), functionDef, std::vector(), yetToBeInstantiatedTemplateTypes, false); std::cout << "Template function " << functionName << " has these parameters: "; for (auto i : transChildren) @@ -247,8 +266,8 @@ void ASTTransformation::fourthPass(NodeTree* ast, NodeTree* par std::string name = concatSymbolTree(typedefChildren[0]); NodeTree* typeDef = ast->getDataRef()->scope[name][0]; //No overloaded types - //It's an alias - if (typedefChildren[1]->getData().getName() == "type") + //It's an alias. Note that typedefChildren.size() can equal one when it's a regular class with an empty body, i.e. {} + if (typedefChildren.size() > 1 && typedefChildren[1]->getData().getName() == "type") continue; //We're done with aliases too //Do the inside of classes here @@ -280,7 +299,7 @@ NodeTree* ASTTransformation::seachScopeForFunctionDef(NodeTree types.push_back(type); } std::cout << "About to seach scope about " << concatSymbolTree(children[1]) << std::endl; - NodeTree* result = scopeLookup(scope, functionName, types); + NodeTree* result = functionLookup(scope, functionName, types); std::cout << "Done searching scope about " << concatSymbolTree(children[1]) << std::endl; return result; } @@ -304,47 +323,25 @@ NodeTree* ASTTransformation::transform(NodeTree* from, NodeTree NodeTree* newNode = NULL; std::vector*> children = from->getChildren(); std::set skipChildren; -/* - if (name == "translation_unit") { - newNode = new NodeTree(name, ASTData(translation_unit)); - scope = newNode; - topScope = newNode; //Top scope is maintained for templates, which need to add themselves to the top scope from where ever they are instantiated - //One of Kraken's features is that definition order does not matter. This is done by doing a first pass across the translation unit - //to nominally add all the type_def's and function def's to the top scope before they're actually processed - for (NodeTree* i : children) { - if (i->getDataRef()->getName() == "type_def") { - std::string name; - if (i->getChildren()[0]->getData().getName() == "template_dec") // It's a template - name = concatSymbolTree(i->getChildren()[1]); - else //It's not - name = concatSymbolTree(i->getChildren()[0]); - scope->getDataRef()->scope[name].push_back(new NodeTree("type_def", ASTData(type_def, Symbol(name, true, name)))); //Just a placeholder - } - } - std::cout << "The scope here at first intantiation is " << scope->getDataRef()->toString() << std::endl; - } else if (name == "interpreter_directive") { - newNode = new NodeTree(name, ASTData(interpreter_directive)); - } else if (name == "import" && !current.isTerminal()) { - std::string toImport = concatSymbolTree(children[0]); - newNode = new NodeTree(name, ASTData(import, Symbol(toImport, true))); - //Do the imported file too - NodeTree* outsideTranslationUnit = importer->import(toImport + ".krak"); - scope->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) - scope->getDataRef()->scope[i->first].push_back(j); - return newNode; // Don't need children of import - } else */if (name == "identifier") { + if (name == "identifier") { //Make sure we get the entire name std::string lookupName = concatSymbolTree(from); std::cout << "Looking up: " << lookupName << std::endl; - newNode = scopeLookup(scope, lookupName, types); - if (newNode == NULL) { - std::cout << "scope lookup error! Could not find " << lookupName << " in identifier " << std::endl; - throw "LOOKUP ERROR: " + lookupName; - } + if (types.size()) { + newNode = functionLookup(scope, lookupName, types); + if (newNode == NULL) { + std::cout << "scope lookup error! Could not find " << lookupName << " in identifier " << std::endl; + throw "LOOKUP ERROR: " + lookupName; + } + } else { + auto possibleMatches = scopeLookup(scope, lookupName); + if (!possibleMatches.size()) { + std::cout << "scope lookup error! Could not find " << lookupName << " in identifier " << std::endl; + throw "LOOKUP ERROR: " + lookupName; + } + newNode = possibleMatches[0]; + } } else if (name == "type_def") { //If it is an alisis of a type std::string typeAlias; @@ -470,18 +467,6 @@ NodeTree* ASTTransformation::transform(NodeTree* from, NodeTree } else if (name == "expression" || name == "shiftand" || name == "term" || name == "unarad" || name == "access_operation") { //If this is an actual part of an expression, not just a premoted child if (children.size() > 2) { - /* else if (children.size() >= 4) { //Array brackets [] - funcName = "[]"; - std::vector*> transformedChildren; - transformedChildren.push_back(transform(children[0], scope, types, templateTypeReplacements, instantiateTemplates)); - transformedChildren.push_back(transform(children[2], scope, types, templateTypeReplacements, instantiateTemplates)); - NodeTree* function = doFunction(scope, funcName, transformedChildren, templateTypeReplacements); - if (function == NULL) { - std::cout << "scope lookup error! Could not find " << funcName << " in factor " << std::endl; - throw "LOOKUP ERROR: " + funcName; - } - return function; - }*/ NodeTree* lhs = transform(children[0], scope, std::vector(), templateTypeReplacements, instantiateTemplates); //LHS does not inherit types NodeTree* rhs; if (name == "access_operation") { @@ -646,10 +631,17 @@ NodeTree* ASTTransformation::transform(NodeTree* from, NodeTree return transform(children[0], scope, types, templateTypeReplacements, instantiateTemplates); } else if (name == "integer") { newNode = new NodeTree(name, ASTData(value, Symbol(concatSymbolTree(from), true), new Type(integer))); - } else if (name == "float") { - newNode = new NodeTree(name, ASTData(value, Symbol(concatSymbolTree(from), true), new Type(floating))); - } else if (name == "double") { - newNode = new NodeTree(name, ASTData(value, Symbol(concatSymbolTree(from), true), new Type(double_percision))); + } else if (name == "floating_literal") { + std::string literal = concatSymbolTree(from); + ValueType type = double_percision; + if (literal.back() == 'f') { + literal = literal.substr(0, literal.length()-1); + type = floating; + } else if (literal.back() == 'd') { + literal = literal.substr(0, literal.length()-1); + type = double_percision; + } + newNode = new NodeTree(name, ASTData(value, Symbol(literal, true), new Type(type))); } else if (name == "char") { //Is this correct? This might be a useless old thing newNode = new NodeTree(name, ASTData(value, Symbol(concatSymbolTree(children[0]), true), new Type(character, 1))); //Indirection of 1 for array } else if (name == "string" || name == "triple_quoted_string") { @@ -716,7 +708,7 @@ NodeTree* ASTTransformation::doFunction(NodeTree* scope, std:: std::cout << std::endl; NodeTree* operatorMethod = NULL; if (nodes[0]->getDataRef()->valueType && nodes[0]->getDataRef()->valueType->typeDefinition) - operatorMethod = scopeLookup(nodes[0]->getDataRef()->valueType->typeDefinition, lookupOp, mapNodesToTypes(slice(nodes,1,-1))); + operatorMethod = functionLookup(nodes[0]->getDataRef()->valueType->typeDefinition, lookupOp, mapNodesToTypes(slice(nodes,1,-1))); if (operatorMethod) { //Ok, so we construct std::cout << "Early method level operator was found" << std::endl; @@ -738,7 +730,7 @@ NodeTree* ASTTransformation::doFunction(NodeTree* scope, std:: } newNode = new NodeTree(lookup, ASTData(function_call, Symbol(lookup, true))); - NodeTree* function = scopeLookup(scope, lookup, mapNodesToTypes(nodes)); + NodeTree* function = functionLookup(scope, lookup, mapNodesToTypes(nodes)); newNode->addChild(function); newNode->addChildren(nodes); @@ -763,9 +755,8 @@ NodeTree* ASTTransformation::doFunction(NodeTree* scope, std:: return newNode; } -//Search recursively through levels of scope (each ASTData, that is, every node, has its own scope) -//We pass in types so that if we're searching for a function we can find the right overloaded one -NodeTree* ASTTransformation::scopeLookup(NodeTree* scope, std::string lookup, std::vector types) { +//Lookup a function that takes in parameters matching the types passed in +NodeTree* ASTTransformation::functionLookup(NodeTree* scope, std::string lookup, std::vector types) { //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()) { @@ -776,22 +767,17 @@ NodeTree* ASTTransformation::scopeLookup(NodeTree* scope, std: LLElementIterator = languageLevelOperators.find(lookup); if (LLElementIterator != languageLevelOperators.end()) lookup = "operator" + lookup; - //Search the map - auto scopeMap = scope->getDataRef()->scope; - auto elementIterator = scopeMap.find(lookup); - for (auto i : scopeMap) - std::cout << i.first << " "; - std::cout << std::endl; - // - if (elementIterator != scopeMap.end()) { - for (auto i = elementIterator->second.begin(); i != elementIterator->second.end(); i++) { - //Types and functions cannot have the same name, and types very apparently do not have parameter types, so check and short-circuit - if ((*i)->getDataRef()->type == type_def) - return *i; - std::cout << lookup << " has " << elementIterator->second.size() << " possible solutions" << std::endl; + //Look up the name + std::vector*> possibleMatches = scopeLookup(scope, lookup); + std::cout << "Function lookup of " << lookup << " has " << possibleMatches.size() << " possible matches." << std::endl; + if (possibleMatches.size()) { + for (auto i : possibleMatches) { + //We're not looking for types + if (i->getDataRef()->type == type_def) + continue; - std::vector*> children = (*i)->getChildren(); + std::vector*> children = i->getChildren(); //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 @@ -818,20 +804,11 @@ NodeTree* ASTTransformation::scopeLookup(NodeTree* scope, std: } } if (typesMatch) - return *i; + return i; } } - //if it doesn't exist, try the enclosing scope if it exists. - auto enclosingIterator = scopeMap.find("~enclosing_scope"); - if (enclosingIterator != scopeMap.end()) { - // std::cout << "upper scope exists, searching it for " << lookup << std::endl; - NodeTree* upperResult = scopeLookup(enclosingIterator->second[0], lookup, types); - if (upperResult) - return upperResult; - } - //std::cout << "upper scope does not exist" << std::endl; - std::cout << "could not find " << lookup << " in standard scope, checking for operator" << std::endl; + std::cout << "could not find " << lookup << " in standard scopes, checking for operator" << std::endl; //Note that we don't check for types. At some point we should, as we don't know how to add objects/structs without overloaded operators, etc //Also, we've already searched for the element because this is also how we keep track of operator overloading if (LLElementIterator != languageLevelOperators.end()) { @@ -839,7 +816,125 @@ NodeTree* ASTTransformation::scopeLookup(NodeTree* scope, std: return LLElementIterator->second[0]; } std::cout << "Did not find, returning NULL" << std::endl; - return NULL; + return NULL; +} + + +//Lookup function for template functions. It has some extra concerns compared to function lookup, namely traits +NodeTree* ASTTransformation::templateFunctionLookup(NodeTree* scope, std::string lookup, std::vector templateInstantiationTypes, std::vector types) { + std::vector*> mostFittingTemplates; + int bestNumTraitsSatisfied = -1; + auto possibleMatches = scopeLookup(scope, lookup); + std::cout << "Template Function instantiation has " << possibleMatches.size() << " possible matches." << std::endl; + for (auto i : possibleMatches) { + NodeTree* templateSyntaxTree = i->getDataRef()->valueType->templateDefinition; + + //When called without a second parameter, makeTemplateFunctionTypeMap returns a map with blank Types filled in that contain the correct Traits + auto nameTraitsPairs = makeTemplateFunctionNameTraitPairs(templateSyntaxTree->getChildren()[0]); + + //Check if sizes match between the placeholder and actual template types + if (nameTraitsPairs.size() != templateInstantiationTypes.size()) + continue; + + std::map typeMap; + bool traitsEqual = true; + int typeIndex = 0; + int currentTraitsSatisfied = 0; + for (auto j : nameTraitsPairs) { + if (j.second != templateInstantiationTypes[typeIndex]->traits) { + traitsEqual = false; + std::cout << "Traits unequal for " << j.first << " and " << templateInstantiationTypes[typeIndex]->toString() << ": "; + std::copy(j.second.begin(), j.second.end(), std::ostream_iterator(std::cout, " ")); + std::cout << " vs "; + std::copy(templateInstantiationTypes[typeIndex]->traits.begin(), templateInstantiationTypes[typeIndex]->traits.end(), std::ostream_iterator(std::cout, " ")); + std::cout << std::endl; + break; + } + //As we go, build up the typeMap for when we transform the parameters for parameter checking + typeMap[j.first] = templateInstantiationTypes[typeIndex]; + currentTraitsSatisfied += templateInstantiationTypes[typeIndex]->traits.size(); + typeIndex++; + } + if (!traitsEqual) + continue; + + std::vector*> functionParameters = slice(templateSyntaxTree->getChildren(), 3, -2, 2); //skip template, return type, name, intervening commas, and the code block + std::cout << functionParameters.size() << " " << types.size() << std::endl; + if (functionParameters.size() != types.size()) + continue; + + bool parameterTypesMatch = true; + for (int j = 0; j < functionParameters.size(); j++) { + auto paramType = typeFromTypeNode(functionParameters[j]->getChildren()[0], scope, typeMap, false); + std::cout << "Template param type: " << paramType->toString() << " : Needed Type: " << types[j].toString() << std::endl; + if (*paramType != types[j]) { + parameterTypesMatch = false; + std::cout << "Not equal: " << paramType->toString() << " : Needed Type: " << types[j].toString() << std::endl; + break; + } + } + if (!parameterTypesMatch) + continue; + //See if this is a better match than the current best + if (currentTraitsSatisfied > bestNumTraitsSatisfied) { + mostFittingTemplates.clear(); + std::cout << "Function satisfying " << currentTraitsSatisfied << " beats previous " << bestNumTraitsSatisfied << std::endl; + bestNumTraitsSatisfied = currentTraitsSatisfied; + } else if (currentTraitsSatisfied < bestNumTraitsSatisfied) + continue; + mostFittingTemplates.push_back(i); + std::cout << "Current function fits, satisfying " << currentTraitsSatisfied << " traits" << std::endl; + } + if (!mostFittingTemplates.size()) { + std::cout << "No template functions fit for " << lookup << "!" << std::endl; + throw "No matching template functions"; + } else if (mostFittingTemplates.size() > 1) { + std::cout << "Multiple template functions fit with equal number of traits satisfied for " << lookup << "!" << std::endl; + throw "Multiple matching template functions"; + } + return mostFittingTemplates[0]; +} + +//Extract pairs of type names and traits +std::vector>> ASTTransformation::makeTemplateFunctionNameTraitPairs(NodeTree* templateNode) { + std::vector*> templateParams = slice(templateNode->getChildren(), 1, -2, 2); //Skip <, >, and interveaning commas + std::vector>> typePairs; + for (auto i : templateParams) { + if (i->getChildren().size() > 1) + typePairs.push_back(std::make_pair(concatSymbolTree(i->getChildren()[0]), parseTraits(i->getChildren()[1]))); + else + typePairs.push_back(std::make_pair(concatSymbolTree(i->getChildren()[0]), std::set())); + } + return typePairs; +} + +std::map ASTTransformation::makeTemplateFunctionTypeMap(NodeTree* templateNode, std::vector types) { + auto typePairs = makeTemplateFunctionNameTraitPairs(templateNode); + std::map typeMap; + int typeIndex = 0; + std::cout << typePairs.size() << " " << types.size() << std::endl; + for (auto i : typePairs) { + typeMap[i.first] = types[typeIndex]; + std::cout << "Mapping " << i.first << " to " << types[typeIndex]->toString() << std::endl; + typeIndex++; + } + return typeMap; +} + +std::vector*> ASTTransformation::scopeLookup(NodeTree* scope, std::string lookup) { + std::vector*> matches; + std::map*>> scopeMap = scope->getDataRef()->scope; + auto possibleMatches = scopeMap.find(lookup); + if (possibleMatches != scopeMap.end()) + matches.insert(matches.end(), possibleMatches->second.begin(), possibleMatches->second.end()); + + // Add results from our enclosing scope, if it exists + auto enclosingIterator = scopeMap.find("~enclosing_scope"); + if (enclosingIterator != scopeMap.end()) { + std::vector*> upperResult = scopeLookup(enclosingIterator->second[0], lookup); + matches.insert(matches.end(), upperResult.begin(), upperResult.end()); + } + return matches; } //Create a type from a syntax tree. This can get complicated with templates @@ -849,6 +944,7 @@ Type* ASTTransformation::typeFromTypeNode(NodeTree* typeNode, NodeTree* typeDefinition = NULL; + std::set traits; while (typeIn[typeIn.size() - indirection - 1] == '*') indirection++; std::string edited = strSlice(typeIn, 0, -(indirection + 1)); if (edited == "void") @@ -865,8 +961,12 @@ Type* ASTTransformation::typeFromTypeNode(NodeTree* typeNode, NodeTreegetDataRef()->valueType->traits; + } //So either this is an uninstatiated template class type, or this is literally a template type T, and we should get it from our //templateTypeReplacements map. We try this first if (templateTypeReplacements.find(edited) != templateTypeReplacements.end()) { @@ -874,18 +974,19 @@ Type* ASTTransformation::typeFromTypeNode(NodeTree* typeNode, NodeTreeclone(); templateTypeReplacement->modifyIndirection(indirection); return templateTypeReplacement; - } else { - std::cout << edited << " was not found in templateTypeReplacements" << std::endl; - std::cout << "templateTypeReplacements consists of : "; - for (auto i : templateTypeReplacements) - std::cout << i.first << " "; - std::cout << std::endl; } - //If not, we better instantiate it and then add it to the highest (not current) scope - if (typeDefinition == NULL && typeNode->getChildren().size() > 1 && typeNode->getChildren()[1]->getData().getName() == "template_inst") { + std::cout << edited << " was not found in templateTypeReplacements" << std::endl; + std::cout << "templateTypeReplacements consists of : "; + for (auto i : templateTypeReplacements) + std::cout << i.first << " "; + std::cout << std::endl; + + //If not, we better instantiate it and then add it to the highest (not current) scope + if (possibleMatches.size() == 0 && typeNode->getChildren().size() > 1 && typeNode->getChildren()[1]->getData().getName() == "template_inst") { std::cout << "Template type: " << edited << " not yet instantiated" << std::endl; //Look up this template's plain definition. It's type has the syntax tree that we need to parse - NodeTree* templateDefinition = scopeLookup(scope,concatSymbolTree(typeNode->getChildren()[0])); + possibleMatches = scopeLookup(scope,concatSymbolTree(typeNode->getChildren()[0])); + NodeTree* templateDefinition = possibleMatches[0]; if (templateDefinition == NULL) std::cout << "Template definition is null!" << std::endl; else @@ -931,14 +1032,14 @@ Type* ASTTransformation::typeFromTypeNode(NodeTree* typeNode, NodeTreeaddChildren(transformChildren(templateSyntaxTree->getChildren(), skipChildren, typeDefinition, std::vector(), newTemplateTypeReplacement, instantiateTemplates)); } - } else if (typeDefinition == NULL) { + } else if (possibleMatches.size() == 0) { std::cout << "Could not find type " << edited << ", returning NULL" << std::endl; return NULL; } else { - std::cout << "Type: " << edited << " already instantiated with " << typeDefinition << ", will be " << Type(baseType, typeDefinition, indirection).toString() << std::endl; + std::cout << "Type: " << edited << " already instantiated with " << typeDefinition << ", will be " << Type(baseType, typeDefinition, indirection, traits).toString() << std::endl; } } - Type* toReturn = new Type(baseType, typeDefinition, indirection); + Type* toReturn = new Type(baseType, typeDefinition, indirection, traits); std::cout << "Returning type " << toReturn->toString() << std::endl; return toReturn; } @@ -966,7 +1067,7 @@ NodeTree* ASTTransformation::findOrInstantiateFunctionTemplate(std::vec std::cout << " " << i.toString(); std::cout << std::endl; - NodeTree* instantiatedFunction = scopeLookup(scope, fullyInstantiatedName,types); + NodeTree* instantiatedFunction = functionLookup(scope, fullyInstantiatedName, types); //If it already exists, return it if (instantiatedFunction) { std::cout << fullyInstantiatedName << " already exists! Returning" << std::endl; @@ -976,19 +1077,16 @@ NodeTree* ASTTransformation::findOrInstantiateFunctionTemplate(std::vec } //Otherwise, we're going to instantiate it - //Find the template definition - NodeTree* templateDefinition = scopeLookup(scope,functionName,types); + //Find the template definitions + NodeTree* templateDefinition = templateFunctionLookup(scope, functionName, templateActualTypes, types); if (templateDefinition == NULL) { std::cout << functionName << " search turned up null, returing null" << std::endl; return NULL; } NodeTree* templateSyntaxTree = templateDefinition->getDataRef()->valueType->templateDefinition; - std::map newTemplateTypeReplacement; - auto tmunsliced = templateSyntaxTree->getChildren()[0]->getChildren(); - std::vector*> templateParamPlaceholderNodes = slice(tmunsliced, 1, -2, 2);//skip <, >, and commas - for (int i = 0; i < templateParamPlaceholderNodes.size(); i++) - newTemplateTypeReplacement[concatSymbolTree(templateParamPlaceholderNodes[i])] = templateActualTypes[i]; + // Makes a map between the names of the template placeholder parameters and the provided types + std::map newTemplateTypeReplacement = makeTemplateFunctionTypeMap(templateSyntaxTree->getChildren()[0], templateActualTypes); std::vector*> templateChildren = templateSyntaxTree->getChildren(); for (int i = 0; i < templateChildren.size(); i++) diff --git a/src/CGenerator.cpp b/src/CGenerator.cpp index 29cb6ff..20e875e 100644 --- a/src/CGenerator.cpp +++ b/src/CGenerator.cpp @@ -61,12 +61,12 @@ std::string CGenerator::generate(NodeTree* from, NodeTree* enc typedefPoset.addRelationship(children[i], decType->typeDefinition); //Add a dependency } } - //In case there are pointer dependencies. If the typedef has no children, then it is a simple renaming and we don't need to predeclare the class (maybe?) - if (classChildren.size()) + //In case there are pointer dependencies. We don't do this if this is an alias type + if (children[i]->getDataRef()->valueType->typeDefinition == children[i]) output += "struct " + CifyName(children[i]->getDataRef()->symbol.getName()) + ";\n"; else { Type *aliasType = children[i]->getDataRef()->valueType; - if (aliasType->typeDefinition && aliasType->typeDefinition != children[i] && !aliasType->templateDefinition) //Isn't uninstantiated template or 0 parameter class, so must be alias. if typeDefinition isn't null, then it's an alias of a custom, not a primitive, type. + if (aliasType->typeDefinition && !aliasType->templateDefinition) //Isn't uninstantiated template or 0 parameter class, so must be alias. if typeDefinition isn't null, then it's an alias of a custom, not a primitive, type. typedefPoset.addRelationship(children[i], children[i]->getDataRef()->valueType->typeDefinition); //An alias typedef depends on the type it aliases being declared before it } } @@ -147,7 +147,7 @@ std::string CGenerator::generate(NodeTree* from, NodeTree* enc case type_def: if (data.valueType->baseType == template_type) { return "/* non instantiated template " + data.symbol.getName() + " */"; - } else if (children.size() == 0) { + } else if (data.valueType->typeDefinition != from) { return "typedef " + ValueTypeToCType(data.valueType) + " " + data.symbol.getName() + ";"; } else { std::string objectString = "typedef struct __struct_dummy_" + CifyName(data.symbol.getName()) + "__ {\n"; @@ -471,6 +471,11 @@ std::string CGenerator::CifyName(std::string name) { "<", "lessthan", ">", "greaterthan", ">>=", "doubleleftequals", + "(", "openparen", + ")", "closeparen", + "[", "openbracket", + "]", "closebracket", + " ", "space", "->", "arrow" }; int length = sizeof(operatorsToReplace)/sizeof(std::string); //std::cout << "Length is " << length << std::endl; diff --git a/src/Importer.cpp b/src/Importer.cpp index 29eb143..b5758f6 100644 --- a/src/Importer.cpp +++ b/src/Importer.cpp @@ -37,6 +37,7 @@ Importer::Importer(Parser* parserIn, std::vector includePaths) { collapseSymbols.push_back(Symbol("declaration_block", false)); collapseSymbols.push_back(Symbol("type_list", false)); collapseSymbols.push_back(Symbol("template_param_list", false)); + collapseSymbols.push_back(Symbol("trait_list", false)); } Importer::~Importer() { diff --git a/src/RNGLRParser.cpp b/src/RNGLRParser.cpp index 400b4c4..c95a526 100644 --- a/src/RNGLRParser.cpp +++ b/src/RNGLRParser.cpp @@ -110,13 +110,13 @@ NodeTree* RNGLRParser::parseInput(std::string inputString) { std::cout << input[j].toString() << " "; std::cout << std::endl; range = 1; - std::cout << "\n\n\nThe states in the GSS at last frontiers:" << std::endl; +/* std::cout << "\n\n\nThe states in the GSS at last frontiers:" << std::endl; for (int j = (i-range >= 0 ? i-range : 0); j < i; j++) { std::cout << "Frontier:" << j << " (would get): " << input[j].toString() << std::endl; printReconstructedFrontier(j); } std::cout << "\n\n\n\n" << std::endl; - break; + */ break; } //Clear the vector of SPPF nodes created every step diff --git a/src/Type.cpp b/src/Type.cpp index 1114777..f454127 100644 --- a/src/Type.cpp +++ b/src/Type.cpp @@ -7,47 +7,50 @@ Type::Type() { templateDefinition = NULL; } -Type::Type(ValueType typeIn) { - indirection = 0; - baseType = typeIn; - typeDefinition = NULL; - templateDefinition = NULL; -} - Type::Type(ValueType typeIn, int indirectionIn) { indirection = indirectionIn; baseType = typeIn; typeDefinition = NULL; templateDefinition = NULL; - if (indirection < 0) SEGFAULT } -Type::Type(NodeTree* typeDefinitionIn) { +Type::Type(ValueType typeIn, std::set traitsIn) { indirection = 0; - baseType = none; - typeDefinition = typeDefinitionIn; + baseType = typeIn; + traits = traitsIn; + typeDefinition = NULL; templateDefinition = NULL; } + Type::Type(NodeTree* typeDefinitionIn, int indirectionIn) { indirection = indirectionIn; baseType = none; typeDefinition = typeDefinitionIn; templateDefinition = NULL; - if (indirection < 0) SEGFAULT } -Type::Type(ValueType typeIn, NodeTree* typeDefinitionIn, int indirectionIn) { +Type::Type(NodeTree* typeDefinitionIn, std::set traitsIn) { + indirection = 0; + baseType = none; + typeDefinition = typeDefinitionIn; + traits = traitsIn; + templateDefinition = NULL; +} + +Type::Type(ValueType typeIn, NodeTree* typeDefinitionIn, int indirectionIn, std::set traitsIn) { baseType = typeIn; indirection = indirectionIn; typeDefinition = typeDefinitionIn; - templateDefinition = NULL; - if (indirection < 0) SEGFAULT + traits = traitsIn; + templateDefinition = NULL; } -Type::Type(ValueType typeIn, NodeTree* templateDefinitionIn) { + +Type::Type(ValueType typeIn, NodeTree* templateDefinitionIn, std::set traitsIn) { indirection = 0; baseType = typeIn; typeDefinition = NULL; templateDefinition = templateDefinitionIn; + traits = traitsIn; } @@ -55,7 +58,7 @@ Type::~Type() { } const bool Type::operator==(const Type &other) const { - return( baseType == other.baseType && indirection == other.indirection && typeDefinition == other.typeDefinition && templateDefinition == other.templateDefinition); + return( baseType == other.baseType && indirection == other.indirection && typeDefinition == other.typeDefinition && templateDefinition == other.templateDefinition && other.traits == traits); } const bool Type::operator!=(const Type &other) const { @@ -103,16 +106,18 @@ std::string Type::toString() { } for (int i = 0; i < indirection; i++) typeString += "*"; + if (traits.size()) { + typeString += "[ "; + for (auto i : traits) + typeString += i + " "; + typeString += "]"; + } //std::cout << "Extra components of " << typeString << " are " << indirection << " " << typeDefinition << " " << templateDefinition << std::endl; return typeString; } Type* Type::clone() { - return new Type(baseType, typeDefinition, indirection); -} - -void Type::check() { - if (indirection < 0) SEGFAULT + return new Type(baseType, typeDefinition, indirection, traits); } int Type::getIndirection() { @@ -121,7 +126,6 @@ int Type::getIndirection() { void Type::setIndirection(int indirectionIn) { indirection = indirectionIn; - check(); } void Type::increaseIndirection() { diff --git a/stdlib/io.krak b/stdlib/io.krak index 9cf6dab..60b9118 100644 --- a/stdlib/io.krak +++ b/stdlib/io.krak @@ -43,6 +43,15 @@ void print(float toPrint) { return; } +void print(double toPrint) { + __if_comp__ __C__ { + __simple_passthrough__ """ + printf("%f", toPrint); + """ + } + return; +} + void println(float toPrint) { print(toPrint); println(); diff --git a/tests/commentFirstTest.expected_results b/tests/commentFirstTest.expected_results new file mode 100644 index 0000000..a369ea6 --- /dev/null +++ b/tests/commentFirstTest.expected_results @@ -0,0 +1 @@ +1337 diff --git a/tests/commentFirstTest.krak b/tests/commentFirstTest.krak new file mode 100644 index 0000000..4464897 --- /dev/null +++ b/tests/commentFirstTest.krak @@ -0,0 +1,7 @@ +/* Comment first! */ +import io; + +int main() { + println(1337); + return 0; +} diff --git a/tests/functionMultipleTemplateTest.krak b/tests/functionMultipleTemplateTest.krak index f780891..e6d11ce 100644 --- a/tests/functionMultipleTemplateTest.krak +++ b/tests/functionMultipleTemplateTest.krak @@ -6,7 +6,7 @@ template void addAndPrint(T a, J b) { int main() { - addAndPrint(10,12.14159); + addAndPrint(10,12.14159); print("\n"); return 0; diff --git a/tests/traitsTest.expected_results b/tests/traitsTest.expected_results new file mode 100644 index 0000000..04f7294 --- /dev/null +++ b/tests/traitsTest.expected_results @@ -0,0 +1,5 @@ +No Traits +First Trait +Second Trait +Both Traits + diff --git a/tests/traitsTest.krak b/tests/traitsTest.krak new file mode 100644 index 0000000..ff6162e --- /dev/null +++ b/tests/traitsTest.krak @@ -0,0 +1,77 @@ +import io; + +typedef NoTraits {}; + +typedef Trait1 (FirstTrait) {}; +typedef Trait2 (SecondTrait) {}; +typedef TwoTrait (FirstTrait, SecondTrait) {}; +typedef AlreadySpecilized (FirstTrait, SecondTrait) {}; + +template void OneTwoFunc(T obj) { + println("No Traits"); +} + +template void OneTwoFunc(T obj) { + println("First Trait"); +} + +template void OneTwoFunc(T obj) { + println("Second Trait"); +} + +template void OneTwoFunc(T obj) { + println("Both Traits"); +} +/* +template void OneTwoFunc(AlreadySpecilized obj) { + println("Already Specilized"); +} +*/ +//This should work for objects too! +//To test, we cycle the mapping of traits + +/* + *typedef template OneTwoObj (FirstTrait) {}; + *typedef template OneTwoObj (SecondTrait) {}; + *typedef template OneTwoObj (FirstTrait, SecondTrait) {}; + *typedef template OneTwoObj {}; + *typedef template OneTwoObj { + * void proveSpecilized() { + * println("I'm specilized!"); + * } + *}; + */ + +int main() { + NoTraits a; + Trait1 b; + Trait2 c; + TwoTrait d; + AlreadySpecilized e; + + OneTwoFunc(a); + OneTwoFunc(b); + OneTwoFunc(c); + OneTwoFunc(d); +// OneTwoFunc(e); + + println(); + +/* + * OneTwoObj alpha; + * OneTwoObj beta; + * OneTwoObj gamma; + * OneTwoObj delta; + * OneTwoObj epsilon; + * + * OneTwoFunc>(alpha); + * OneTwoFunc>(b); + * OneTwoFunc>(c); + * OneTwoFunc>(d); + * + * //We can't pass along our inner part, so let's just make sure that it is the right object. + * //epsilon.proveSpecilized(); + */ + + return 0; +}