diff --git a/CMakeLists.txt b/CMakeLists.txt index db3eb07..8dc844b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,13 +2,22 @@ cmake_minimum_required (VERSION 2.6) project(Kraken) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") set( MY_INCLUDES ${PROJECT_SOURCE_DIR}/include) -set( MY_SOURCES main.cpp src/Parser.cpp src/LALRParser.cpp src/GraphStructuredStack.cpp src/RNGLRParser.cpp src/ParseAction.cpp src/ParseRule.cpp src/Symbol.cpp src/StringReader.cpp src/State.cpp src/util.cpp src/Lexer.cpp src/RegEx.cpp src/RegExState.cpp src/Table.cpp src/ASTData.cpp src/ASTTransformation.cpp src/CGenerator.cpp src/Type.cpp src/Importer.cpp ) +set( MY_SOURCES main.cpp src/Parser.cpp src/LALRParser.cpp src/GraphStructuredStack.cpp src/RNGLRParser.cpp src/ParseAction.cpp src/ParseRule.cpp src/Symbol.cpp src/StringReader.cpp src/State.cpp src/util.cpp src/Lexer.cpp src/RegEx.cpp src/RegExState.cpp src/Table.cpp src/ASTData.cpp src/ASTTransformation.cpp src/CGenerator.cpp src/Type.cpp src/Importer.cpp src/Tester.cpp ) + +add_custom_target(STDLibCopy ALL) +add_custom_command(TARGET STDLibCopy POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy_directory + "${PROJECT_SOURCE_DIR}/stdlib" + "${PROJECT_BINARY_DIR}/stdlib") include_directories( ${MY_INCLUDES} ) add_executable(kraken ${MY_SOURCES}) + + diff --git a/LICENCE.md b/LICENCE.md new file mode 100644 index 0000000..4717d3f --- /dev/null +++ b/LICENCE.md @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2014 Nathan Christopher Braswell + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/future_features.txt b/future_features.txt new file mode 100644 index 0000000..88b0a92 --- /dev/null +++ b/future_features.txt @@ -0,0 +1,10 @@ +Declaration of a pointer and multiplication are ambigious! +( T* a; maybe either a declaration or a multiplication) + +Fix destructors being placed after return. +Fix functions before declaration? (in class? (this is from an old file)) +Template instantiation without explicit type param +Fix // comment right before top level function declaration. Something to do +with the return as /* comment */ does not have that problem +for in or for each loops +Traits on aliases, maybe that keep their old traits? diff --git a/include/ASTTransformation.h b/include/ASTTransformation.h index fccf125..af5290a 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" @@ -15,17 +18,46 @@ class ASTTransformation: public NodeTransformation { public: ASTTransformation(Importer* importerIn); ~ASTTransformation(); + + //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); + void secondPassDoClassInsides(NodeTree* typeDef, std::vector*> typedefChildren, std::map templateTypeReplacements); + NodeTree* secondPassDeclaration(NodeTree* from, NodeTree* scope, std::map templateTypeReplacements); + NodeTree* secondPassFunction(NodeTree* from, NodeTree* scope, std::map templateTypeReplacements); + + //Third pass redoes all imports to import the new function prototypes and identifiers + void thirdPass(NodeTree* ast); + + //The fourth pass finishes up by doing all function bodies + void fourthPass(NodeTree* ast, NodeTree* parseTree); + NodeTree* searchScopeForFunctionDef(NodeTree* scope, NodeTree* parseTree, std::map templateTypeReplacements); + void fourthPassFunction(NodeTree* from, NodeTree* functionDef, std::map templateTypeReplacements); + virtual NodeTree* transform(NodeTree* from); - NodeTree* transform(NodeTree* from, NodeTree* scope, std::vector types = std::vector()); - std::vector*> transformChildren(std::vector*> children, std::set skipChildren, NodeTree* scope, std::vector types); + NodeTree* transform(NodeTree* from, NodeTree* scope, std::vector types, std::map templateTypeReplacements); + std::vector*> transformChildren(std::vector*> children, std::set skipChildren, NodeTree* scope, std::vector types, std::map templateTypeReplacements); std::vector mapNodesToTypes(std::vector*> nodes); std::string concatSymbolTree(NodeTree* root); - NodeTree* scopeLookup(NodeTree* scope, std::string lookup, std::vector*> nodes); - NodeTree* scopeLookup(NodeTree* scope, std::string lookup, std::vector types = std::vector()); - Type* typeFromString(std::string type, NodeTree* scope); + NodeTree* doFunction(NodeTree* scope, std::string lookup, std::vector*> nodes, std::map templateTypeReplacements); + + 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); + + Type* typeFromTypeNode(NodeTree* typeNode, NodeTree* scope, std::map templateTypeReplacements); + NodeTree* templateClassLookup(NodeTree* scope, std::string name, std::vector templateInstantiationTypes); + NodeTree* findOrInstantiateFunctionTemplate(std::vector*> children, NodeTree* scope, std::vector types, std::map templateTypeReplacements); + std::map makeTemplateFunctionTypeMap(NodeTree* templateNode, std::vector types); + std::vector>> makeTemplateNameTraitPairs(NodeTree* templateNode); private: Importer * importer; - std::map*>> languageLevelScope; + std::map*>> languageLevelReservedWords; + std::map*>> languageLevelOperators; + NodeTree* topScope; //maintained for templates that need to add themselves to the top scope no matter where they are instantiated }; #endif diff --git a/include/CGenerator.h b/include/CGenerator.h index fe8e8b8..a0472fb 100644 --- a/include/CGenerator.h +++ b/include/CGenerator.h @@ -10,6 +10,7 @@ #include "Type.h" #include "util.h" +#include "Poset.h" class CGenerator { @@ -17,15 +18,17 @@ class CGenerator { CGenerator(); ~CGenerator(); void generateCompSet(std::map*> ASTs, std::string outputName); + std::string generateClassStruct(NodeTree* from); std::string generate(NodeTree* from, NodeTree* enclosingObject = NULL); + std::string generateAliasChains(NodeTree* scopeNode, NodeTree* definition); static std::string ValueTypeToCType(Type *type); static std::string ValueTypeToCTypeDecoration(Type *type); - static std::string CifyFunctionName(std::string name); - std::string generateObjectMethod(NodeTree* enclosingObject, NodeTree* from); - + static std::string CifyName(std::string name); + std::string generateObjectMethod(NodeTree* enclosingObject, NodeTree* from, std::string *functionPrototype); + NodeTree* getMethodsObjectType(NodeTree* scope, std::string functionName); std::string generatorString; private: std::string tabs(); int tabLevel; }; -#endif \ No newline at end of file +#endif diff --git a/include/GraphStructuredStack.h b/include/GraphStructuredStack.h index e79a8fe..7d07443 100644 --- a/include/GraphStructuredStack.h +++ b/include/GraphStructuredStack.h @@ -27,6 +27,7 @@ class GraphStructuredStack { void addEdge(NodeTree* start, NodeTree* end, NodeTree* edge); void clear(); + std::vector getFrontier(int frontier); std::string toString(); private: std::vector*>*> gss; diff --git a/include/Importer.h b/include/Importer.h index c0b4f55..8ec0646 100644 --- a/include/Importer.h +++ b/include/Importer.h @@ -14,13 +14,27 @@ #include "CollapseTransformation.h" #include "ASTTransformation.h" +class ASTTransformation; + class Importer { public: - Importer(Parser* parserIn); + Importer(Parser* parserIn, std::vector includePaths); ~Importer(); - NodeTree* import(std::string fileName); + void import(std::string fileName); + NodeTree* getUnit(std::string fileName); + NodeTree* importFirstPass(std::string fileName); + NodeTree* parseAndTrim(std::string fileName); + void registerAST(std::string name, NodeTree* ast, NodeTree* syntaxTree); std::map*> getASTMap(); private: + ASTTransformation *ASTTransformer; + struct importTriplet { + std::string name; + NodeTree* ast; + NodeTree* syntaxTree; + }; + std::vector importedTrips; + std::vector includePaths; Parser* parser; std::vector removeSymbols; std::vector collapseSymbols; diff --git a/include/ParseAction.h b/include/ParseAction.h index 175dd61..a15aca0 100644 --- a/include/ParseAction.h +++ b/include/ParseAction.h @@ -11,6 +11,7 @@ #include #include + class ParseAction { public: enum ActionType { INVALID, REDUCE, SHIFT, ACCEPT, REJECT }; @@ -18,10 +19,11 @@ class ParseAction { ParseAction(ActionType action, ParseRule* reduceRule); ParseAction(ActionType action, int shiftState); ~ParseAction(); - bool const equalsExceptLookahead(const ParseAction &other); - bool const operator==(const ParseAction &other); - bool const operator!=(const ParseAction &other); - std::string toString(); + bool const equalsExceptLookahead(const ParseAction &other) const; + bool const operator==(const ParseAction &other) const; + bool const operator!=(const ParseAction &other) const; + bool const operator<(const ParseAction &other) const; + std::string toString(bool printRuleLookahead = true); static std::string actionToString(ActionType action); ActionType action; @@ -31,4 +33,4 @@ class ParseAction { }; -#endif \ No newline at end of file +#endif diff --git a/include/ParseRule.h b/include/ParseRule.h index dd3ac37..94d602a 100644 --- a/include/ParseRule.h +++ b/include/ParseRule.h @@ -16,10 +16,10 @@ class ParseRule { ParseRule(); ParseRule(Symbol leftHandle, int pointerIndex, std::vector &rightSide, std::vector* lookahead); ~ParseRule(); - const bool equalsExceptLookahead(const ParseRule &other); - bool const operator==(const ParseRule &other); - bool const operator!=(const ParseRule &other); - + const bool equalsExceptLookahead(const ParseRule &other) const; + bool const operator==(const ParseRule &other) const; + bool const operator!=(const ParseRule &other) const; + bool const operator<(const ParseRule &other) const; //Used for ordering so we can put ParseRule's in sets, and also so that ParseActions will have an ordering ParseRule* clone(); void setLeftHandle(Symbol leftHandle); @@ -40,7 +40,7 @@ class ParseRule { void addLookahead(std::vector* lookahead); std::vector* getLookahead(); - std::string toString(); + std::string toString(bool printLookahead = true); std::string toDOT(); private: @@ -51,4 +51,4 @@ class ParseRule { }; -#endif \ No newline at end of file +#endif diff --git a/include/Parser.h b/include/Parser.h index 6f1cc49..25daf02 100644 --- a/include/Parser.h +++ b/include/Parser.h @@ -12,6 +12,7 @@ #include "Table.h" #include +#include #include #include #include @@ -36,8 +37,13 @@ class Parser { void importTable(char* tableData); protected: - std::vector* firstSet(Symbol token); - std::vector* firstSet(Symbol token, std::vector avoidList); + std::vector firstSet(Symbol token, std::vector avoidList = std::vector(), bool addNewTokens = true); + bool isNullable(Symbol token); + bool isNullableHelper(Symbol token, std::set done); + + std::map> tokenFirstSet; + std::map tokenNullable; + std::vector* incrementiveFollowSet(ParseRule* rule); virtual void closure(State* state); virtual void addStates(std::vector< State* >* stateSets, State* state, std::queue* toDo); @@ -65,4 +71,4 @@ class Parser { NodeTree* reduceTreeCombine(Symbol newSymbol, std::vector &symbols); }; -#endif \ No newline at end of file +#endif diff --git a/include/Poset.h b/include/Poset.h new file mode 100644 index 0000000..f29d350 --- /dev/null +++ b/include/Poset.h @@ -0,0 +1,126 @@ + +#ifndef POSET_H +#define POSET_H + +#include +#include +#include +#include + +#include + +#include "util.h" + +template +class Poset { + public: + Poset(); + ~Poset(); + void addRelationship(T first, T second); + void addVertex(T vertex); + bool zeroDependencies(T vertex); + std::set getDependsOn(T dependency); + std::vector getTopoSort(); + static void test(); + private: + //backing data structures + std::map> adjMatrix; + std::set verticies; +}; + +template +Poset::Poset() { + //Nothing needed +} + +template +Poset::~Poset() { + //Ditto +} + + +template +void Poset::addRelationship(T first, T second) { + verticies.insert(first); + verticies.insert(second); + adjMatrix[first][second] = true; +} + +template +void Poset::addVertex(T vertex) { + verticies.insert(vertex); +} + +template +bool Poset::zeroDependencies(T vertex) { + auto depMapItr = adjMatrix.find(vertex); + if (depMapItr == adjMatrix.end()) + return true; + for (auto i : depMapItr->second) + if (i.second == true) + return false; + return true; +} + +template +std::set Poset::getDependsOn(T dependency) { + std::set vertsThatDependOn; + for (auto i : adjMatrix) { + auto depItr = i.second.find(dependency); + if (depItr != i.second.end() && depItr->second) + vertsThatDependOn.insert(i.first); + } + return vertsThatDependOn; +} + +template +std::vector Poset::getTopoSort() { + std::vector sorted; + std::queue toDo; + for (auto i : verticies) + if (zeroDependencies(i)) + toDo.push(i); + while(!toDo.empty()) { + T current = toDo.front(); toDo.pop(); + sorted.push_back(current); + for (T depOnCurrent : getDependsOn(current)) { + adjMatrix[depOnCurrent][current] = false; //Remove the edge to current, since current's now been taken care of + if (zeroDependencies(depOnCurrent)) + toDo.push(depOnCurrent); + } + } + return sorted; +} + + +//would make it just an int specilization, but then we get multiple definition complaints.... +template +void Poset::test() { + std::string result; + { + Poset poset; + poset.addVertex(1000); + for (int i = 0; i < 20; i++) + poset.addRelationship(i,i+1); + result = ""; + for (int i : poset.getTopoSort()) + result += intToString(i) + " "; + //std::cout << result << std::endl; + assert(result == "20 1000 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 "); //Note that sets do not have a set order, so this could change + //This is why the 1000 is in an odd, yet valid, position + } + { + Poset poset; + for (int i = 0; i < 20; i+=2) + poset.addRelationship(i,i+1); + result = ""; + for (int i : poset.getTopoSort()) + result += intToString(i) + " "; + //std::cout << result << std::endl; + assert(result == "1 3 5 7 9 11 13 15 17 19 0 2 4 6 8 10 12 14 16 18 "); + } + + std::cout << "Poset tests passed" << std::endl; +} + +#endif \ No newline at end of file diff --git a/include/RNGLRParser.h b/include/RNGLRParser.h index 6b285e7..74c47ef 100644 --- a/include/RNGLRParser.h +++ b/include/RNGLRParser.h @@ -5,6 +5,8 @@ #include #include #include +#include +#include #include #include "Parser.h" #include "Symbol.h" @@ -16,6 +18,7 @@ class RNGLRParser: public Parser { RNGLRParser(); ~RNGLRParser(); NodeTree* parseInput(std::string inputString); + void printReconstructedFrontier(int frontier); private: void reducer(int i); diff --git a/include/Table.h b/include/Table.h index 6b8ce88..ca2ace9 100644 --- a/include/Table.h +++ b/include/Table.h @@ -1,5 +1,8 @@ #include +#include +#include + #include "util.h" #include "ParseRule.h" #include "ParseAction.h" @@ -20,7 +23,8 @@ class Table { void remove(int stateNum, Symbol tranSymbol); std::vector* get(int state, Symbol token); ParseAction* getShift(int state, Symbol token); - std::string toString(); + std::vector> stateAsParseActionVector(int state); + std::string toString(); private: std::vector< std::vector< std::vector* >* > table; std::vector symbolIndexVec; diff --git a/include/Tester.h b/include/Tester.h new file mode 100644 index 0000000..7bf1815 --- /dev/null +++ b/include/Tester.h @@ -0,0 +1,31 @@ +#include +#include + +#include + +#include "util.h" + +#ifndef TESTER_H +#define TESTER_H + +class Tester { + public: + Tester(std::string krakenInvocation, std::string krakenGrammerLocation); + ~Tester(); + int ssystem(std::string command); + bool run(std::string fileName); + bool compareFiles(std::string file1Path, std::string file2Path); + void cleanExtras(std::string fileName); + + private: + std::string krakenInvocation; + std::string krakenGrammerLocation; + std::string removeCmd; + std::string resultsExtention; + std::string expectedExtention; + std::string krakenExtention; + std::string shell; + std::string changePermissions; + std::string redirect; +}; +#endif diff --git a/include/Type.h b/include/Type.h index 882e143..a47fa7b 100644 --- a/include/Type.h +++ b/include/Type.h @@ -7,31 +7,43 @@ #include #include +#include //Circular dependency class ASTData; #include "ASTData.h" #include "util.h" -enum ValueType {none, void_type, boolean, integer, floating, double_percision, character }; +enum ValueType {none, template_type, template_type_type, void_type, boolean, integer, floating, double_percision, character }; 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, 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; - std::string toString(); - ValueType baseType; + Type* clone(); + std::string toString(bool showTraits = true); + int getIndirection(); + void setIndirection(int indirectionIn); + void increaseIndirection(); + void decreaseIndirection(); + void modifyIndirection(int mod); + + ValueType baseType; NodeTree* typeDefinition; + NodeTree* templateDefinition; + std::map templateTypeReplacement; + std::set traits; + private: int indirection; - private: }; -#endif \ No newline at end of file +#endif diff --git a/include/util.h b/include/util.h index 7f17f51..2a5c70d 100644 --- a/include/util.h +++ b/include/util.h @@ -9,6 +9,9 @@ #include #include #include +#include +#include +#include std::string intToString(int theInt); std::string replaceExEscape(std::string first, std::string search, std::string replace); @@ -16,6 +19,9 @@ std::string strSlice(std::string str, int begin, int end); int findPerenEnd(std::string str, int i); std::vector split(const std::string &str, char delim); std::string join(const std::vector &strVec, std::string joinStr); +std::string readFile(std::istream &file); + + template bool contains(std::vector vec, T item) { for (auto i : vec) @@ -25,15 +31,32 @@ bool contains(std::vector vec, T item) { } template -std::vector slice(std::vector vec, int begin, int end) { +std::vector slice(std::vector vec, int begin, int end, int step = 1) { std::vector toReturn; if (begin < 0) begin += vec.size()+1; if (end < 0) end += vec.size()+1; - for (int i = begin; i < end; i++) + for (int i = begin; i < end; i += step) toReturn.push_back(vec[i]); return toReturn; } +template +bool subset(std::set a, std::set b) { + for (auto i : a) + if (b.find(i) == b.end()) + return false; + return true; +} +/* +std::vector split(std::string str, char delim) { + std::stringstream stream(str); + std::string item; + std::vector results; + while(std::getline(stream, item, delim)) + results.push_back(item); + return results; +} +*/ #endif diff --git a/krakenGrammer.kgm b/krakenGrammer.kgm index 9438a5a..a9af015 100644 --- a/krakenGrammer.kgm +++ b/krakenGrammer.kgm @@ -2,10 +2,19 @@ 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 ; +type = type WS "\*" | "void" | "int" | "float" | "double" | "char" | identifier | identifier WS template_inst ; +dec_type = "\|" WS type WS "\|" ; + +template_inst = "<" WS type_list WS ">" ; +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 template_param | template_param ; +template_param = identifier WS traits | identifier ; import = "import" WS identifier WS ";" ; + interpreter_directive = "#!" WS path | ; path = path path_part | path_part ; path_part = forward_slash alphanumeric | back_slash alphanumeric ; @@ -29,24 +38,33 @@ 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 = type WS func_identifier WS "\(" WS opt_typed_parameter_list WS "\)" WS code_block ; +function = template_dec WS dec_type WS func_identifier WS "\(" WS opt_typed_parameter_list WS "\)" WS code_block | dec_type WS func_identifier WS "\(" WS opt_typed_parameter_list WS "\)" WS code_block ; opt_typed_parameter_list = typed_parameter_list | ; typed_parameter_list = typed_parameter_list WS "," WS typed_parameter | typed_parameter ; -typed_parameter = type WS identifier ; +typed_parameter = dec_type WS identifier ; 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 identifier WS "{" WS class_innerds 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 "}" ; -if_statement = "if" WS "\(" WS boolean_expression WS "\)" WS statement ; +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 ; while_loop = "while" WS boolean_expression WS statement ; @@ -54,7 +72,7 @@ for_loop = "for" WS "\(" WS statement WS boolean_expression WS ";" WS statement return_statement = "return" | "return" WS boolean_expression ; -code_block = "{" WS statement_list WS "}" ; +code_block = "{" WS statement_list WS "}" | "{" WS "}" ; statement_list = statement_list WS statement | statement ; statement = if_statement | while_loop | for_loop | return_statement WS ";" | boolean_expression WS ";" | assignment_statement WS ";" | declaration_statement WS ";" | code_block | if_comp | simple_passthrough ; @@ -62,26 +80,25 @@ function_call = unarad "\(" WS opt_parameter_list WS "\)" ; boolean_expression = boolean_expression WS "\|\|" WS and_boolean_expression | and_boolean_expression ; and_boolean_expression = and_boolean_expression "&&" bool_exp | bool_exp ; -bool_exp = "!" WS bool_exp | expression WS comparator WS expression | bool | expression ; +bool_exp = expression WS comparator WS expression | 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 | function_call | bool | string | character | "\(" WS boolean_expression WS "\)" | access_operation ; -number = integer | float | double ; +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 | 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 ; -declaration_statement = type WS identifier WS "=" WS boolean_expression | type WS identifier ; +declaration_statement = dec_type WS identifier WS "=" WS boolean_expression | dec_type WS identifier | dec_type WS identifier WS "." WS identifier WS "\(" WS opt_parameter_list WS "\)" ; 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" ; +integer = sign numeric | sign hexadecimal ; +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/main.cpp b/main.cpp index 90028d0..f33e2ed 100644 --- a/main.cpp +++ b/main.cpp @@ -14,24 +14,56 @@ #include "Importer.h" #include "ASTData.h" #include "CGenerator.h" +#include "Poset.h" #include "util.h" +#include "Tester.h" int main(int argc, char* argv[]) { - if (argc == 2 && std::string(argv[1]) == "--test") { + std::vector includePaths; + includePaths.push_back(""); //Local + + if (argc <= 1) { + std::cout << "Kraken invocation: kraken sourceFile.krak grammerFile.kgm outputName" << std::endl; + std::cout << "Or for testing do: kraken --test [optional list of names of file (.krak .expected_results) without extentions to run]" << std::endl; + return 0; + } + + if (argc >= 2 && std::string(argv[1]) == "--test") { StringReader::test(); RegEx::test(); Lexer::test(); //std::cout << strSlice("123", 0, -1) << std::endl; + Poset::test(); + + if (argc >= 3) { + std::string testResults, line; + int passed = 0, failed = 0; + Tester test(argv[0], "../krakenGrammer.kgm"); + for (int i = 2; i < argc; i++) { + bool result = test.run(argv[i]); + if (result) + line = std::string(argv[i]) + "\t\tpassed!\n", passed++; + else + line = std::string(argv[i]) + "\t\tFAILED!\n", failed++; + std::cout << line << std::endl; + testResults += line; + } + std::cout << "===========Done Testing===========" << std::endl; + std::cout << testResults << std::endl; + std::cout << "Test results: " << passed << "/" << passed+failed << std::endl; + } return 0; } - + std::string krakenDir = argv[0]; + krakenDir = strSlice(krakenDir, 0, -(std::string("kraken").length()+1)); + includePaths.push_back(krakenDir + "stdlib/"); //Add the stdlib directory that exists in the same directory as the kraken executable to the path std::string programName = argv[1]; std::string grammerFileString = argv[2]; std::string outputName = argv[3]; std::ifstream grammerInFile, compiledGrammerInFile; - std::ofstream /*outFileC,*/ compiledGrammerOutFile; + std::ofstream compiledGrammerOutFile; grammerInFile.open(grammerFileString); if (!grammerInFile.is_open()) { @@ -40,17 +72,9 @@ int main(int argc, char* argv[]) { } compiledGrammerInFile.open(grammerFileString + ".comp", std::ios::binary | std::ios::ate); - if (!compiledGrammerInFile.is_open()) { + if (!compiledGrammerInFile.is_open()) std::cout << "Problem opening compiledGrammerInFile " << grammerFileString + ".comp" << "\n"; - //return(1); - } -/* - outFileC.open((outputName + ".c").c_str()); - if (!outFileC.is_open()) { - std::cout << "Probelm opening third output file " << outputName + ".c" << "\n"; - return(1); - } - */ + //Read the input file into a string std::string grammerInputFileString; std::string line; @@ -63,8 +87,6 @@ int main(int argc, char* argv[]) { //LALRParser parser; RNGLRParser parser; parser.loadGrammer(grammerInputFileString); - //std::cout << "Creating State Set from Main" << std::endl; - //std::cout << "\nState Set" << std::endl; //Start binary stuff bool compGramGood = false; @@ -88,7 +110,6 @@ int main(int argc, char* argv[]) { } else { compGramGood = true; std::cout << "Grammer file is up to date." << std::endl; - //int tableLength = *((int*)(binaryTablePointer + 4 + sizeof(int) + gramStringLength)); parser.importTable(binaryTablePointer + 4 + sizeof(int) + gramStringLength); //Load table starting at the table section } } else { @@ -118,40 +139,23 @@ int main(int argc, char* argv[]) { } //End binary stuff - //std::cout << "finished State Set from Main" << std::endl; - //std::cout << "Doing stateSetToString from Main" << std::endl; - // std::cout << "\n\n\n\n\n\n\n\n\n\nState Set toString" << std::endl; - // std::cout << parser.stateSetToString() << std::endl; - // std::cout << "finished stateSetToString from Main" << std::endl; - // std::cout << "\n\n\n\n\n\n\n\n\n\nTable" << std::endl; - // std::cout << parser.tableToString() << std::endl; - // std::cout << "\n\n\n\n\n\n\n\n\n\nGrammer Input File" << std::endl; - // std::cout << grammerInputFileString << std::endl; - // std::cout << "\n\n\n\n\n\n\n\n\n\nGrammer toString" << std::endl; - // std::cout << parser.grammerToString() << std::endl; - //std::cout << parser.grammerToDOT() << std::endl; - - //outFile << parser.grammerToDOT() << std::endl; std::cout << "\nParsing" << std::endl; - Importer importer(&parser); + Importer importer(&parser, includePaths); + + for (auto i : includePaths) + std::cout << i << std::endl; - /*NodeTree* AST =*/ importer.import(programName); std::map*> ASTs = importer.getASTMap(); - //Do optomization, etc. here. + //Do optimization, etc. here. //None at this time, instead going straight to C in this first (more naive) version //Code generation //For right now, just C CGenerator().generateCompSet(ASTs, outputName); - /* - std::string c_code = CGenerator().generate(AST); - outFileC << c_code << std::endl; - outFileC.close(); -*/ return(0); } - + diff --git a/src/ASTTransformation.cpp b/src/ASTTransformation.cpp index c91572a..c883adf 100644 --- a/src/ASTTransformation.cpp +++ b/src/ASTTransformation.cpp @@ -2,98 +2,427 @@ ASTTransformation::ASTTransformation(Importer *importerIn) { importer = importerIn; - //Set up language level special scope. (the final scope checked) + topScope = NULL; + + //Set up language level reserved identifier scope (only this, right now) + languageLevelReservedWords["this"].push_back(new NodeTree("identifier", ASTData(identifier, Symbol("this", true), NULL))); + + //Set up language level special scope. (the final scope checked) //Note the NULL type - languageLevelScope["+"].push_back( new NodeTree("function", ASTData(function, Symbol("+", true), NULL))); - languageLevelScope["-"].push_back(new NodeTree("function", ASTData(function, Symbol("-", true), NULL))); - languageLevelScope["*"].push_back(new NodeTree("function", ASTData(function, Symbol("*", true), NULL))); - languageLevelScope["&"].push_back(new NodeTree("function", ASTData(function, Symbol("&", true), NULL))); - languageLevelScope["--"].push_back(new NodeTree("function", ASTData(function, Symbol("--", true), NULL))); - languageLevelScope["++"].push_back(new NodeTree("function", ASTData(function, Symbol("++", true), NULL))); - languageLevelScope["=="].push_back(new NodeTree("function", ASTData(function, Symbol("==", true), NULL))); - languageLevelScope["<="].push_back(new NodeTree("function", ASTData(function, Symbol("<=", true), NULL))); - languageLevelScope[">="].push_back(new NodeTree("function", ASTData(function, Symbol(">=", true), NULL))); - languageLevelScope["<"].push_back(new NodeTree("function", ASTData(function, Symbol("<", true), NULL))); - languageLevelScope[">"].push_back(new NodeTree("function", ASTData(function, Symbol(">", true), NULL))); - languageLevelScope["&&"].push_back(new NodeTree("function", ASTData(function, Symbol("&&", true), NULL))); - languageLevelScope["||"].push_back(new NodeTree("function", ASTData(function, Symbol("||", true), NULL))); - languageLevelScope["!"].push_back(new NodeTree("function", ASTData(function, Symbol("!", true), NULL))); - languageLevelScope["*="].push_back(new NodeTree("function", ASTData(function, Symbol("*=", true), NULL))); - languageLevelScope["+="].push_back(new NodeTree("function", ASTData(function, Symbol("+=", true), NULL))); - languageLevelScope["-="].push_back(new NodeTree("function", ASTData(function, Symbol("-=", true), NULL))); - languageLevelScope["."].push_back(new NodeTree("function", ASTData(function, Symbol(".", true), NULL))); - languageLevelScope["->"].push_back(new NodeTree("function", ASTData(function, Symbol("->", true), NULL))); + languageLevelOperators["+"].push_back(new NodeTree("function", ASTData(function, Symbol("+", true), NULL))); + languageLevelOperators["-"].push_back(new NodeTree("function", ASTData(function, Symbol("-", true), NULL))); + languageLevelOperators["*"].push_back(new NodeTree("function", ASTData(function, Symbol("*", true), NULL))); + languageLevelOperators["/"].push_back(new NodeTree("function", ASTData(function, Symbol("/", true), NULL))); + languageLevelOperators["%"].push_back(new NodeTree("function", ASTData(function, Symbol("%", true), NULL))); + languageLevelOperators["&"].push_back(new NodeTree("function", ASTData(function, Symbol("&", true), NULL))); + languageLevelOperators["--"].push_back(new NodeTree("function", ASTData(function, Symbol("--", true), NULL))); + languageLevelOperators["++"].push_back(new NodeTree("function", ASTData(function, Symbol("++", true), NULL))); + languageLevelOperators["=="].push_back(new NodeTree("function", ASTData(function, Symbol("==", true), new Type(boolean)))); + languageLevelOperators["<="].push_back(new NodeTree("function", ASTData(function, Symbol("<=", true), new Type(boolean)))); + languageLevelOperators[">="].push_back(new NodeTree("function", ASTData(function, Symbol(">=", true), new Type(boolean)))); + languageLevelOperators["<"].push_back(new NodeTree("function", ASTData(function, Symbol("<", true), new Type(boolean)))); + languageLevelOperators[">"].push_back(new NodeTree("function", ASTData(function, Symbol(">", true), new Type(boolean)))); + languageLevelOperators["&&"].push_back(new NodeTree("function", ASTData(function, Symbol("&&", true), new Type(boolean)))); + languageLevelOperators["||"].push_back(new NodeTree("function", ASTData(function, Symbol("||", true), new Type(boolean)))); + languageLevelOperators["!"].push_back(new NodeTree("function", ASTData(function, Symbol("!", true), new Type(boolean)))); + languageLevelOperators["*="].push_back(new NodeTree("function", ASTData(function, Symbol("*=", true), NULL))); + languageLevelOperators["+="].push_back(new NodeTree("function", ASTData(function, Symbol("+=", true), NULL))); + languageLevelOperators["-="].push_back(new NodeTree("function", ASTData(function, Symbol("-=", true), NULL))); + languageLevelOperators["."].push_back(new NodeTree("function", ASTData(function, Symbol(".", true), NULL))); + languageLevelOperators["->"].push_back(new NodeTree("function", ASTData(function, Symbol("->", true), NULL))); + languageLevelOperators["[]"].push_back(new NodeTree("function", ASTData(function, Symbol("[]", true), NULL))); } ASTTransformation::~ASTTransformation() { // } -NodeTree* ASTTransformation::transform(NodeTree* from) { - //Set up top scope - return transform(from, NULL, std::vector()); +//First pass defines all type_defs (objects and ailises) +NodeTree* ASTTransformation::firstPass(std::string fileName, NodeTree* parseTree) { + 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 + + //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) { + 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]); + 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. + //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); + firstDec->getDataRef()->scope["~enclosing_scope"].push_back(translationUnit); + } + } + + //Now go through and do all imports + //We do this second so that if an import also imports us, all of our stuff has already been defined + for (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)))); + //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); + } + } + + return translationUnit; } -NodeTree* ASTTransformation::transform(NodeTree* from, NodeTree* scope, std::vector types) { +std::set 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 + std::vector*> children = parseTree->getChildren(); + + //Go through and declare data internal to objects as well as all function prototypes (methods and otherwise) + //Note that this pass can instantiate class templates + for (NodeTree* i : children) { + if (i->getDataRef()->getName() == "type_def") { + if (i->getChildren()[0]->getData().getName() == "template_dec") // It's a template + 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 (besides uninstantiated templates, which can have multiple versions based on types or specilizations) + + //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()); + 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 + // std::cout << name << " alias's to " << aliasedType->typeDefinition << std::endl; + // std::cout << "that is " << aliasedType->typeDefinition->getDataRef()->toString() << std::endl; + continue; + } + //Do the inside of classes here + secondPassDoClassInsides(typeDef, typedefChildren, std::map()); + } else if (i->getDataRef()->getName() == "function") { + //Do prototypes of functions + ast->addChild(secondPassFunction(i, ast, std::map())); + } else if (i->getDataRef()->getName() == "declaration_statement") { + //Do declaration statements + ast->addChild(secondPassDeclaration(i, ast, std::map())); + } + } +} + +void ASTTransformation::secondPassDoClassInsides(NodeTree* typeDef, std::vector*> typedefChildren, std::map templateTypeReplacements) { + //We pull out this functionality into a new function because this is used in typeFromTypeNode to partially instantiate templates + for (NodeTree* j : typedefChildren) { + if (j->getDataRef()->getName() == "declaration_statement") { + //do declaration + typeDef->addChild(secondPassDeclaration(j, typeDef, templateTypeReplacements)); + } else if (j->getDataRef()->getName() == "function") { + //do member method + typeDef->addChild(secondPassFunction(j, typeDef, templateTypeReplacements)); + } + } +} + +//This function may need to partially instantiate a class template +NodeTree* ASTTransformation::secondPassDeclaration(NodeTree* from, NodeTree* scope, std::map templateTypeReplacements) { + //Check here for method call (an error here) + NodeTree* decStmt = new NodeTree("declaration_statement", ASTData(declaration_statement)); + std::string newIdentifierStr = concatSymbolTree(from->getChildren()[1]); + Type* identifierType = typeFromTypeNode(from->getChildren()[0], scope, templateTypeReplacements); + std::cout << "Declaring an identifier " << newIdentifierStr << " to be of type " << identifierType->toString() << std::endl; + NodeTree* newIdentifier = new NodeTree("identifier", ASTData(identifier, Symbol(newIdentifierStr, true), identifierType)); + scope->getDataRef()->scope[newIdentifierStr].push_back(newIdentifier); + decStmt->getDataRef()->scope["~enclosing_scope"].push_back(scope); + decStmt->addChild(newIdentifier); + + return decStmt; +} + +//This function may need to partially instantiate a class template +NodeTree* ASTTransformation::secondPassFunction(NodeTree* from, NodeTree* scope, std::map templateTypeReplacements) { + //If this is a function template + std::vector*> children = from->getChildren(); + NodeTree* functionDef = NULL; + std::string functionName; + if (children[0]->getData().getName() == "template_dec") { + functionName = concatSymbolTree(children[2]); + 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 + //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); + std::cout << "Template function " << functionName << " has these parameters: "; + for (auto i : transChildren) + std::cout << "||" << i->getDataRef()->toString() << "|| "; + std::cout << "DoneList" << std::endl; + functionDef->addChildren(transChildren); + + std::cout << "Finished Non-Instantiated Template function " << functionName << std::endl; + return functionDef; + } + functionName = concatSymbolTree(children[1]); + functionDef = new NodeTree("function", ASTData(function, Symbol(functionName, true), typeFromTypeNode(children[0], scope, templateTypeReplacements))); + scope->getDataRef()->scope[functionName].push_back(functionDef); + functionDef->getDataRef()->scope["~enclosing_scope"].push_back(scope); + //We only do the parameter nodes. We don't do the body yet, as this is the secondPass + auto transChildren = transformChildren(slice(children,2,-2), std::set(), functionDef, std::vector(), templateTypeReplacements); + + // std::cout << "REGULAR function " << functionName << " has " << transChildren.size() << " parameters: "; + // for (auto i : transChildren) + // std::cout << "||" << i->getDataRef()->toString() << "|| "; + // std::cout << "DoneList" << std::endl; + + + functionDef->addChildren(transChildren); + return functionDef; +} + + + +//Third pass redoes all imports to import the new function prototypes and identifiers +void ASTTransformation::thirdPass(NodeTree* ast) { + std::vector*> children = ast->getChildren(); + //Go through and do all imports again + for (NodeTree* i : children) { + if (i->getDataRef()->type == import) { + std::string toImport = i->getDataRef()->symbol.getName(); + 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); + else + std::cout << "Not Copying " << i->first << std::endl; + } + } + } +} + +//The fourth pass finishes up by doing all function bodies +void ASTTransformation::fourthPass(NodeTree* ast, NodeTree* parseTree) { + topScope = ast; //Top scope is maintained for templates, which need to add themselves to the top scope from where ever they are instantiated + std::vector*> children = parseTree->getChildren(); + + //Go through and finish both regular functions and class methods + //Note that this pass can instantiate class AND function templates + for (NodeTree* i : children) { + if (i->getDataRef()->getName() == "type_def") { + if (i->getChildren()[0]->getData().getName() == "template_dec") // It's a template + continue; //We've already set up the class templates + std::vector*> typedefChildren = i->getChildren(); + std::string name = concatSymbolTree(typedefChildren[0]); + NodeTree* typeDef = ast->getDataRef()->scope[name][0]; //No overloaded types + + //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 + for (NodeTree* j : typedefChildren) { + if (j->getDataRef()->getName() == "function") { + fourthPassFunction(j, searchScopeForFunctionDef(typeDef, j, std::map()), std::map()); //do member method + } + } + } else if (i->getDataRef()->getName() == "function") { + //Do prototypes of functions + if (i->getChildren()[0]->getData().getName() == "template_dec") + continue; //We've already set up function templates + fourthPassFunction(i, searchScopeForFunctionDef(ast, i, std::map()), std::map()); + } + } + + // We do these here, in a loop, so that we can do mututally recursive definitions + // even inside of class templates. As its methods may cause partial instantiation of + // other class templates, we need to do this until the size no longer changes. + std::vector*> classTemplates; + int lastSize = 0; + while (lastSize != ast->getDataRef()->scope.size()) { + lastSize = ast->getDataRef()->scope.size(); + classTemplates.clear(); + for (auto i : ast->getDataRef()->scope) { + if (i.second[0]->getDataRef()->type == type_def && i.second[0]->getDataRef()->valueType->templateTypeReplacement.size()) { + classTemplates.push_back(i.second[0]); + std::cout << "Saving " << i.second[0]->getDataRef()->toString() << " to instantiate." << std::endl; + } + } + for (auto i : classTemplates) { + Type* classTemplateType = i->getDataRef()->valueType; + std::cout << "Instantiating template " << i->getDataRef()->toString() << std::endl; + for (NodeTree* j : classTemplateType->templateDefinition->getChildren()) + if (j->getDataRef()->getName() == "function") + fourthPassFunction(j, searchScopeForFunctionDef(i, j, classTemplateType->templateTypeReplacement), classTemplateType->templateTypeReplacement); //do member method + classTemplateType->templateTypeReplacement.clear(); // This template has been fully instantiated, clear it's map so it won't be instantiated again + } + } +} + +//This function finds the right AST definition in a scope given its parseTree +NodeTree* ASTTransformation::searchScopeForFunctionDef(NodeTree* scope, NodeTree* parseTree, std::map templateTypeReplacements) { + std::string functionName = concatSymbolTree(parseTree->getChildren()[1]); + std::vector types; + std::vector*> children = parseTree->getChildren(); + //Skipping the initial return type and identifier as well as the final code block + std::cout << "\n Searching scope for function def, function is :" << concatSymbolTree(children[1]) << ", children size is " << children.size() << std::endl; + for (int i = 2; i < children.size()-1; i+=2) { //Skip over commas + std::cout << "Making type for lookup ||" << concatSymbolTree(children[i]) << "||" << std::endl; + Type type = *typeFromTypeNode(children[i]->getChildren()[0], scope, templateTypeReplacements); + std::cout << "Type made: " << type.toString() << std::endl; + types.push_back(type); + } + std::cout << "About to search scope about " << concatSymbolTree(children[1]) << std::endl; + NodeTree* result = functionLookup(scope, functionName, types); + std::cout << "Done searching scope about " << concatSymbolTree(children[1]) << std::endl; + return result; +} + +//This function does the function bodies given its start (the prototype) +//It is used in the fourth pass to finish things up +//Note that it may instantiate class OR function templates, which need to be fully instantiated +void ASTTransformation::fourthPassFunction(NodeTree* from, NodeTree* functionDef, std::map templateTypeReplacements) { + NodeTree* codeBlock = from->getChildren()[from->getChildren().size()-1]; + functionDef->addChild(transform(codeBlock, functionDef, std::vector(), templateTypeReplacements)); +} + +NodeTree* ASTTransformation::transform(NodeTree* from) { + //Set up top scope + return transform(from, NULL, std::vector(), std::map()); +} + +NodeTree* ASTTransformation::transform(NodeTree* from, NodeTree* scope, std::vector types, std::map templateTypeReplacements) { Symbol current = from->getData(); std::string name = current.getName(); NodeTree* newNode = NULL; std::vector*> children = from->getChildren(); std::set skipChildren; - if (name == "translation_unit") { - newNode = new NodeTree(name, ASTData(translation_unit)); - scope = newNode; - } 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; - } else if (newNode->getDataRef()->symbol.getName() !=lookupName) { - //This happens when the lookup name denotes a member of an object, i.e. obj.foo - //The newNode points to obj, not foo. - } - //newNode = new NodeTree(name, ASTData(identifier, Symbol(concatSymbolTree(children[0]), true))); + if (types.size()) { + newNode = functionLookup(scope, lookupName, types); + if (newNode == NULL) { + std::cout << "scope lookup error! Could not find " << lookupName << " in identifier (functionLookup)" << 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 (scopeLookup)" << std::endl; + throw "LOOKUP ERROR: " + lookupName; + } + newNode = possibleMatches[0]; + } } else if (name == "type_def") { - std::string typeAlias = concatSymbolTree(children[0]); //If it is an alisis of a type + std::string typeAlias; + std::cout << "The scope here at type_def is " << scope->getDataRef()->toString() << std::endl; if (children[1]->getData().getName() == "type") { - newNode = new NodeTree(name, ASTData(type_def, Symbol(typeAlias, true, typeAlias), typeFromString(concatSymbolTree(children[1]), scope))); - skipChildren.insert(1); //Don't want any children, it's unnecessary for ailising + typeAlias = concatSymbolTree(children[0]); + newNode = scope->getDataRef()->scope[typeAlias][0]; //The node for this type_def has already been made by translation_unit. + //This is done so that types that reference each other can be declared in any order + + newNode->getDataRef()->valueType = typeFromTypeNode(children[1], scope, templateTypeReplacements); + skipChildren.insert(0); //Don't want any children, it's unnecessary for ailising + skipChildren.insert(1); } else { //Is a struct or class - newNode = new NodeTree(name, ASTData(type_def, Symbol(typeAlias, true, typeAlias))); - newNode->getDataRef()->valueType = new Type(newNode); //Type is self-referential since this is the definition + Type* objectType = NULL; + if (children[0]->getData().getName() == "template_dec") { + typeAlias = concatSymbolTree(children[1]); + std::cout << "Template Type!"<getDataRef()->scope[typeAlias][0]; //The node for this type_def has already been made by translation_unit. + //This is done so that types that reference each other can be declared in any order + // std::cout << "typeAlias is " << typeAlias << " and newNode is " << newNode << std::endl; + + //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. + objectType = new Type(template_type, from); + } else { + typeAlias = concatSymbolTree(children[0]); + + newNode = scope->getDataRef()->scope[typeAlias][0]; //The node for this type_def has already been made by translation_unit. + //This is done so that types that reference each other can be declared in any order + + objectType = new Type(newNode); + skipChildren.insert(0); //Identifier lookup will be ourselves, as we just added ourselves to the scope + } + newNode->getDataRef()->valueType = objectType; //Type is self-referential since this is the definition } - scope->getDataRef()->scope[typeAlias].push_back(newNode); + //scope->getDataRef()->scope[typeAlias].push_back(newNode); newNode->getDataRef()->scope["~enclosing_scope"].push_back(scope); + + //Templates are done here. No need to go farther + if (children[0]->getData().getName() == "template_dec") + return newNode; scope = newNode; - skipChildren.insert(0); //Identifier lookup will be ourselves, as we just added ourselves to the scope - //return newNode; } else if (name == "function") { - std::string functionName = concatSymbolTree(children[1]); - newNode = new NodeTree(name, ASTData(function, Symbol(functionName, true), typeFromString(concatSymbolTree(children[0]), scope))); + std::string functionName; +/*MULTHERE*/ //If this is a function template + if (children[0]->getData().getName() == "template_dec") { + functionName = concatSymbolTree(children[2]); + newNode = new NodeTree(name, ASTData(function, Symbol(functionName, true), new Type(template_type, from))); + scope->getDataRef()->scope[functionName].push_back(newNode); + newNode->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 + //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 + + auto transChildren = transformChildren(slice(children,3,-2), std::set(), newNode, types, yetToBeInstantiatedTemplateTypes); + std::cout << "Template function " << functionName << " has these parameters: "; + for (auto i : transChildren) + std::cout << "||" << i->getDataRef()->toString() << "|| "; + std::cout << "??||" << std::endl; + newNode->addChildren(transChildren); + + std::cout << "Finished Non-Instantiated Template function " << functionName << std::endl; + return newNode; + } + functionName = concatSymbolTree(children[1]); + newNode = new NodeTree(name, ASTData(function, Symbol(functionName, true), typeFromTypeNode(children[0], scope, templateTypeReplacements))); skipChildren.insert(0); skipChildren.insert(1); scope->getDataRef()->scope[functionName].push_back(newNode); newNode->getDataRef()->scope["~enclosing_scope"].push_back(scope); scope = newNode; - + // auto transChildren = transformChildren(children, skipChildren, scope, types); // std::cout << functionName << " "; // for (auto i : transChildren) @@ -101,8 +430,8 @@ NodeTree* ASTTransformation::transform(NodeTree* from, NodeTree // std::cout << "??||" << std::endl; // newNode->addChildren(transChildren); // return newNode; - - std::cout << "finished function " << functionName << std::endl; + + std::cout << "finished function (kinda, not children) " << functionName << std::endl; } else if (name == "code_block") { newNode = new NodeTree(name, ASTData(code_block)); newNode->getDataRef()->scope["~enclosing_scope"].push_back(scope); @@ -110,101 +439,98 @@ NodeTree* ASTTransformation::transform(NodeTree* from, NodeTree } else if (name == "typed_parameter") { //newNode = transform(children[1]); //Transform to get the identifier std::string parameterName = concatSymbolTree(children[1]); - std::string typeString = concatSymbolTree(children[0]);//Get the type (left child) and set our new identifer to be that type - newNode = new NodeTree("identifier", ASTData(identifier, Symbol(parameterName, true), typeFromString(typeString, scope))); + std::cout << "Doing typed parameter " << parameterName << std::endl; + //std::string typeString = concatSymbolTree(children[0]);//Get the type (left child) and set our new identifer to be that type + newNode = new NodeTree("identifier", ASTData(identifier, Symbol(parameterName, true), typeFromTypeNode(children[0], scope, templateTypeReplacements))); scope->getDataRef()->scope[parameterName].push_back(newNode); newNode->getDataRef()->scope["~enclosing_scope"].push_back(scope); + std::cout << "Done doing typed_parameter " << parameterName << std::endl; return newNode; } else if (name == "boolean_expression" || name == "and_boolean_expression" || name == "bool_exp") { //If this is an actual part of an expression, not just a premoted term if (children.size() > 1) { //We do children first so we can do appropriate scope searching with types (yay operator overloading!) skipChildren.insert(1); - std::vector*> transformedChildren = transformChildren(children, skipChildren, scope, types); + std::vector*> transformedChildren = transformChildren(children, skipChildren, scope, types, templateTypeReplacements); std::string functionCallString = concatSymbolTree(children[1]); - NodeTree* function = scopeLookup(scope, functionCallString, transformedChildren); + NodeTree* function = doFunction(scope, functionCallString, transformedChildren, templateTypeReplacements); if (function == NULL) { std::cout << "scope lookup error! Could not find " << functionCallString << " in boolean stuff " << std::endl; - throw "LOOKUP ERROR: " + functionCallString; + throw "LOOKUP ERROR: " + functionCallString; } - newNode = new NodeTree(functionCallString, ASTData(function_call, function->getDataRef()->valueType)); - newNode->addChild(function); // First child of function call is a link to the function - newNode->addChildren(transformedChildren); + newNode = function; + // newNode = new NodeTree(functionCallString, ASTData(function_call, function->getDataRef()->valueType)); + // newNode->addChild(function); // First child of function call is a link to the function + // newNode->addChildren(transformedChildren); } else { //std::cout << children.size() << std::endl; if (children.size() == 0) return new NodeTree(); - return transform(children[0], scope, types); //Just a promoted term, so do child + return transform(children[0], scope, types, templateTypeReplacements); //Just a promoted term, so do child } //Here's the order of ops stuff - } else if (name == "expression" || name == "shiftand" || name == "term" || name == "unarad" || name == "access_operation") { //unarad can ride through, it should always just be a promoted child + } 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) { - NodeTree* lhs = transform(children[0], scope); //LHS does not inherit types + NodeTree* lhs = transform(children[0], scope, std::vector(), templateTypeReplacements); //LHS does not inherit types NodeTree* rhs; - if (name == "access_operation") - rhs = transform(children[2], lhs->getDataRef()->valueType->typeDefinition, types); //If an access operation, then the right side will be in the lhs's type's scope + if (name == "access_operation") { + std::cout << "lhs is: " << lhs->getDataRef()->toString() << std::endl; + rhs = transform(children[2], lhs->getDataRef()->valueType->typeDefinition, types, templateTypeReplacements); //If an access operation, then the right side will be in the lhs's type's scope + } else - rhs = transform(children[2], scope, types); + rhs = transform(children[2], scope, types, templateTypeReplacements); std::string functionCallName = concatSymbolTree(children[1]); - //std::cout << "scope lookup from expression or similar" << std::endl; + if (functionCallName == "[") + functionCallName = "[]"; //fudge the lookup of brackets because only one is at children[1] (the other is at children[3]) + //std::cout << "scope lookup from expression or similar" << std::endl; std::vector*> transformedChildren; transformedChildren.push_back(lhs); transformedChildren.push_back(rhs); - NodeTree* function = scopeLookup(scope, functionCallName, transformedChildren); - if (function == NULL) { + newNode = doFunction(scope, functionCallName, transformedChildren, templateTypeReplacements); + if (newNode == NULL) { std::cout << "scope lookup error! Could not find " << functionCallName << " in expression " << std::endl; - throw "LOOKUP ERROR: " + functionCallName; + throw "LOOKUP ERROR: " + functionCallName; } - newNode = new NodeTree(functionCallName, ASTData(function_call, Symbol(functionCallName, true))); - newNode->addChild(function); // First child of function call is a link to the function definition - newNode->addChild(lhs); - newNode->addChild(rhs); - if (name == "access_operation") - std::cout << "Access Operation: " << lhs->getDataRef()->symbol.getName() << " : " << rhs->getDataRef()->symbol.getName() << std::endl; - std::cout << functionCallName << " - " << function->getName() << " has value type " << function->getDataRef()->valueType << " and rhs " << rhs->getDataRef()->valueType << std::endl; - //Set the value of this function call - if (function->getDataRef()->valueType) - newNode->getDataRef()->valueType = function->getDataRef()->valueType; - else if (rhs->getDataRef()->valueType) - newNode->getDataRef()->valueType = rhs->getDataRef()->valueType; - else - newNode->getDataRef()->valueType = NULL; - std::cout << "function call to " << functionCallName << " - " << function->getName() << " is now " << newNode->getDataRef()->valueType << std::endl; + // //Set the value of this function call + if (newNode->getDataRef()->valueType == NULL && rhs->getDataRef()->valueType) { + std::cout << "The value type from doFunction was null! (for " << functionCallName << ")" << std::endl; + newNode->getDataRef()->valueType = rhs->getDataRef()->valueType; + } + //else + // newNode->getDataRef()->valueType = NULL; + std::cout << "function call to " << functionCallName << " - " << newNode->getName() << " is now " << newNode->getDataRef()->valueType << std::endl; return newNode; //skipChildren.insert(1); + } else if (children.size() == 2) { + //Is template instantiation + return findOrInstantiateFunctionTemplate(children, scope, types, templateTypeReplacements); } else { - return transform(children[0], scope, types); //Just a promoted child, so do it instead + return transform(children[0], scope, types, templateTypeReplacements); //Just a promoted child, so do it instead } } else if (name == "factor") { //Do factor here, as it has all the weird unary operators //If this is an actual part of an expression, not just a premoted child //NO SUPPORT FOR CASTING YET + std::string funcName; if (children.size() == 2) { - std::string funcName = concatSymbolTree(children[0]); + funcName = concatSymbolTree(children[0]); NodeTree* param; if (funcName == "*" || funcName == "&" || funcName == "++" || funcName == "--" || funcName == "-" || funcName == "!" || funcName == "~") - param = transform(children[1], scope, types); + param = transform(children[1], scope, types, templateTypeReplacements); else - funcName = concatSymbolTree(children[1]), param = transform(children[0], scope, types); + funcName = concatSymbolTree(children[1]), param = transform(children[0], scope, types, templateTypeReplacements); //std::cout << "scope lookup from factor" << std::endl; std::vector*> transformedChildren; transformedChildren.push_back(param); - NodeTree* function = scopeLookup(scope, funcName, transformedChildren); + 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; + throw "LOOKUP ERROR: " + funcName; } - newNode = new NodeTree(funcName, ASTData(function_call, Symbol(funcName, true))); - newNode->addChild(function); - newNode->addChild(param); - if (function->getDataRef()->valueType) - newNode->getDataRef()->valueType = function->getDataRef()->valueType; - else - newNode->getDataRef()->valueType = param->getDataRef()->valueType; - return newNode; + return function; } else { - return transform(children[0], scope, types); //Just a promoted child, so do it instead + return transform(children[0], scope, types, templateTypeReplacements); //Just a promoted child, so do it instead } } else if (name == "statement") { newNode = new NodeTree(name, ASTData(statement)); @@ -220,25 +546,21 @@ NodeTree* ASTTransformation::transform(NodeTree* from, NodeTree newNode = new NodeTree(name, ASTData(assignment_statement)); std::string assignFuncName = concatSymbolTree(children[1]); if (assignFuncName == "=") { - newNode->addChild(transform(children[0], scope, types)); - newNode->addChild(transform(children[2], scope, types)); + newNode->addChild(transform(children[0], scope, types, templateTypeReplacements)); + newNode->addChild(transform(children[2], scope, types, templateTypeReplacements)); } else { //For assignments like += or *=, expand the syntatic sugar. - NodeTree* lhs = transform(children[0], scope, types); - NodeTree* rhs = transform(children[2], scope, types); + NodeTree* lhs = transform(children[0], scope, types, templateTypeReplacements); + NodeTree* rhs = transform(children[2], scope, types, templateTypeReplacements); std::vector*> transformedChildren; transformedChildren.push_back(lhs); transformedChildren.push_back(rhs); std::string functionName = assignFuncName.substr(0,1); - NodeTree* childCall = new NodeTree(functionName, ASTData(function_call, Symbol(functionName, true))); - NodeTree* functionDef = scopeLookup(scope, functionName, transformedChildren); - if (functionDef == NULL) { + NodeTree* operatorCall = doFunction(scope, functionName, transformedChildren, templateTypeReplacements); + if (operatorCall == NULL) { std::cout << "scope lookup error! Could not find " << functionName << " in assignment_statement " << std::endl; - throw "LOOKUP ERROR: " + functionName; + throw "LOOKUP ERROR: " + functionName; } - childCall->addChild(functionDef); //First child of function call is definition of the function - childCall->addChild(lhs); - childCall->addChild(rhs); newNode->addChild(lhs); - newNode->addChild(childCall); + newNode->addChild(operatorCall); } return newNode; } else if (name == "declaration_statement") { @@ -247,25 +569,40 @@ NodeTree* ASTTransformation::transform(NodeTree* from, NodeTree // NodeTree* newIdentifier = transform(children[1], scope); //Transform the identifier // newIdentifier->getDataRef()->valueType = Type(concatSymbolTree(children[0]));//set the type of the identifier std::string newIdentifierStr = concatSymbolTree(children[1]); - std::string typeString = concatSymbolTree(children[0]);//Get the type (left child) and set our new identifer to be that type - Type* identifierType = typeFromString(typeString, scope); + Type* identifierType = typeFromTypeNode(children[0], scope, templateTypeReplacements); + std::cout << "Declaring an identifier " << newIdentifierStr << " to be of type " << identifierType->toString() << std::endl; NodeTree* newIdentifier = new NodeTree("identifier", ASTData(identifier, Symbol(newIdentifierStr, true), identifierType)); scope->getDataRef()->scope[newIdentifierStr].push_back(newIdentifier); newNode->getDataRef()->scope["~enclosing_scope"].push_back(scope); - //Now we don't do this thing - // if (identifierType->typeDefinition) { - // //Is a custom type. Populate this declaration's scope with it's inner declarations - // std::vector*> definitions = identifierType->typeDefinition->getChildren(); - // for (auto i : definitions) { - // //Point to the identifier. May need to change so it points to the declaration or something, with new declarations..... - // newIdentifier->getDataRef()->scope[i->get(0)->getDataRef()->symbol.getName()] = i->get(0); //make each declaration's name point to it's definition, like above - // } - // } - newNode->addChild(newIdentifier); + + if (children.size() > 2 && concatSymbolTree(children[2]) == ".") { + //A bit of a special case for declarations - if there's anything after just the normal 1 node declaration, it's either + //an expression that is assigned to the declaration (int a = 4;) or a member call (Object a.constructAThing()) + //This code is a simplified version of the code in function_call with respect to access_operation. + //Note that in this case, what is lhs there is our newIdentifier here (the declaration of the left side of the access operation) + auto sliced = slice(children, 4, -1); + std::vector*> initPositionFuncParams = transformChildren(sliced, std::set(), scope, types, templateTypeReplacements); + NodeTree* rhs = transform(children[3], identifierType->typeDefinition, mapNodesToTypes(initPositionFuncParams), templateTypeReplacements); //If an access operation, then the right side will be in the lhs's type's scope + std::vector*> transformedChildren; transformedChildren.push_back(newIdentifier); transformedChildren.push_back(rhs); + NodeTree* accessFuncCall = doFunction(scope, ".", transformedChildren, templateTypeReplacements); + accessFuncCall->getDataRef()->valueType = rhs->getDataRef()->valueType; + //Now we borrow a bit of code from function_call below to actually use our new accessFuncCall to setup a "initPosition" function call + //that will follow the identifier in this declaration node + std::string initPosFuncName = newIdentifierStr + "." + concatSymbolTree(children[3]); + NodeTree* initPositionFuncCall = new NodeTree(initPosFuncName, ASTData(function_call, Symbol(initPosFuncName, true))); + initPositionFuncCall->addChild(accessFuncCall); + initPositionFuncCall->getDataRef()->valueType = accessFuncCall->getDataRef()->valueType; + initPositionFuncCall->addChildren(initPositionFuncParams); + newNode->addChild(initPositionFuncCall); + return newNode; + } + skipChildren.insert(0); //These, the type and the identifier, have been taken care of. skipChildren.insert(1); - } else if (name == "if_comp") { + newNode->addChildren(transformChildren(children, skipChildren, scope, types, templateTypeReplacements)); + return newNode; + } else if (name == "if_comp") { newNode = new NodeTree(name, ASTData(if_comp)); newNode->addChild(new NodeTree("identifier", ASTData(identifier, Symbol(concatSymbolTree(children[0]),true)))); skipChildren.insert(0); //Don't do the identifier. The identifier lookup will fail. That's why we do it here. @@ -274,17 +611,14 @@ NodeTree* ASTTransformation::transform(NodeTree* from, NodeTree } else if (name == "function_call") { std::string functionCallName = concatSymbolTree(children[0]); newNode = new NodeTree(functionCallName, ASTData(function_call, Symbol(functionCallName, true))); - // if (function == NULL) { - // std::cout << "scope lookup error! Could not find " << functionCallName << " in function_call " << std::endl; - // throw "LOOKUP ERROR: " + functionCallName; - // } + skipChildren.insert(0); - std::vector*> transformedChildren = transformChildren(children, skipChildren, scope, types); + std::vector*> transformedChildren = transformChildren(children, skipChildren, scope, types, templateTypeReplacements); std::cout << "scope lookup from function_call: " << functionCallName << std::endl; for (auto i : children) std::cout << i << " : " << i->getName() << " : " << i->getDataRef()->getName() << std::endl; - NodeTree* function = transform(children[0], scope, mapNodesToTypes(transformedChildren)); + NodeTree* function = transform(children[0], scope, mapNodesToTypes(transformedChildren), templateTypeReplacements); std::cout << "The thing: " << function << " : " << function->getName() << std::endl; for (auto i : function->getChildren()) std::cout << i->getName() << " "; @@ -294,46 +628,56 @@ NodeTree* ASTTransformation::transform(NodeTree* from, NodeTree newNode->addChildren(transformedChildren); return newNode; } else if (name == "parameter") { - return transform(children[0], scope, types); //Don't need a parameter node, just the value + return transform(children[0], scope, types, templateTypeReplacements); //Don't need a parameter node, just the value } else if (name == "type") { std::string theConcat = concatSymbolTree(from); //We have no symbol, so this will concat our children - newNode = new NodeTree(name, ASTData(value, Symbol(theConcat, true), typeFromString(theConcat, scope))); + newNode = new NodeTree(name, ASTData(value, Symbol(theConcat, true), typeFromTypeNode(from, scope, templateTypeReplacements))); } else if (name == "number") { - return transform(children[0], scope, types); + return transform(children[0], scope, types, templateTypeReplacements); } 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 == "char") { + } 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") { newNode = new NodeTree(name, ASTData(value, Symbol(concatSymbolTree(children[0]), true), new Type(character, 1))); //Indirection of 1 for array - } else { + } else if (name == "character") { + newNode = new NodeTree(name, ASTData(value, Symbol(concatSymbolTree(children[0]), true), new Type(character, 0))); //Indirection of 0 for character + } else if (name == "bool") { + newNode = new NodeTree(name, ASTData(value, Symbol(concatSymbolTree(children[0]), true), new Type(boolean, 0))); //Indirection of 0 for character + } else if (name == "AmbiguityPackOuter" || name == "AmbiguityPackInner") { + std::cout << "///////////////////////////////////////////////////////////////////////////////" << std::endl; + std::cout << "Ambigious program when parsed by this grammer! This is a bug, please report it." << std::endl; + std::cout << "///////////////////////////////////////////////////////////////////////////////" << std::endl; + throw "Ambigious parse!"; + } else { + // Should get rid of this eventually. Right now it handles cases like sign, alpha, a comma, etc + std::cout << "Unhandled syntax node: " << name << std::endl; return new NodeTree(); } //Do all children but the ones we skip - for (int i = 0; i < children.size(); i++) { - if (skipChildren.find(i) == skipChildren.end()) { - NodeTree* transChild = transform(children[i], scope, types); - if (transChild->getDataRef()->type) //Only add the children that have a real ASTData::ASTType, that is, legit ASTData. - newNode->addChild(transChild); - else - delete transChild; - } - } + newNode->addChildren(transformChildren(children, skipChildren, scope, types, templateTypeReplacements)); return newNode; } //We use this functionality a lot at different places -std::vector*> ASTTransformation::transformChildren(std::vector*> children, std::set skipChildren, NodeTree* scope, std::vector types) { +std::vector*> ASTTransformation::transformChildren(std::vector*> children, std::set skipChildren, NodeTree* scope, std::vector types, std::map templateTypeReplacements) { std::vector*> transformedChildren; // In general, iterate through children and do them. Might not do this for all children. for (int i = 0; i < children.size(); i++) { if (skipChildren.find(i) == skipChildren.end()) { - NodeTree* transChild = transform(children[i], scope, types); + NodeTree* transChild = transform(children[i], scope, types, templateTypeReplacements); if (transChild->getDataRef()->type) //Only add the children that have a real ASTData::ASTType, that is, legit ASTData. transformedChildren.push_back(transChild); else @@ -343,13 +687,17 @@ std::vector*> ASTTransformation::transformChildren(std::vector return transformedChildren; } +//Extract types from already transformed nodes std::vector ASTTransformation::mapNodesToTypes(std::vector*> nodes) { std::vector types; - for (auto i : nodes) + for (auto i : nodes) { + std::cout << i->getDataRef()->toString() << std::endl; types.push_back(*(i->getDataRef()->valueType)); + } return types; } +//Simple way to extract strings from syntax trees. Used often for identifiers, strings, types std::string ASTTransformation::concatSymbolTree(NodeTree* root) { std::string concatString; std::string ourValue = root->getDataRef()->getValue(); @@ -357,16 +705,16 @@ std::string ASTTransformation::concatSymbolTree(NodeTree* root) { concatString += ourValue; std::vector*> children = root->getChildren(); for (int i = 0; i < children.size(); i++) { - concatString += concatSymbolTree(children[i]); + concatString += concatSymbolTree(children[i]); } return concatString; } -//Overloaded with the actual children to allow us to handle operator methods -NodeTree* ASTTransformation::scopeLookup(NodeTree* scope, std::string lookup, std::vector*> nodes) { - // - auto LLElementIterator = languageLevelScope.find(lookup); - if (LLElementIterator != languageLevelScope.end()) { +//We pass in the actual children (parameters) to allow us to handle overloaded operator methods (where a parameter is actually the scope of the method) +NodeTree* ASTTransformation::doFunction(NodeTree* scope, std::string lookup, std::vector*> nodes, std::map templateTypeReplacements) { + auto LLElementIterator = languageLevelOperators.find(lookup); + NodeTree* newNode; + if (LLElementIterator != languageLevelOperators.end()) { std::cout << "Checking for early method level operator overload" << std::endl; std::string lookupOp = "operator" + lookup; for (auto i : nodes) @@ -374,51 +722,81 @@ NodeTree* ASTTransformation::scopeLookup(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 + //Ok, so we construct std::cout << "Early method level operator was found" << std::endl; //return operatorMethod; - newNode = new NodeTree(functionCallName, ASTData(function_call, Symbol(functionCallName, true))); - newNode->addChild(function); // First child of function call is a link to the function definition - newNode->addChild(lhs); - newNode->addChild(rhs); + NodeTree* newNode = new NodeTree(lookupOp, ASTData(function_call, Symbol(lookupOp, true))); + NodeTree* dotFunctionCall = new NodeTree(".", ASTData(function_call, Symbol(".", true))); + dotFunctionCall->addChild(languageLevelOperators["."][0]); //function definition + dotFunctionCall->addChild(nodes[0]); // The object whose method we're calling + dotFunctionCall->addChild(operatorMethod); //The method we're calling + newNode->addChild(dotFunctionCall); // First child of function call is a link to the function definition + newNode->addChildren(slice(nodes, 1, -1)); //The rest of the parameters to the operator //Set the value of this function call - if (function->getDataRef()->valueType) - newNode->getDataRef()->valueType = function->getDataRef()->valueType; - else if (rhs->getDataRef()->valueType) - newNode->getDataRef()->valueType = rhs->getDataRef()->valueType; - else - newNode->getDataRef()->valueType = NULL; + newNode->getDataRef()->valueType = operatorMethod->getDataRef()->valueType; + return newNode; } std::cout << "Early method level operator was NOT found" << std::endl; } - return scopeLookup(scope, lookup, mapNodesToTypes(nodes)); + + newNode = new NodeTree(lookup, ASTData(function_call, Symbol(lookup, true))); + NodeTree* function = functionLookup(scope, lookup, mapNodesToTypes(nodes)); + newNode->addChild(function); + newNode->addChildren(nodes); + + //Specially handle dereference and address of to assign the correct type + //We need some significant other type corrections here, maybe to the point of being their own function. (int + float, etc.) + for (auto i : nodes) + std::cout << i->getDataRef()->toString() << " "; + std::cout< oldTypes = mapNodesToTypes(nodes); + if ((nodes.size() != 2 && lookup == "*") || lookup == "&" || lookup == "[]") { + Type* newType = oldTypes[0].clone(); + if (lookup == "*" || lookup == "[]") + newType->decreaseIndirection(); + else + newType->increaseIndirection(); + + newNode->getDataRef()->valueType = newType, std::cout << "Operator " + lookup << " is altering indirection from " << oldTypes[0].toString() << " to " << newType->toString() << std::endl; + } else { + newNode->getDataRef()->valueType = function->getDataRef()->valueType, std::cout << "Some other ||" << lookup << "||" << std::endl; + } + return newNode; } -NodeTree* ASTTransformation::scopeLookup(NodeTree* scope, std::string lookup, std::vector types) { - //We first search the languageLevelScope to see if it's an operator. If so, we modifiy the lookup with a preceding "operator" - auto LLElementIterator = languageLevelScope.find(lookup); - if (LLElementIterator != languageLevelScope.end()) +//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()) { + std::cout << "found it at language level as reserved word." << std::endl; + return LLElementIterator->second[0]; + } + //We search the languageLevelOperators to see if it's an operator. If so, we modifiy the lookup with a preceding "operator" + 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; - //return *i; - std::vector*> children = (*i)->getChildren(); - if (types.size() != ((children.size() > 0) ? children.size()-1 : 0)) { - std::cout << "Type sizes do not match between two " << lookup << "(" << types.size() << "," << ((children.size() > 0) ? children.size()-1 : 0) << "), types are: "; + + //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(); + //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: "; for (auto j : types) std::cout << j.toString() << " "; std::cout << std::endl; @@ -426,41 +804,240 @@ NodeTree* ASTTransformation::scopeLookup(NodeTree* scope, std: } bool typesMatch = true; for (int j = 0; j < types.size(); j++) { - if (types[j] != *(children[j]->getDataRef()->valueType)) { + Type* tmpType = children[j]->getDataRef()->valueType; + //Don't worry if types don't match if it's a template type + // std::cout << "Checking for segfaults, we have" << std::endl; + // std::cout << types[j].toString() << std::endl; + // std::cout << tmpType->toString() << std::endl; + // std::cout << "Done!" << std::endl; + if (types[j] != *tmpType && tmpType->baseType != template_type_type) { typesMatch = false; - std::cout << "Types do not match between two " << lookup << std::endl; + std::cout << "Types do not match between two " << lookup << " " << types[j].toString(); + std::cout << " vs " << children[j]->getDataRef()->valueType->toString() << std::endl; break; } } 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 != languageLevelScope.end()) { + if (LLElementIterator != languageLevelOperators.end()) { std::cout << "found it at language level as operator." << std::endl; return LLElementIterator->second[0]; } std::cout << "Did not find, returning NULL" << std::endl; - return NULL; + return NULL; } -Type* ASTTransformation::typeFromString(std::string typeIn, NodeTree* scope) { +//Lookup class templates. It evaluates possible matches on traits +NodeTree* ASTTransformation::templateClassLookup(NodeTree* scope, std::string lookup, std::vector templateInstantiationTypes) { + std::vector*> mostFittingTemplates; + int bestNumTraitsSatisfied = -1; + auto possibleMatches = scopeLookup(scope, lookup); + std::cout << "Template Class instantiation has " << possibleMatches.size() << " possible matches." << std::endl; + for (auto i : possibleMatches) { + NodeTree* templateSyntaxTree = i->getDataRef()->valueType->templateDefinition; + + auto nameTraitsPairs = makeTemplateNameTraitPairs(templateSyntaxTree->getChildren()[0]); + //Check if sizes match between the placeholder and actual template types + if (nameTraitsPairs.size() != templateInstantiationTypes.size()) + continue; + + bool traitsEqual = true; + int typeIndex = 0; + int currentTraitsSatisfied = 0; + for (auto j : nameTraitsPairs) { + if (!subset(j.second, templateInstantiationTypes[typeIndex]->traits)) { + traitsEqual = false; + std::cout << "Traits not subset for " << j.first << " and " << templateInstantiationTypes[typeIndex]->toString() << ": "; + //std::cout << baseType << " " << indirection << " " << typeDefinition << " " << templateDefinition << " " << traits << ; + 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; + } else { + std::cout << "Traits ARE subset for " << j.first << " and " << templateInstantiationTypes[typeIndex]->toString() << ": "; + //std::cout << baseType << " " << indirection << " " << typeDefinition << " " << templateDefinition << " " << traits << ; + 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; + } + currentTraitsSatisfied += j.second.size(); + typeIndex++; + } + if (!traitsEqual) + continue; + + //See if this is a better match than the current best + if (currentTraitsSatisfied > bestNumTraitsSatisfied) { + mostFittingTemplates.clear(); + std::cout << "Class satisfying " << currentTraitsSatisfied << " beats previous " << bestNumTraitsSatisfied << std::endl; + bestNumTraitsSatisfied = currentTraitsSatisfied; + } else if (currentTraitsSatisfied < bestNumTraitsSatisfied) + continue; + mostFittingTemplates.push_back(i); + std::cout << "Current class fits, satisfying " << currentTraitsSatisfied << " traits" << std::endl; + } + if (!mostFittingTemplates.size()) { + std::cout << "No template classes fit for " << lookup << "!" << std::endl; + throw "No matching template classes"; + } else if (mostFittingTemplates.size() > 1) { + std::cout << "Multiple template classes fit with equal number of traits satisfied for " << lookup << "!" << std::endl; + throw "Multiple matching template classes"; + } + return mostFittingTemplates[0]; +} + +//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; + int index = 1; + for (auto i : possibleMatches) { + std::cout << "Possibility " << index++ << std::endl; + NodeTree* templateSyntaxTree = i->getDataRef()->valueType->templateDefinition; + if (!templateSyntaxTree) { + std::cout << "Not a template, skipping" << std::endl; + continue; + } + + auto nameTraitsPairs = makeTemplateNameTraitPairs(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 (!subset(j.second, templateInstantiationTypes[typeIndex]->traits)) { + traitsEqual = false; + std::cout << "Traits not a subset 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; + } else { + std::cout << "Traits ARE a subset 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; + } + //As we go, build up the typeMap for when we transform the parameters for parameter checking + typeMap[j.first] = templateInstantiationTypes[typeIndex]; + currentTraitsSatisfied += j.second.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); + std::cout << "Template param type: " << paramType->toString() << " : Needed Type: " << types[j].toString() << std::endl; + if (*paramType != types[j]) { + parameterTypesMatch = false; + std::cout << "Not equal template param: " << paramType->toString() << " : Needed Type actual param: " << 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::makeTemplateNameTraitPairs(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 = makeTemplateNameTraitPairs(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, bool includeModules) { + //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()) { + std::cout << "found it at language level as reserved word." << std::endl; + return LLElementIterator->second; + } + std::vector*> matches; + std::map*>> scopeMap = scope->getDataRef()->scope; + auto possibleMatches = scopeMap.find(lookup); + if (possibleMatches != scopeMap.end()) { + for (auto i : possibleMatches->second) + if (includeModules || i->getName() != "translation_unit") + 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 + 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 +Type* ASTTransformation::typeFromTypeNode(NodeTree* typeNode, NodeTree* scope, std::map templateTypeReplacements) { + std::string typeIn = concatSymbolTree(typeNode); + int indirection = 0; ValueType baseType; NodeTree* typeDefinition = NULL; + std::set traits; while (typeIn[typeIn.size() - indirection - 1] == '*') indirection++; std::string edited = strSlice(typeIn, 0, -(indirection + 1)); if (edited == "void") @@ -470,15 +1047,190 @@ Type* ASTTransformation::typeFromString(std::string typeIn, NodeTree* s else if (edited == "int") baseType = integer; else if (edited == "float") - baseType = floating -; else if (edited == "double") + baseType = floating; + else if (edited == "double") baseType = double_percision; else if (edited == "char") baseType = character; else { baseType = none; - typeDefinition = scopeLookup(scope, edited); - //std::cout << "scopeLookup of type " << edited << " returned " << typeDefinition << std::endl; + + auto possibleMatches = scopeLookup(scope, edited); + if (possibleMatches.size()) { + typeDefinition = possibleMatches[0]; + traits = typeDefinition->getDataRef()->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()) { + std::cout << "Template type! (" << edited << ")" << std::endl; + Type* templateTypeReplacement = templateTypeReplacements[edited]->clone(); + templateTypeReplacement->modifyIndirection(indirection); + return templateTypeReplacement; + } + 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; + + // getChildren()[1] is \* because of pointer instead of template_inst + // To counter this, for every indirection we step down a level + for (int i = 0; i < indirection; i++) + typeNode = typeNode->getChildren()[0]; + + std::cout << possibleMatches.size() << " " << typeNode->getChildren().size() << std::endl; + if (typeNode->getChildren().size() > 1) + std::cout << typeNode->getChildren()[1]->getDataRef()->getName() << 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; + + //We pull out the replacement types first so that we can choose the correct possibly overloaded template + std::vector*> templateParamInstantiationNodes = slice(typeNode->getChildren()[1]->getChildren(), 1, -2, 2); //same + std::vector templateParamInstantiationTypes; + std::string instTypeString = ""; + for (int i = 0; i < templateParamInstantiationNodes.size(); i++) { + Type* instType = typeFromTypeNode(templateParamInstantiationNodes[i], scope, templateTypeReplacements); + templateParamInstantiationTypes.push_back(instType); + instTypeString += (instTypeString == "") ? instType->toString(false) : "," + instType->toString(false); + } + + //Finish creating the new name for this instantiation + std::string classNameWithoutTemplate = concatSymbolTree(typeNode->getChildren()[0]); + std::string fullyInstantiatedName = classNameWithoutTemplate + "<" + instTypeString + ">"; + + // Recheck for prior definition here, now that we have the true name. + possibleMatches = scopeLookup(scope, fullyInstantiatedName); + if (possibleMatches.size()) { + typeDefinition = possibleMatches[0]; + traits = typeDefinition->getDataRef()->valueType->traits; + std::cout << "Found already instantiated template of " << fullyInstantiatedName << " at second check" << std::endl; + } else { + std::cout << "Did not find already instantiated template of " << fullyInstantiatedName << " at second check" << std::endl; + //Look up this template's plain definition. It's type has the syntax tree that we need to parse + NodeTree* templateDefinition = templateClassLookup(scope, concatSymbolTree(typeNode->getChildren()[0]), templateParamInstantiationTypes); + if (templateDefinition == NULL) + std::cout << "Template definition is null!" << std::endl; + else + std::cout << "Template definition is not null!" << std::endl; + + NodeTree* templateSyntaxTree = templateDefinition->getDataRef()->valueType->templateDefinition; + //Create a new map of template type names to actual types. + std::vector*> templateParamPlaceholderNodes = slice(templateSyntaxTree->getChildren()[0]->getChildren(), 1, -2, 2); //Don't get beginning or end for < or >, skip commas in the middle + std::map newTemplateTypeReplacement; + for (int i = 0; i < templateParamInstantiationTypes.size(); i++) + newTemplateTypeReplacement[concatSymbolTree(templateParamPlaceholderNodes[i])] = templateParamInstantiationTypes[i]; + + typeDefinition = new NodeTree("type_def", ASTData(type_def, Symbol(fullyInstantiatedName, true, fullyInstantiatedName))); + traits = templateDefinition->getDataRef()->valueType->traits; // We have the same traits as the template definition + Type* selfType = new Type(typeDefinition, traits); // Type is self-referential since this is the definition. + typeDefinition->getDataRef()->valueType = selfType; + + //Note that we're adding to the current top scope. This makes it more efficient by preventing multiple instantiation and should not cause any problems + //It also makes sure it gets generated in the right place + std::cout << "Adding to top scope and template's origional scope with fullyInstantiatedName " << fullyInstantiatedName << std::endl; + topScope->getDataRef()->scope[fullyInstantiatedName].push_back(typeDefinition); + topScope->addChild(typeDefinition); //Add this object the the highest scope's + //NodeTree* templateHighScope = templateDefinition->getDataRef()->scope["~enclosing_scope"][0]; + //if (topScope != templateHighScope) + //templateHighScope->getDataRef()->scope[fullyInstantiatedName].push_back(typeDefinition); + // We put it in the scope of the template so that it can find itself (as it's scope is its template definition) + templateDefinition->getDataRef()->scope[fullyInstantiatedName].push_back(typeDefinition); + //Note that the instantiated template's scope is the template's definition. + typeDefinition->getDataRef()->scope["~enclosing_scope"].push_back(templateDefinition); + + // We only partially instantiate templates no matter what now + // They are all fully instantiated in the loop at the end of the 4th pass + // This is done for code simplicity and so that that loop can do template class methods + // that instantiate other templates that instantiate other templates while still retaining the + // deferred method allowing us to correctly instantiate multiple levels of mututally recursive definitions. + selfType->templateDefinition = templateSyntaxTree; //We're going to still need this when we finish instantiating + selfType->templateTypeReplacement = newTemplateTypeReplacement; //Save the types for use when this is fully instantiated in pass 4 + secondPassDoClassInsides(typeDefinition, templateSyntaxTree->getChildren(), newTemplateTypeReplacement); //Use these types when instantiating data members + } + } 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, traits).toString() << std::endl; + } } - return new Type(baseType, typeDefinition, indirection); + Type* toReturn = new Type(baseType, typeDefinition, indirection, traits); + std::cout << "Returning type " << toReturn->toString() << std::endl; + return toReturn; } + +NodeTree* ASTTransformation::findOrInstantiateFunctionTemplate(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]); + + auto unsliced = children[1]->getChildren(); + std::vector*> templateParamInstantiationNodes = slice(unsliced, 1 , -2, 2);//skip <, >, and commas + std::string instTypeString = ""; + std::vector templateActualTypes; + for (int i = 0; i < templateParamInstantiationNodes.size(); i++) { + Type* instType = typeFromTypeNode(templateParamInstantiationNodes[i],scope, templateTypeReplacements); + instTypeString += (instTypeString == "" ? instType->toString() : "," + instType->toString()); + templateActualTypes.push_back(instType); + } + std::cout << "Size: " << templateParamInstantiationNodes.size() << std::endl; + std::string fullyInstantiatedName = functionName + "<" + instTypeString + ">"; + std::cout << "Looking for " << fullyInstantiatedName << std::endl; + + std::cout << "Types are : "; + for (auto i : types) + std::cout << " " << i.toString(); + std::cout << std::endl; + + NodeTree* instantiatedFunction = functionLookup(scope, fullyInstantiatedName, types); + //If it already exists, return it + if (instantiatedFunction) { + std::cout << fullyInstantiatedName << " already exists! Returning" << std::endl; + return instantiatedFunction; + } else { + instantiatedFunction = functionLookup(topScope, fullyInstantiatedName, types); + if (instantiatedFunction) { + std::cout << fullyInstantiatedName << "already exists! Found in TopScope" << std::endl; + return instantiatedFunction; + } + std::cout << fullyInstantiatedName << " does NOT exist" << std::endl; + } + + //Otherwise, we're going to instantiate it + //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; + // 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++) + std::cout << ", " << i << " : " << templateChildren[i]->getDataRef()->getName(); + std::cout << std::endl; + + instantiatedFunction = new NodeTree("function", ASTData(function, Symbol(fullyInstantiatedName, true), typeFromTypeNode(templateChildren[1], scope, newTemplateTypeReplacement))); + std::set skipChildren; + skipChildren.insert(0); + skipChildren.insert(1); + skipChildren.insert(2); + //scope->getDataRef()->scope[fullyInstantiatedName].push_back(instantiatedFunction); + instantiatedFunction->getDataRef()->scope["~enclosing_scope"].push_back(templateDefinition->getDataRef()->scope["~enclosing_scope"][0]); //Instantiated Template Function's scope is it's template's definition's scope + topScope->getDataRef()->scope[fullyInstantiatedName].push_back(instantiatedFunction); + topScope->addChild(instantiatedFunction); //Add this object the the highest scope's + + std::cout << "About to do children of " << functionName << " to " << fullyInstantiatedName << std::endl; + instantiatedFunction->addChildren(transformChildren(templateSyntaxTree->getChildren(), skipChildren, instantiatedFunction, std::vector(), newTemplateTypeReplacement)); + + + std::cout << "Fully Instantiated function " << functionName << " to " << fullyInstantiatedName << std::endl; + + return instantiatedFunction; +} + diff --git a/src/CGenerator.cpp b/src/CGenerator.cpp index c6c7723..6234d7a 100644 --- a/src/CGenerator.cpp +++ b/src/CGenerator.cpp @@ -15,7 +15,8 @@ void CGenerator::generateCompSet(std::map*> ASTs, std::ofstream outputCFile; outputCFile.open(i->first + ".c"); if (outputCFile.is_open()) { - outputCFile << generate(i->second); + // Prequel common to all files + outputCFile << "#include \n#include \n#include \n" << generate(i->second); } else { std::cout << "Cannot open file " << i->first << ".c" << std::endl; } @@ -35,59 +36,163 @@ std::string CGenerator::tabs() { return returnTabs; } +std::string CGenerator::generateClassStruct(NodeTree* from) { + auto data = from->getData(); + auto children = from->getChildren(); + std::string objectString = "struct __struct_dummy_" + CifyName(data.symbol.getName()) + "__ {\n"; + tabLevel++; + for (int i = 0; i < children.size(); i++) { + std::cout << children[i]->getName() << std::endl; + if (children[i]->getName() != "function") + objectString += tabs() + generate(children[i], nullptr) + "\n"; + } + tabLevel--; + objectString += "};"; + return objectString; +} + +// This method recurseivly generates all aliases of some definition +std::string CGenerator::generateAliasChains(NodeTree* scopeNode, NodeTree* definition) { + auto scope = scopeNode->getDataRef()->scope; + std::string output; + for (auto i = scope.begin(); i != scope.end(); i++) { + for (auto declaration : i->second) { + auto declarationData = declaration->getDataRef(); + if (declarationData->type == type_def + && declarationData->valueType->typeDefinition != declaration + && declarationData->valueType->typeDefinition == definition) { + output += "typedef " + CifyName(definition->getDataRef()->symbol.getName()) + " " + CifyName(declarationData->symbol.getName()) + ";\n"; + // Recursively add the ones that depend on this one + output += generateAliasChains(scopeNode, declaration); + } + } + } + return output; +} + //The enclosing object is for when we're generating the inside of object methods. They allow us to check scope lookups against the object we're in std::string CGenerator::generate(NodeTree* from, NodeTree* enclosingObject) { ASTData data = from->getData(); std::vector*> children = from->getChildren(); - std::string output = ""; + std::string output; switch (data.type) { case translation_unit: - //Do here because we may need the typedefs before the declarations of variables - for (int i = 0; i < children.size(); i++) - if (children[i]->getDataRef()->type == type_def) - output += generate(children[i], enclosingObject) + "\n"; + { + // Ok, so we've got to do this in passes to preserve mututally recursive definitions. + // + // First Pass: All classes get "struct dummy_thing; typedef struct dummy_thing thing;". + // Also, other typedefs follow after their naming. + // Second Pass: All top level variable declarations + // Third Pass: Define all actual structs of a class, in correct order (done with posets) + // Fourth Pass: Declare all function prototypes (as functions may be mutually recursive too). + // (this includes object methods) + // Fifth Pass: Define all functions (including object methods). + + // However, most of these do not actually have to be done as separate passes. First, second, fourth, and fifth + // are done simultanously, but append to different strings that are then concatinated properly, in order. + + std::string plainTypedefs = "/**\n * Plain Typedefs\n */\n\n"; + std::string variableDeclarations = "/**\n * Variable Declarations \n */\n\n"; + std::string classStructs = "/**\n * Class Structs\n */\n\n"; + std::string functionPrototypes = "/**\n * Function Prototypes\n */\n\n"; + std::string functionDefinitions = "/**\n * Function Definitions\n */\n\n"; + + Poset*> typedefPoset; + for (int i = 0; i < children.size(); i++) { + if (children[i]->getDataRef()->type == type_def) { + // If we're an alias type, continue. We handle those differently + if (children[i]->getDataRef()->valueType->typeDefinition != children[i]) + continue; + + typedefPoset.addVertex(children[i]); // We add this definition by itself just in case there are no dependencies. + // If it has dependencies, there's no harm in adding it here + // Go through every child in the class looking for declaration statements. For each of these that is not a primitive type + // we will add a dependency from this definition to that definition in the poset. + std::vector*> classChildren = children[i]->getChildren(); + for (auto j : classChildren) { + if (j->getDataRef()->type == declaration_statement) { + Type* decType = j->getChildren()[0]->getDataRef()->valueType; // Type of the declaration + if (decType->typeDefinition && decType->getIndirection() == 0) // If this is a custom type and not a pointer + typedefPoset.addRelationship(children[i], decType->typeDefinition); // Add a dependency + } + } + } + } + //Now generate the typedef's in the correct, topological order + for (NodeTree* i : typedefPoset.getTopoSort()) + classStructs += generateClassStruct(i) + "\n"; + //Declare everything in translation unit scope here. (allows stuff from other files, automatic forward declarations) for (auto i = data.scope.begin(); i != data.scope.end(); i++) { - for (auto overloadedMembers : i->second) { - NodeTree* declaration = overloadedMembers; + for (auto declaration : i->second) { std::vector*> decChildren = declaration->getChildren(); ASTData declarationData = declaration->getData(); switch(declarationData.type) { case identifier: - output += ValueTypeToCType(declarationData.valueType) + " " + declarationData.symbol.getName() + "; /*identifier*/\n"; + variableDeclarations += ValueTypeToCType(declarationData.valueType) + " " + declarationData.symbol.getName() + "; /*identifier*/\n"; break; case function: { - if (decChildren.size() == 0) { //Not a real function, must be a built in passthrough { - output += "/* built in function: " + declarationData.toString() + " */\n"; - break; + if (declarationData.valueType->baseType == template_type) + functionPrototypes += "/* template function " + declarationData.symbol.toString() + " */\n"; + else if (decChildren.size() == 0) //Not a real function, must be a built in passthrough + functionPrototypes += "/* built in function: " + declarationData.symbol.toString() + " */\n"; + else { + functionPrototypes += "\n" + ValueTypeToCType(declarationData.valueType) + " "; + std::string nameDecoration, parameters; + for (int j = 0; j < decChildren.size()-1; j++) { + if (j > 0) + parameters += ", "; + parameters += ValueTypeToCType(decChildren[j]->getData().valueType) + " " + generate(decChildren[j], enclosingObject); + nameDecoration += "_" + ValueTypeToCTypeDecoration(decChildren[j]->getData().valueType); + } + functionPrototypes += CifyName(declarationData.symbol.getName() + nameDecoration) + "(" + parameters + "); /*func*/\n"; + // Only generate function if this is the unit it was defined in + std::cout << "Generating " << CifyName(declarationData.symbol.getName()) << std::endl; + if (contains(children, declaration)) + functionDefinitions += generate(declaration, enclosingObject); } - output += "\n" + ValueTypeToCType(declarationData.valueType) + " "; - std::string nameDecoration, parameters; - for (int j = 0; j < decChildren.size()-1; j++) { - if (j > 0) - parameters += ", "; - parameters += ValueTypeToCType(decChildren[j]->getData().valueType) + " " + generate(decChildren[j], enclosingObject); - nameDecoration += "_" + ValueTypeToCTypeDecoration(decChildren[j]->getData().valueType); - } - output += CifyFunctionName(declarationData.symbol.getName()) + nameDecoration + "(" + parameters + "); /*func*/\n"; - break; } - case type_def: - //type - output += "/*typedef " + declarationData.symbol.getName() + " */\n"; break; + case type_def: + //type + plainTypedefs += "/*typedef " + declarationData.symbol.getName() + " */\n"; + + if (declarationData.valueType->baseType == template_type) { + plainTypedefs += "/* non instantiated template " + declarationData.symbol.getName() + " */"; + } else if (declarationData.valueType->typeDefinition != declaration) { + if (declarationData.valueType->typeDefinition) + continue; // Aliases of objects are done with the thing it alises + // Otherwise, we're actually a renaming of a primitive, can generate here + plainTypedefs += "typedef " + ValueTypeToCType(declarationData.valueType) + " " + CifyName(declarationData.symbol.getName()) + ";\n"; + plainTypedefs += generateAliasChains(from, declaration); + } else { + plainTypedefs += "typedef struct __struct_dummy_" + CifyName(declarationData.symbol.getName()) + "__ " + CifyName(declarationData.symbol.getName()) + ";\n"; + functionPrototypes += "/* Method Prototypes for " + declarationData.symbol.getName() + " */\n"; + // We use a seperate string for this because we only include it if this is the file we're defined in + std::string objectFunctionDefinitions = "/* Method Definitions for " + declarationData.symbol.getName() + " */\n"; + for (int j = 0; j < decChildren.size(); j++) { + std::cout << decChildren[j]->getName() << std::endl; + if (decChildren[j]->getName() == "function") //If object method + objectFunctionDefinitions += generateObjectMethod(declaration, decChildren[j], &functionPrototypes) + "\n"; + } + // Add all aliases to the plain typedefs. This will add any alias that aliases to this object, and any alias that aliases to that, and so on + plainTypedefs += generateAliasChains(from, declaration); + functionPrototypes += "/* Done with " + declarationData.symbol.getName() + " */\n"; + // If this is the file the object is defined in, include methods + if (contains(children, declaration)) + functionDefinitions += objectFunctionDefinitions + "/* Done with " + declarationData.symbol.getName() + " */\n"; + } + break; default: //std::cout << "Declaration? named " << declaration->getName() << " of unknown type " << ASTData::ASTTypeToString(declarationData.type) << " in translation unit scope" << std::endl; output += "/*unknown declaration named " + declaration->getName() + "*/\n"; } } } - //Do here because we need the newlines - for (int i = 0; i < children.size(); i++) - if (children[i]->getDataRef()->type != type_def) - output += generate(children[i], enclosingObject) + "\n"; + output += plainTypedefs + variableDeclarations + classStructs + functionPrototypes + functionDefinitions; return output; + } break; case interpreter_directive: //Do nothing @@ -97,33 +202,22 @@ std::string CGenerator::generate(NodeTree* from, NodeTree* enc //return "#include <" + data.symbol.getName() + ">\n"; case identifier: { - //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 self reference. + //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 "this"; + else + std::cout << "Error: this used in non-object scope" << std::endl; + //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; if (enclosingObject && enclosingObject->getDataRef()->scope.find(data.symbol.getName()) != enclosingObject->getDataRef()->scope.end()) - preName += "self->"; - if (false) - for (int j = 0; j < children.size()-1; j++) - preName += ValueTypeToCType(children[j]->getData().valueType) + "_"; - return preName + CifyFunctionName(data.symbol.getName()); //Cifying does nothing if not an operator overload + preName += "this->"; + return preName + CifyName(data.symbol.getName()); //Cifying does nothing if not an operator overload } - case type_def: - if (children.size() == 0) { - return "typedef " + ValueTypeToCType(data.valueType) + " " + data.symbol.getName() + ";"; - } else { - std::string objectString = "typedef struct __struct_dummy_" + data.symbol.getName() + "__ {\n"; - std::string postString; //The functions have to be outside the struct definition - for (int i = 0; i < children.size(); i++) { - std::cout << children[i]->getName() << std::endl; - if (children[i]->getName() == "function") //If object method - postString += generateObjectMethod(from, children[i]) + "\n"; - else - objectString += generate(children[i], enclosingObject) + "\n"; - } - objectString += "} " + data.symbol.getName() + ";"; - return objectString + postString; //Functions come after the declaration of the struct - } case function: { + if (data.valueType->baseType == template_type) + return "/* template function: " + data.symbol.getName() + " */"; output += "\n" + ValueTypeToCType(data.valueType) + " "; std::string nameDecoration, parameters; for (int j = 0; j < children.size()-1; j++) { @@ -132,22 +226,39 @@ std::string CGenerator::generate(NodeTree* from, NodeTree* enc parameters += ValueTypeToCType(children[j]->getData().valueType) + " " + generate(children[j], enclosingObject); nameDecoration += "_" + ValueTypeToCTypeDecoration(children[j]->getData().valueType); } - output += CifyFunctionName(data.symbol.getName()) + nameDecoration + "(" + parameters + ")\n" + generate(children[children.size()-1], enclosingObject); + output += CifyName(data.symbol.getName() + nameDecoration) + "(" + parameters + ")\n" + generate(children[children.size()-1], enclosingObject); return output; } case code_block: + { output += "{\n"; - tabLevel++; + std::string destructorString = ""; + tabLevel++; for (int i = 0; i < children.size(); i++) { //std::cout << "Line " << i << std::endl; std::string line = generate(children[i], enclosingObject); //std::cout << line << std::endl; output += line; - } - tabLevel--; + if (children[i]->getChildren().size() && children[i]->getChildren()[0]->getDataRef()->type == declaration_statement) { + NodeTree *identifier = children[i]->getChildren()[0]->getChildren()[0]; + Type* declarationType = identifier->getDataRef()->valueType; + if (declarationType->getIndirection()) + continue; + NodeTree *typeDefinition = declarationType->typeDefinition; + if (!typeDefinition) + continue; + if (typeDefinition->getDataRef()->scope.find("destruct") == typeDefinition->getDataRef()->scope.end()) + continue; + destructorString += tabs() + CifyName(typeDefinition->getDataRef()->symbol.getName()) + + "__" + "destruct" + "(&" + generate(identifier, enclosingObject) + ");\n";//Call the destructor + } + } + output += destructorString; + tabLevel--; output += tabs() + "}"; return output; - case expression: + } + case expression: output += " " + data.symbol.getName() + ", "; case boolean_expression: output += " " + data.symbol.getName() + " "; @@ -175,7 +286,12 @@ std::string CGenerator::generate(NodeTree* from, NodeTree* enc case declaration_statement: if (children.size() == 1) return ValueTypeToCType(children[0]->getData().valueType) + " " + generate(children[0], enclosingObject) + ";"; - else + else if (children[1]->getChildren().size() && children[1]->getChildren()[0]->getChildren().size() > 1 + && children[1]->getChildren()[0]->getChildren()[1] == children[0]) { + //That is, if we're a declaration with an init position call (Object a.construct()) + //We can tell if our function call (children[1])'s access operation([0])'s lhs ([1]) is the thing we just declared (children[0]) + return ValueTypeToCType(children[0]->getData().valueType) + " " + generate(children[0], enclosingObject) + "; " + generate(children[1]) + "/*Init Position Call*/"; + } else return ValueTypeToCType(children[0]->getData().valueType) + " " + generate(children[0], enclosingObject) + " = " + generate(children[1], enclosingObject) + ";"; case if_comp: if (generate(children[0], enclosingObject) == generatorString) @@ -198,11 +314,13 @@ std::string CGenerator::generate(NodeTree* from, NodeTree* enc if (funcType == function) { if (name == "++" || name == "--") return generate(children[1], enclosingObject) + name; - if (name == "*" && children.size() == 2) //Is dereference, not multiplication - return "*(" + generate(children[1], enclosingObject) + ")"; + if ( (name == "*" || name == "&" || name == "!" ) && children.size() == 2) //Is dereference, not multiplication, address-of, or other unary operator + return name + "(" + generate(children[1], enclosingObject) + ")"; + if (name == "[]") + return "(" + generate(children[1], enclosingObject) + ")[" +generate(children[2],enclosingObject) + "]"; if (name == "+" || name == "-" || name == "*" || name == "/" || name == "==" || name == ">=" || name == "<=" || name == "!=" || name == "<" || name == ">" || name == "%" || name == "+=" || name == "-=" || name == "*=" || name == "/=" || name == "||" - || name == "&&" || name == "!" ) + || name == "&&") return "((" + generate(children[1], enclosingObject) + ")" + name + "(" + generate(children[2], enclosingObject) + "))"; else if (name == "." || name == "->") { if (children.size() == 1) @@ -212,18 +330,24 @@ std::string CGenerator::generate(NodeTree* from, NodeTree* enc std::string functionName = children[2]->getDataRef()->symbol.getName(); NodeTree* possibleObjectType = children[1]->getDataRef()->valueType->typeDefinition; //If is an object method, generate it like one. Needs extension/modification for inheritence - if (possibleObjectType && possibleObjectType->getDataRef()->scope.find(functionName) != possibleObjectType->getDataRef()->scope.end()) { - std::string nameDecoration; - std::vector*> functionDefChildren = children[2]->getChildren(); //The function def is the rhs of the access operation - std::cout << "Decorating (in access-should be object) " << name << " " << functionDefChildren.size() << std::endl; - for (int i = 0; i < (functionDefChildren.size() > 0 ? functionDefChildren.size()-1 : 0); i++) - nameDecoration += "_" + ValueTypeToCTypeDecoration(functionDefChildren[i]->getData().valueType); -/*HERE*/ return possibleObjectType->getDataRef()->symbol.getName() +"__" + CifyFunctionName(functionName) + nameDecoration + "(" + (name == "." ? "&" : "") + generate(children[1], enclosingObject) + ","; - //The comma lets the upper function call know we already started the param list - //Note that we got here from a function call. We just pass up this special case and let them finish with the perentheses - } else { - std::cout << "Is not in scope or not type" << std::endl; - return "((" + generate(children[1], enclosingObject) + ")" + name + functionName + ")"; + if (possibleObjectType) { + NodeTree* unaliasedTypeDef = getMethodsObjectType(possibleObjectType, functionName); + if (unaliasedTypeDef) { //Test to see if the function's a member of this type_def, or if this is an alias, of the original type. Get this original type if it exists. + std::string nameDecoration; + std::vector*> functionDefChildren = children[2]->getChildren(); //The function def is the rhs of the access operation + std::cout << "Decorating (in access-should be object) " << name << " " << functionDefChildren.size() << std::endl; + for (int i = 0; i < (functionDefChildren.size() > 0 ? functionDefChildren.size()-1 : 0); i++) + nameDecoration += "_" + ValueTypeToCTypeDecoration(functionDefChildren[i]->getData().valueType); +/*HERE*/ return CifyName(unaliasedTypeDef->getDataRef()->symbol.getName()) +"__" + CifyName(functionName + nameDecoration) + "(" + (name == "." ? "&" : "") + generate(children[1], enclosingObject) + ","; + //The comma lets the upper function call know we already started the param list + //Note that we got here from a function call. We just pass up this special case and let them finish with the perentheses + } else { + std::cout << "Is not in scope or not type" << std::endl; + return "((" + generate(children[1], enclosingObject) + ")" + name + functionName + ")"; + } + } else { + std::cout << "Is not in scope or not type" << std::endl; + return "((" + generate(children[1], enclosingObject) + ")" + name + functionName + ")"; } } else { //return "((" + generate(children[1], enclosingObject) + ")" + name + generate(children[2], enclosingObject) + ")"; @@ -239,10 +363,10 @@ std::string CGenerator::generate(NodeTree* from, NodeTree* enc //Check to see if we're inside of an object and this is a method call bool isSelfObjectMethod = enclosingObject && contains(enclosingObject->getChildren(), children[0]); if (isSelfObjectMethod) - output += enclosingObject->getDataRef()->symbol.getName() +"__"; -/*HERE*/ output += CifyFunctionName(name) + nameDecoration + "("; + output += CifyName(enclosingObject->getDataRef()->symbol.getName()) +"__"; +/*HERE*/ output += CifyName(name + nameDecoration) + "("; if (isSelfObjectMethod) - output += children.size() > 1 ? "self," : "self"; + output += children.size() > 1 ? "this," : "this"; } } else { //This part handles cases where our definition isn't the function definition (that is, it is probabally the return from another function) @@ -272,22 +396,29 @@ std::string CGenerator::generate(NodeTree* from, NodeTree* enc return output; } +NodeTree* CGenerator::getMethodsObjectType(NodeTree* scope, std::string functionName) { + //check the thing + while (scope != scope->getDataRef()->valueType->typeDefinition) //type is an alias, follow it to the definition + scope = scope->getDataRef()->valueType->typeDefinition; + return (scope->getDataRef()->scope.find(functionName) != scope->getDataRef()->scope.end()) ? scope : NULL; +} -std::string CGenerator::generateObjectMethod(NodeTree* enclosingObject, NodeTree* from) { - std::string output; +// Returns the function prototype in the out param and the full definition normally +std::string CGenerator::generateObjectMethod(NodeTree* enclosingObject, NodeTree* from, std::string *functionPrototype) { ASTData data = from->getData(); Type enclosingObjectType = *(enclosingObject->getDataRef()->valueType); //Copy a new type so we can turn it into a pointer if we need to - enclosingObjectType.indirection++; + enclosingObjectType.increaseIndirection(); std::vector*> children = from->getChildren(); std::string nameDecoration, parameters; for (int i = 0; i < children.size()-1; i++) { parameters += ", " + ValueTypeToCType(children[i]->getData().valueType) + " " + generate(children[i]); nameDecoration += "_" + ValueTypeToCTypeDecoration(children[i]->getData().valueType); } - output += "\n" + ValueTypeToCType(data.valueType) + " " + enclosingObject->getDataRef()->symbol.getName() +"__" - + CifyFunctionName(data.symbol.getName()) + nameDecoration + "(" + ValueTypeToCType(&enclosingObjectType) - + " self" + parameters + ")\n" + generate(children[children.size()-1], enclosingObject); //Pass in the object so we can properly handle access to member stuff - return output; + std::string functionSignature = "\n" + ValueTypeToCType(data.valueType) + " " + CifyName(enclosingObject->getDataRef()->symbol.getName()) +"__" + + CifyName(data.symbol.getName()) + nameDecoration + "(" + ValueTypeToCType(&enclosingObjectType) + + " this" + parameters + ")"; + *functionPrototype += functionSignature + ";\n"; + return functionSignature + "\n" + generate(children[children.size()-1], enclosingObject); //Pass in the object so we can properly handle access to member stuff } std::string CGenerator::ValueTypeToCType(Type *type) { @@ -295,7 +426,7 @@ std::string CGenerator::ValueTypeToCType(Type *type) { switch (type->baseType) { case none: if (type->typeDefinition) - return_type = type->typeDefinition->getDataRef()->symbol.getName(); + return_type = CifyName(type->typeDefinition->getDataRef()->symbol.getName()); else return_type = "none"; break; @@ -321,7 +452,7 @@ std::string CGenerator::ValueTypeToCType(Type *type) { return_type = "unknown_ValueType"; break; } - for (int i = 0; i < type->indirection; i++) + for (int i = 0; i < type->getIndirection(); i++) return_type += "*"; return return_type; } @@ -331,7 +462,7 @@ std::string CGenerator::ValueTypeToCTypeDecoration(Type *type) { switch (type->baseType) { case none: if (type->typeDefinition) - return_type = type->typeDefinition->getDataRef()->symbol.getName(); + return_type = CifyName(type->typeDefinition->getDataRef()->symbol.getName()); else return_type = "none"; break; @@ -357,12 +488,12 @@ std::string CGenerator::ValueTypeToCTypeDecoration(Type *type) { return_type = "unknown_ValueType"; break; } - for (int i = 0; i < type->indirection; i++) + for (int i = 0; i < type->getIndirection(); i++) return_type += "_P__"; return return_type; } -std::string CGenerator::CifyFunctionName(std::string name) { +std::string CGenerator::CifyName(std::string name) { std::string operatorsToReplace[] = { "+", "plus", "-", "minus", "*", "star", @@ -392,7 +523,14 @@ std::string CGenerator::CifyFunctionName(std::string name) { "|=", "pipeequals", "*=", "starequals", "<<=", "doublerightequals", + "<", "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/GraphStructuredStack.cpp b/src/GraphStructuredStack.cpp index dcdf2ff..1d117f3 100644 --- a/src/GraphStructuredStack.cpp +++ b/src/GraphStructuredStack.cpp @@ -117,6 +117,13 @@ void GraphStructuredStack::addEdge(NodeTree* start, NodeTree* end, Nod edges[std::make_pair(start, end)] = edge; } +std::vector GraphStructuredStack::getFrontier(int frontier) { + std::vector toReturn; + for (int i = 0; i < gss[frontier]->size(); i++) + toReturn.push_back((*(gss[frontier]))[i]->getData()); + return toReturn; +} + std::string GraphStructuredStack::toString() { std::string tostring = ""; for (std::vector*>*>::size_type i = 0; i < gss.size(); i++) { diff --git a/src/Importer.cpp b/src/Importer.cpp index 88c367f..7d6ac37 100644 --- a/src/Importer.cpp +++ b/src/Importer.cpp @@ -1,9 +1,12 @@ #include "Importer.h" -Importer::Importer(Parser* parserIn) { +Importer::Importer(Parser* parserIn, std::vector includePaths) { //constructor parser = parserIn; + this->includePaths = includePaths; + ASTTransformer = new ASTTransformation(this); + removeSymbols.push_back(Symbol("$NULL$", true)); removeSymbols.push_back(Symbol("WS", false)); removeSymbols.push_back(Symbol("\\(", true)); removeSymbols.push_back(Symbol("\\)", true)); @@ -13,13 +16,15 @@ Importer::Importer(Parser* parserIn) { removeSymbols.push_back(Symbol("}", true)); removeSymbols.push_back(Symbol("(", true)); removeSymbols.push_back(Symbol(")", true)); - removeSymbols.push_back(Symbol("import", true)); //Don't need the actual text of the symbol + removeSymbols.push_back(Symbol("import", true)); removeSymbols.push_back(Symbol("interpreter_directive", false)); removeSymbols.push_back(Symbol("if", true)); removeSymbols.push_back(Symbol("while", true)); removeSymbols.push_back(Symbol("__if_comp__", true)); removeSymbols.push_back(Symbol("comp_simple_passthrough", true)); removeSymbols.push_back(Symbol("typedef", true)); + removeSymbols.push_back(Symbol("template", true)); + removeSymbols.push_back(Symbol("\\|", true)); collapseSymbols.push_back(Symbol("opt_typed_parameter_list", false)); collapseSymbols.push_back(Symbol("opt_parameter_list", false)); @@ -31,23 +36,102 @@ Importer::Importer(Parser* parserIn) { collapseSymbols.push_back(Symbol("unorderd_list_part", false)); collapseSymbols.push_back(Symbol("if_comp_pred", false)); 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)); + collapseSymbols.push_back(Symbol("dec_type", false)); } Importer::~Importer() { //destructor + delete ASTTransformer; } -NodeTree* Importer::import(std::string fileName) { +void Importer::registerAST(std::string name, NodeTree* ast, NodeTree* syntaxTree) { + imported[name] = ast; + importedTrips.push_back({name, ast, syntaxTree}); + std::cout << "REGISTERD " << name << std::endl; +} + +NodeTree* Importer::getUnit(std::string fileName) { + std::cout << "\n\nImporting " << fileName << " "; //Check to see if we've already done it - if (imported.find(fileName) != imported.end()) + if (imported.find(fileName) != imported.end()) { + std::cout << "Already Imported!" << std::endl; return imported[fileName]; + } + std::cout << "Not yet imported" << std::endl; + + return NULL; +} + +NodeTree* Importer::importFirstPass(std::string fileName) { + NodeTree* ast = getUnit(fileName); + if (ast == NULL) { + NodeTree* parseTree = parseAndTrim(fileName); + if (!parseTree) + return NULL; + //Call with ourself to allow the transformation to call us to import files that it needs + ast = ASTTransformer->firstPass(fileName, parseTree); //This firstPass will register itself + } + return ast; +} + +void Importer::import(std::string fileName) { + + //Start the ball rolling by importing and running the first pass on the first file. + //This will import, first pass and register all the other files too. + + std::cout << "\n\n =====FIRST PASS===== \n\n" << std::endl; + importFirstPass(fileName); //First pass defines all objects + + std::cout << "\n\n =====SECOND PASS===== \n\n" << std::endl; + for (importTriplet i : importedTrips) //Second pass defines data inside objects, outside declaration statements, + std::cout << "\n\nSecond pass for: " << i.name << std::endl, ASTTransformer->secondPass(i.ast, i.syntaxTree); //function prototypes, and identifiers (as we now have all type defs) + + std::cout << "\n\n =====THIRD PASS===== \n\n" << std::endl; + for (importTriplet i : importedTrips) //Third pass redoes all imports to import the new function prototypes and identifiers + std::cout << "\n\nThird pass for: " << i.name << std::endl, ASTTransformer->thirdPass(i.ast); + + std::cout << "\n\n =====FOURTH PASS===== \n\n" << std::endl; + for (importTriplet i : importedTrips) //Fourth pass finishes up by doing all function bodies + std::cout << "\n\nFourth pass for: " << i.name << std::endl, ASTTransformer->fourthPass(i.ast, i.syntaxTree); //With that, we're done + + //Note that class template instantiation can happen in the second or fourth passes and that function template instantion + //can happen in the fourth pass. + + std::ofstream outFileAST; + for (importTriplet i : importedTrips) { + std::string outputName = i.name + "out"; + outFileAST.open((outputName + ".AST.dot").c_str()); + if (!outFileAST.is_open()) { + std::cout << "Problem opening second output file " << outputName + ".AST.dot" << "\n"; + return; + } + if (i.ast) { + outFileAST << i.ast->DOTGraphString() << std::endl; + } else { + std::cout << "Tree returned from ASTTransformation for " << fileName << " is NULL!" << std::endl; + } + outFileAST.close(); + } +} + +NodeTree* Importer::parseAndTrim(std::string fileName) { std::ifstream programInFile; - std::ofstream outFile, outFileTransformed, outFileAST; + std::ofstream outFile, outFileTransformed; + std::string outputName = fileName + "out"; - - programInFile.open(fileName); + + for (auto i : includePaths) { + programInFile.open(i+fileName); + if (programInFile.is_open()) + break; + else + std::cout << i+fileName << " is no good" << std::endl; + } if (!programInFile.is_open()) { std::cout << "Problem opening programInFile " << fileName << "\n"; return NULL; @@ -65,12 +149,6 @@ NodeTree* Importer::import(std::string fileName) { return NULL; } - outFileAST.open((outputName + ".AST.dot").c_str()); - if (!outFileAST.is_open()) { - std::cout << "Probelm opening second output file " << outputName + ".AST.dot" << "\n"; - return NULL; - } - std::string programInputFileString, line; while(programInFile.good()) { getline(programInFile, line); @@ -85,8 +163,10 @@ NodeTree* Importer::import(std::string fileName) { //std::cout << parseTree->DOTGraphString() << std::endl; outFile << parseTree->DOTGraphString() << std::endl; } else { - std::cout << "ParseTree returned from parser is NULL!" << std::endl; - } + std::cout << "ParseTree returned from parser for " << fileName << " is NULL!" << std::endl; + outFile.close(); outFileTransformed.close(); + return NULL; + } outFile.close(); //Remove Transformations @@ -106,19 +186,7 @@ NodeTree* Importer::import(std::string fileName) { } outFileTransformed.close(); - //Call with ourself to allow the transformation to call us to import files that it needs - NodeTree* AST = ASTTransformation(this).transform(parseTree); - - if (AST) { - outFileAST << AST->DOTGraphString() << std::endl; - } else { - std::cout << "Tree returned from ASTTransformation is NULL!" << std::endl; - } - outFileAST.close(); - - imported[fileName] = AST; - - return AST; + return parseTree; } std::map*> Importer::getASTMap() { diff --git a/src/ParseAction.cpp b/src/ParseAction.cpp index 64f3e95..1e21714 100644 --- a/src/ParseAction.cpp +++ b/src/ParseAction.cpp @@ -22,18 +22,33 @@ ParseAction::~ParseAction() { } -const bool ParseAction::equalsExceptLookahead(const ParseAction &other) { +const bool ParseAction::equalsExceptLookahead(const ParseAction &other) const { return( action == other.action && ( reduceRule == other.reduceRule || reduceRule->equalsExceptLookahead(*(other.reduceRule)) ) && shiftState == other.shiftState); } -const bool ParseAction::operator==(const ParseAction &other) { +const bool ParseAction::operator==(const ParseAction &other) const { return( action == other.action && ( reduceRule == other.reduceRule || *reduceRule == *(other.reduceRule) ) && shiftState == other.shiftState); } -const bool ParseAction::operator!=(const ParseAction &other) { +const bool ParseAction::operator!=(const ParseAction &other) const { return !(this->operator==(other)); } +//Exists so we can put ParseActions into sets +const bool ParseAction::operator<(const ParseAction &other) const { + if (action != other.action) + return action < other.action; + if (reduceRule != other.reduceRule) { + if (! (reduceRule && other.reduceRule)) { + return reduceRule < other.reduceRule; + } else { + return *reduceRule < *(other.reduceRule); + } + } + + return shiftState < other.shiftState; +} + std::string ParseAction::actionToString(ActionType action) { switch (action) { case REDUCE: @@ -53,12 +68,12 @@ std::string ParseAction::actionToString(ActionType action) { } } -std::string ParseAction::toString() { +std::string ParseAction::toString(bool printRuleLookahead) { std::string outputString = ""; outputString += actionToString(action); if (reduceRule != NULL) - outputString += " " + reduceRule->toString(); + outputString += " " + reduceRule->toString(printRuleLookahead); if (shiftState != -1) - outputString += " " + intToString(shiftState); + outputString += " " + intToString(shiftState); return(outputString); -} \ No newline at end of file +} diff --git a/src/ParseRule.cpp b/src/ParseRule.cpp index e27208a..2b8996c 100644 --- a/src/ParseRule.cpp +++ b/src/ParseRule.cpp @@ -16,18 +16,34 @@ ParseRule::~ParseRule() { } -const bool ParseRule::equalsExceptLookahead(const ParseRule &other) { +const bool ParseRule::equalsExceptLookahead(const ParseRule &other) const { return(leftHandle == other.leftHandle && rightSide == other.rightSide && pointerIndex == other.pointerIndex); } -const bool ParseRule::operator==(const ParseRule &other) { +const bool ParseRule::operator==(const ParseRule &other) const { return(equalsExceptLookahead(other) && (lookahead == NULL ? other.lookahead == NULL : (*lookahead) == *(other.lookahead))); } -const bool ParseRule::operator!=(const ParseRule &other) { +const bool ParseRule::operator!=(const ParseRule &other) const { return !(this->operator==(other)); } +const bool ParseRule::operator<(const ParseRule &other) const { + //Used for ordering so we can put ParseRule's in sets, and also so that ParseActions will have an ordering + if (leftHandle != other.leftHandle) + return leftHandle < other.leftHandle; + if (rightSide != other.rightSide) + return rightSide < other.rightSide; + if (lookahead != other.lookahead) { + if (! (lookahead && other.lookahead)) { + return lookahead < other.lookahead; + } else { + return *lookahead < *(other.lookahead); + } + } + return false; +} + ParseRule* ParseRule::clone() { std::vector* newLookahead = NULL; if (lookahead) { @@ -111,7 +127,7 @@ std::vector* ParseRule::getLookahead() { return lookahead; } -std::string ParseRule::toString() { +std::string ParseRule::toString(bool printLookahead) { std::string concat = leftHandle.toString() + " -> "; for (int i = 0; i < rightSide.size(); i++) { if (i == pointerIndex) @@ -120,7 +136,7 @@ std::string ParseRule::toString() { } if (pointerIndex >= rightSide.size()) concat += "(*)"; - if (lookahead != NULL) { + if (printLookahead && lookahead != NULL) { concat += "**"; for (std::vector::size_type i = 0; i < lookahead->size(); i++) concat += (*lookahead)[i].toString(); diff --git a/src/Parser.cpp b/src/Parser.cpp index 5971829..e32a9cf 100644 --- a/src/Parser.cpp +++ b/src/Parser.cpp @@ -32,10 +32,22 @@ Symbol Parser::getOrAddSymbol(std::string symbolString, bool isTerminal) { void Parser::loadGrammer(std::string grammerInputString) { reader.setString(grammerInputString); - std::string currToken = reader.word(); + std::string currToken = reader.word(false); //Don't truncate so we can find the newline correctly (needed for comments) while(currToken != "") { - //Load the left of the rule + //First, if this starts with a '#', skip this + if (currToken.front() == '#') { + //If this line is more than one token long, eat it + std::cout << "Ate: " << currToken << std::endl; + if (currToken.back() != '\n') + std::cout << "Eating " << reader.line() << " b/c grammer comment" << std::endl; + currToken = reader.word(false); + continue; + } + if (currToken.back() == '\n' || currToken.back() == ' ' || currToken.back() == '\t') + currToken.erase(currToken.size()-1); + + //Load the left of the rule ParseRule* currentRule = new ParseRule(); Symbol leftSide = getOrAddSymbol(currToken, false); //Left handle is never a terminal currentRule->setLeftHandle(leftSide); @@ -76,7 +88,7 @@ void Parser::loadGrammer(std::string grammerInputString) { loadedGrammer.push_back(currentRule); //Get next token - currToken = reader.word(); + currToken = reader.word(false); } //std::cout << "Parsed!\n"; @@ -117,59 +129,86 @@ int Parser::stateNum(State* state) { return -1; } -std::vector* Parser::firstSet(Symbol token) { - std::vector avoidList; - return firstSet(token, avoidList); -} - -std::vector* Parser::firstSet(Symbol token, std::vector avoidList) { - //If we've already done this token, don't do it again +std::vector Parser::firstSet(Symbol token, std::vector avoidList, bool addNewTokens) { + if (tokenFirstSet.find(token) != tokenFirstSet.end()) + return tokenFirstSet[token]; + //If we've already done this token, don't do it again for (std::vector::size_type i = 0; i < avoidList.size(); i++) - if (avoidList[i] == token) { - return new std::vector(); - } + if (avoidList[i] == token) + return std::vector(); avoidList.push_back(token); - std::vector* first = new std::vector(); + + std::vector first; //First, if the symbol is a terminal, than it's first set is just itself. if (token.isTerminal()) { - first->push_back(token); + first.push_back(token); return(first); } //Otherwise.... //Ok, to make a first set, go through the grammer, if the token it's left side, add it's production's first token's first set. //If that one includes mull, do the next one too (if it exists). Symbol rightToken; - std::vector* recursiveFirstSet = NULL; + std::vector recursiveFirstSet; for (std::vector::size_type i = 0; i < loadedGrammer.size(); i++) { if (token == loadedGrammer[i]->getLeftSide()) { //Loop through the rule adding first sets for each token if the previous token contained NULL - bool recFirstSetHasNull = false; int j = 0; do { rightToken = loadedGrammer[i]->getRightSide()[j]; //Get token of the right side of this rule if (rightToken.isTerminal()) { - recursiveFirstSet = new std::vector(); - recursiveFirstSet->push_back(rightToken); + recursiveFirstSet.push_back(rightToken); } else { //Add the entire set - recursiveFirstSet = firstSet(rightToken, avoidList); + recursiveFirstSet = firstSet(rightToken, avoidList, false);//Don't add children to cache, as early termination may cause them to be incomplete } - first->insert(first->end(), recursiveFirstSet->begin(), recursiveFirstSet->end()); - //Check to see if the current recursiveFirstSet contains NULL, if so, then go through again with the next token. (if there is one) - recFirstSetHasNull = false; - for (std::vector::size_type k = 0; k < recursiveFirstSet->size(); k++) { - if ((*recursiveFirstSet)[k] == nullSymbol) { - recFirstSetHasNull = true; - } - } - delete recursiveFirstSet; + first.insert(first.end(), recursiveFirstSet.begin(), recursiveFirstSet.end()); j++; - } while (recFirstSetHasNull && loadedGrammer[i]->getRightSide().size() > j); + } while (isNullable(rightToken) && loadedGrammer[i]->getRightSide().size() > j); } } + if (addNewTokens) + tokenFirstSet[token] = first; return(first); } +bool Parser::isNullable(Symbol token) { + if (tokenNullable.find(token) != tokenNullable.end()) + return tokenNullable[token]; + bool nullable = isNullableHelper(token, std::set()); + tokenNullable[token] = nullable; + return nullable; +} +//We use this helper function to recurse because it is possible to wind up with loops, and if so we want +//early termination. However, this means that nullable determinations in the middle of the loop are inaccurate +//(since we terminated early), so we don't want to save them. Thus, for simplicity, only the main method will +//add to the cache. This is somewhat unfortunate for preformance, but the necessary additions to keep track of +//invalidated state are more complicated than it's worth. +bool Parser::isNullableHelper(Symbol token, std::set done) { + if (token.isTerminal()) + return token == nullSymbol; + if (done.find(token) != done.end()) + return false; + done.insert(token); + if (tokenNullable.find(token) != tokenNullable.end()) + return tokenNullable[token]; + + for (std::vector::size_type i = 0; i < loadedGrammer.size(); i++) { + if (token == loadedGrammer[i]->getLeftSide()) { + auto rightSide = loadedGrammer[i]->getRightSide(); + bool ruleNullable = true; + for (int j = 0; j < rightSide.size(); j++) { + if (!isNullableHelper(rightSide[j], done)) { + ruleNullable = false; + break; + } + } + if (ruleNullable) + return true; + } + } + return false; +} + //Return the correct lookahead. This followSet is built based on the current rule's lookahead if at end, or the next Symbol's first set. std::vector* Parser::incrementiveFollowSet(ParseRule* rule) { //Advance the pointer past the current Symbol (the one we want the followset for) to the next symbol (which might be in our follow set, or might be the end) @@ -178,25 +217,24 @@ std::vector* Parser::incrementiveFollowSet(ParseRule* rule) { //Get the first set of the next Symbol. If it contains nullSymbol, keep doing for the next one std::vector* followSet = new std::vector(); - std::vector* symbolFirstSet; + std::vector symbolFirstSet; bool symbolFirstSetHasNull = true; while (symbolFirstSetHasNull && !rule->isAtEnd()) { symbolFirstSetHasNull = false; symbolFirstSet = firstSet(rule->getAtNextIndex()); - for (std::vector::size_type i = 0; i < symbolFirstSet->size(); i++) { - if ((*symbolFirstSet)[i] == nullSymbol) { + for (std::vector::size_type i = 0; i < symbolFirstSet.size(); i++) { + if (symbolFirstSet[i] == nullSymbol) { symbolFirstSetHasNull = true; - symbolFirstSet->erase(symbolFirstSet->begin()+i); + symbolFirstSet.erase(symbolFirstSet.begin()+i); break; } } - followSet->insert(followSet->end(), symbolFirstSet->begin(), symbolFirstSet->end()); - delete symbolFirstSet; + followSet->insert(followSet->end(), symbolFirstSet.begin(), symbolFirstSet.end()); rule->advancePointer(); } if (rule->isAtEnd()) { - symbolFirstSet = rule->getLookahead(); - followSet->insert(followSet->end(), symbolFirstSet->begin(), symbolFirstSet->end()); + symbolFirstSet = *(rule->getLookahead()); + followSet->insert(followSet->end(), symbolFirstSet.begin(), symbolFirstSet.end()); } std::vector* followSetReturn = new std::vector(); for (std::vector::size_type i = 0; i < followSet->size(); i++) { @@ -261,7 +299,7 @@ void Parser::addStates(std::vector< State* >* stateSets, State* state, std::queu //Clone the current rule ParseRule* advancedRule = (*currStateTotal)[i]->clone(); //Try to advance the pointer, if sucessful see if it is the correct next symbol - if (advancedRule->advancePointer()) { + if (advancedRule->advancePointer()) { //Technically, it should be the set of rules sharing this symbol advanced past in the basis for new state //So search our new states to see if any of them use this advanced symbol as a base. diff --git a/src/RNGLRParser.cpp b/src/RNGLRParser.cpp index cbd111f..c95a526 100644 --- a/src/RNGLRParser.cpp +++ b/src/RNGLRParser.cpp @@ -8,6 +8,20 @@ RNGLRParser::~RNGLRParser() { // } +void RNGLRParser::printReconstructedFrontier(int frontier) { + std::vector lastFrontier = gss.getFrontier(frontier); + for (int j = 0; j < lastFrontier.size(); j++) { + std::cout << "State: " << lastFrontier[j] << std::endl; + std::vector> stateParseActions = table.stateAsParseActionVector(lastFrontier[j]); + std::set> noRepeats; + for (auto k : stateParseActions) + noRepeats.insert(k); + for (auto k : noRepeats) + std::cout << k.first << " " << k.second.toString(false) << std::endl; + std::cout << std::endl; + } +} + NodeTree* RNGLRParser::parseInput(std::string inputString) { input.clear(); gss.clear(); @@ -53,7 +67,7 @@ NodeTree* RNGLRParser::parseInput(std::string inputString) { // std::cout << "\nDone with Lexing, length:" << input.size() << std::endl; // std::cout << input[0].toString() << std::endl; - + // for (int i = 0; i < input.size(); i++) // std::cout << "|" << input[i]->toString() << "|"; // std::cout << std::endl; @@ -74,7 +88,6 @@ NodeTree* RNGLRParser::parseInput(std::string inputString) { else if (firstActions[i]->action == ParseAction::REDUCE && fullyReducesToNull(firstActions[i]->reduceRule)) { Reduction newReduction = {v0, firstActions[i]->reduceRule->getLeftSide(), 0, getNullableParts(firstActions[i]->reduceRule), NULL}; toReduce.push(newReduction); - //toReduce.push(std::make_pair(std::make_pair(v0, firstActions[i]->reduceRule->getLeftSide()), 0)); } } @@ -89,14 +102,21 @@ NodeTree* RNGLRParser::parseInput(std::string inputString) { std::cout << "Parsing failed on " << input[i].toString() << std::endl; std::cout << "Problem is on line: " << findLine(i) << std::endl; std::cout << "Nearby is:" << std::endl; - const int range = 10; + int range = 10; for (int j = (i-range >= 0 ? i-range : 0); j < (i+range < input.size() ? i+range : input.size()); j++) if (j == i) std::cout << "||*||*||" << input[j].toString() << "||*||*|| "; else std::cout << input[j].toString() << " "; std::cout << std::endl; - break; + range = 1; +/* 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; } //Clear the vector of SPPF nodes created every step @@ -186,7 +206,7 @@ void RNGLRParser::reducer(int i) { toStateNode = gss.newNode(toState); gss.addToFrontier(i, toStateNode); gss.addEdge(toStateNode, currentReached, newLabel); - + //std::cout << "Adding shifts and reductions for a state that did not exist" << std::endl; std::vector actions = *(table.get(toState, input[i])); for (std::vector::size_type k = 0; k < actions.size(); k++) { @@ -319,7 +339,7 @@ void RNGLRParser::addStates(std::vector< State* >* stateSets, State* state, std: //Clone the current rule ParseRule* advancedRule = (*currStateTotal)[i]->clone(); //Try to advance the pointer, if sucessful see if it is the correct next symbol - if (advancedRule->advancePointer()) { + if (advancedRule->advancePointer()) { //Technically, it should be the set of rules sharing this symbol advanced past in the basis for new state //So search our new states to see if any of them use this advanced symbol as a base. @@ -353,10 +373,10 @@ void RNGLRParser::addStates(std::vector< State* >* stateSets, State* state, std: stateAlreadyInAllStates = true; //If it does exist, we should add it as the shift/goto in the action table //std::cout << "newStates[" << i << "] == stateSets[" << j << "]" << std::endl; - + if (!((*stateSets)[j]->basisEquals(*(newStates[i])))) toDo->push((*stateSets)[j]); - + (*stateSets)[j]->combineStates(*(newStates[i])); //std::cout << j << "\t Hay, doing an inside loop state reductions!" << std::endl; addStateReductionsToTable((*stateSets)[j]); diff --git a/src/Table.cpp b/src/Table.cpp index 5f37e1f..e4cdfd4 100644 --- a/src/Table.cpp +++ b/src/Table.cpp @@ -251,7 +251,7 @@ void Table::add(int stateNum, Symbol tranSymbol, ParseAction* action) { //If this table slot is empty //std::cout << "table[stateNum] is " << table[stateNum] << std::endl; //std::cout << "blank is " << (*(table[stateNum]))[symbolIndex] << std::endl; - + if ( (*(table[stateNum]))[symbolIndex] == NULL ) { //std::cout << "Null, adding " << action->toString() << std::endl; std::vector* actionList = new std::vector(); @@ -262,7 +262,7 @@ void Table::add(int stateNum, Symbol tranSymbol, ParseAction* action) { //else if ( !(*(table[stateNum]))[symbolIndex]->equalsExceptLookahead(*action)) { else { //std::cout << "not Null!" << std::endl; - //std::cout << "State: " << stateNum << " Conflict between old: " << (*(table[stateNum]))[symbolIndex]->toString() << " and new: " << action->toString() << " on " << tranSymbol->toString() << std::endl; + //std::cout << "State: " << stateNum << " Conflict between old: " << (*(table[stateNum]))[symbolIndex]->toString() << " and new: " << action->toString() << " on " << tranSymbol->toString() << std::endl; //Check to see if this action is already in the list @@ -353,6 +353,17 @@ ParseAction* Table::getShift(int state, Symbol token) { return shift; } +std::vector> Table::stateAsParseActionVector(int state) { + std::vector> reconstructedState; + std::vector*>* stateVec = table[state]; + for (int i = 0; i < stateVec->size(); i++) + if (std::vector* forStateAndSymbol = (*stateVec)[i]) + for (int j = 0; j < forStateAndSymbol->size(); j++) + reconstructedState.push_back(std::make_pair(symbolIndexVec[i].toString(),*((*forStateAndSymbol)[j]))); + + return reconstructedState; +} + std::string Table::toString() { std::string concat = ""; for (std::vector::size_type i = 0; i < symbolIndexVec.size(); i++) diff --git a/src/Tester.cpp b/src/Tester.cpp new file mode 100644 index 0000000..3f4cbdf --- /dev/null +++ b/src/Tester.cpp @@ -0,0 +1,69 @@ +#include "Tester.h" + +Tester::Tester(std::string krakenInvocation, std::string krakenGrammerLocation) : krakenInvocation(krakenInvocation), krakenGrammerLocation(krakenGrammerLocation) { + //initlization list + removeCmd = "rm"; + resultsExtention = ".results"; + expectedExtention = ".expected_results"; + krakenExtention = ".krak"; + changePermissions = "chmod 755"; + shell = "sh"; + redirect = ">"; +} + +Tester::~Tester() { + //Nothing +} + +int Tester::ssystem(std::string command) { + return system(command.c_str()); +} + +void Tester::cleanExtras(std::string fileName) { + ssystem(removeCmd + " " + fileName); + ssystem(removeCmd + " " + fileName + krakenExtention + "out*"); + ssystem(removeCmd + " " + fileName + krakenExtention + ".c"); + ssystem(removeCmd + " " + fileName + ".sh"); + ssystem(removeCmd + " " + fileName + resultsExtention); +} + +bool Tester::run(std::string fileName) { + std::cout << "Testing: " << fileName << " with " << krakenInvocation << " and " << krakenGrammerLocation << std::endl; + + cleanExtras(fileName); + + ssystem(changePermissions + " " + fileName); + ssystem(krakenInvocation + " " + fileName + krakenExtention + " " + krakenGrammerLocation + " " + fileName); + ssystem(shell + " " + fileName + ".sh"); + ssystem(fileName + " " + redirect + " " + fileName + resultsExtention); + + bool result = compareFiles(fileName + expectedExtention, fileName + resultsExtention); + + //If the test was succesful, we don't need all the extra files + if (result) + cleanExtras(fileName); + + return result; +} + +bool Tester::compareFiles(std::string file1Path, std::string file2Path) { + std::ifstream file1, file2; + file1.open(file1Path); + if (!file1.is_open()) { + std::cout << file1Path << " could not be opened!" << std::endl; + return false; + } + file2.open(file2Path); + if (!file2.is_open()) { + std::cout << file2Path << " could not be opened!" << std::endl; + return false; + } + + std::string file1contents = readFile(file1); + std::string file2contents = readFile(file2); + + // std::cout << "file1: " << file1contents << std::endl; + // std::cout << "file2: " << file2contents << std::endl; + // std::cout << "comp: " << file1contents.compare(file2contents) << std::endl; + return file1contents.compare(file2contents) == 0; +} diff --git a/src/Type.cpp b/src/Type.cpp index 2e40328..a6988e6 100644 --- a/src/Type.cpp +++ b/src/Type.cpp @@ -4,49 +4,68 @@ Type::Type() { indirection = 0; baseType = none; typeDefinition = 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; } -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; } -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; + traits = traitsIn; + templateDefinition = NULL; } +Type::Type(ValueType typeIn, NodeTree* templateDefinitionIn, std::set traitsIn) { + indirection = 0; + baseType = typeIn; + typeDefinition = NULL; + templateDefinition = templateDefinitionIn; + traits = traitsIn; +} + + Type::~Type() { } const bool Type::operator==(const Type &other) const { - return( baseType == other.baseType && indirection == other.indirection && typeDefinition == other.typeDefinition); + return( baseType == other.baseType && indirection == other.indirection && typeDefinition == other.typeDefinition && templateDefinition == other.templateDefinition && other.traits == traits); } const bool Type::operator!=(const Type &other) const { return(!this->operator==(other)); } -std::string Type::toString() { +std::string Type::toString(bool showTraits) { std::string typeString; switch (baseType) { case none: @@ -55,6 +74,12 @@ std::string Type::toString() { else typeString = "none"; break; + case template_type: + typeString = "template: " + templateDefinition->getDataRef()->toString(); + break; + case template_type_type: + typeString = "template_type_type"; + break; case void_type: typeString = "void"; break; @@ -81,5 +106,35 @@ std::string Type::toString() { } for (int i = 0; i < indirection; i++) typeString += "*"; + if (traits.size() && showTraits) { + 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, traits); +} + +int Type::getIndirection() { + return indirection; +} + +void Type::setIndirection(int indirectionIn) { + indirection = indirectionIn; +} + +void Type::increaseIndirection() { + setIndirection(indirection+1); +} +void Type::decreaseIndirection() { + setIndirection(indirection-1); +} + +void Type::modifyIndirection(int mod) { + setIndirection(indirection + mod); +} diff --git a/src/util.cpp b/src/util.cpp index a3c7802..296807e 100644 --- a/src/util.cpp +++ b/src/util.cpp @@ -71,4 +71,13 @@ std::string join(const std::vector &strVec, std::string joinStr) { return joinedStr; } +std::string readFile(std::istream &file) { + std::string line, contents; + while(file.good()) { + getline(file, line); + contents.append(line+"\n"); + } + return contents; +} + diff --git a/stdlib/io.krak b/stdlib/io.krak new file mode 100644 index 0000000..552ec4d --- /dev/null +++ b/stdlib/io.krak @@ -0,0 +1,59 @@ +__if_comp__ __C__ __simple_passthrough__ """ + #include +""" + +|void| println() { + print("\n"); +} + +|void| print(|char*| toPrint) { + __if_comp__ __C__ { + __simple_passthrough__ """ + printf(toPrint); + """ + } + return; +} + +|void| println(|char*| toPrint) { + print(toPrint); + println(); +} + +|void| print(|int| toPrint) { + __if_comp__ __C__ { + __simple_passthrough__ """ + printf("%d", toPrint); + """ + } + return; +} + +|void| println(|int| toPrint) { + print(toPrint); + println(); +} + +|void| print(|float| toPrint) { + __if_comp__ __C__ { + __simple_passthrough__ """ + printf("%f", 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/stdlib/math.krak b/stdlib/math.krak new file mode 100644 index 0000000..0652e47 --- /dev/null +++ b/stdlib/math.krak @@ -0,0 +1,9 @@ + +|int| NotPi = 3; +|float| Pi = 3.141592654; + +|int| fibanacci(|int| num) { + if (num < 2) + return 1; + return fibanacci(num-1) + fibanacci(num-2); +} diff --git a/stdlib/mem.krak b/stdlib/mem.krak new file mode 100644 index 0000000..406592a --- /dev/null +++ b/stdlib/mem.krak @@ -0,0 +1,64 @@ +__if_comp__ __C__ __simple_passthrough__ """ + #include +""" + +/* we have a template versions so we don't have to cast (because we don't have that yet) */ + +template |T*| malloc(|int| size) { + |T*| memPtr = 0; + __if_comp__ __C__ { + __simple_passthrough__ """ + memPtr = malloc(size); + """ + } + return memPtr; +} + +template |void| free(|T*| memPtr) { + __if_comp__ __C__ { + __simple_passthrough__ """ + free(memPtr); + """ + } +} + +template |int| sizeof() { + |int| result = 0; + |T| testObj; + __if_comp__ __C__ { + __simple_passthrough__ """ + result = sizeof(testObj); + """ + } + return result; +} + +template |T*| new(|int| count) { + return malloc( sizeof() * count ); +} + +template |T*| new() { + return new(1); +} + +/* We specilize on the trait Destructable to decide on whether or not the destructor should be called */ +template |void| delete(|T*| toDelete, |int| itemCount) { + delete(toDelete); +} + +/* Calling this with itemCount = 0 allows you to delete destructable objects without calling their destructors. */ +template |void| delete(|T*| toDelete, |int| itemCount) { + for (|int| i = 0; i < itemCount; i++;) + toDelete[i].destruct(); + delete(toDelete); +} + +/* We specilize on the trait Destructable to decide on whether or not the destructor should be called */ +template |void| delete(|T*| toDelete) { + free(toDelete); +} + +template |void| delete(|T*| toDelete) { + toDelete->destruct(); + free(toDelete); +} diff --git a/stdlib/trivial_container.krak b/stdlib/trivial_container.krak new file mode 100644 index 0000000..80bebeb --- /dev/null +++ b/stdlib/trivial_container.krak @@ -0,0 +1,9 @@ +import io; + +typedef template trivialContainer { + |T| data; + |void| print() { + print(data); + } +}; + diff --git a/stdlib/util.krak b/stdlib/util.krak new file mode 100644 index 0000000..70e605c --- /dev/null +++ b/stdlib/util.krak @@ -0,0 +1,12 @@ + +template |T| greater(|T| a, |T| b) { + if (a > b) + return a; + return b; +} + +template |T| lesser(|T| a, |T| b) { + if (a > b) + return b; + return a; +} diff --git a/stdlib/vector.krak b/stdlib/vector.krak new file mode 100644 index 0000000..0cf12df --- /dev/null +++ b/stdlib/vector.krak @@ -0,0 +1,55 @@ +import mem; +import util; +import io; + +typedef template vector (Destructable) { + |T*| data; + |int| size; + |int| available; + + |vector*| construct() { + size = 0; + available = 8; + data = new(8); + return this; + } + + |void| destruct() { + delete(data); + } + + |bool| resize(|int| newSize) { + |T*| newData = new(newSize); + if (!newData) + return false; + for (|int| i = 0; i < lesser(size, newSize); i++;) + newData[i] = data[i]; + delete(data, 0); + return true; + } + + |T| at(|int| index) { + return get(index); + } + + |T| get(|int| index) { + if (index < 0 || index >= size) { + println("Vector access out of bounds! Retuning 0th element as sanest option"); + return data[0]; + } + return data[index]; + } + + |void| set(|int| index, |T| dataIn) { + if (index < 0 || index >= size) + return; + data[index] = dataIn; + } + |void| addEnd(|T| dataIn) { + if (size < available) + size++; + else + resize(size*2); + data[size-1] = dataIn; + } +}; diff --git a/tests/OperatorOverloadTest.expected_results b/tests/OperatorOverloadTest.expected_results new file mode 100644 index 0000000..78b0a52 --- /dev/null +++ b/tests/OperatorOverloadTest.expected_results @@ -0,0 +1,5 @@ +3 9 +6 18 +Subtraction +3 9 +-97 -61 diff --git a/tests/OperatorOverloadTest.krak b/tests/OperatorOverloadTest.krak new file mode 100644 index 0000000..bcc1d78 --- /dev/null +++ b/tests/OperatorOverloadTest.krak @@ -0,0 +1,64 @@ +import io; + +typedef Vec2 { + |int| x; + |int| y; + + |void| print() { + print(x); + print(" "); + print(y); + } + + |Vec2| add(|Vec2| other) { + |Vec2| toReturn; + toReturn.x = x + other.x; + toReturn.y = y + other.y; + print(); + return toReturn; + } + + |Vec2| subtract(|Vec2| other) { + |Vec2| toReturn; + toReturn.x = x - other.x; + toReturn.y = y - other.y; + print(); + return toReturn; + } + + |Vec2| operator+(|Vec2| other) { + return add(other); + } + +}; + +|Vec2| operator-(|Vec2| lhs, |Vec2| rhs) { + return lhs.subtract(rhs); +} + +|int| main() { + |Vec2| vector1; + |Vec2| vector2; + vector1.x = 3; + vector1.y = 9; + vector2 = vector1; + /* NOTE COMMENT + |Vec2| vector3; + vector3.x = vector1.x + vector2.x; + vector3.y = vector1.y + vector2.y; + vector2.print(); + */ + |Vec2| addition = vector1 + vector2; + print("\n"); + addition.print(); + print("\nSubtraction\n"); + vector2.x = 100; + vector2.y = 70; + |Vec2| subtraction = vector1 - vector2; + print("\n"); + print(subtraction.x); print(" "); print(subtraction.y); + + print("\n"); + + return 0; +} diff --git a/tests/RecursiveTest.expected_results b/tests/RecursiveTest.expected_results new file mode 100644 index 0000000..7ed6ff8 --- /dev/null +++ b/tests/RecursiveTest.expected_results @@ -0,0 +1 @@ +5 diff --git a/tests/RecursiveTest.krak b/tests/RecursiveTest.krak new file mode 100644 index 0000000..03c8b9f --- /dev/null +++ b/tests/RecursiveTest.krak @@ -0,0 +1,14 @@ +import io; + +|int| fibanacci(|int| num) { + if (num < 2) + return 1; + return fibanacci(num-1) + fibanacci(num-2); +} + +|int| main() { + print(fibanacci(4)); + print("\n"); + return 0; +} + 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..0cd8f27 --- /dev/null +++ b/tests/commentFirstTest.krak @@ -0,0 +1,7 @@ +/* Comment first! */ +import io; + +|int| main() { + println(1337); + return 0; +} diff --git a/tests/declarationsTest.expected_results b/tests/declarationsTest.expected_results new file mode 100644 index 0000000..e26fda4 --- /dev/null +++ b/tests/declarationsTest.expected_results @@ -0,0 +1,3 @@ +4 +8 +11 diff --git a/tests/declarationsTest.krak b/tests/declarationsTest.krak new file mode 100644 index 0000000..4e29cc4 --- /dev/null +++ b/tests/declarationsTest.krak @@ -0,0 +1,26 @@ +import io; +import mem; + +typedef ClassWithConstructor { + |int| data; + |ClassWithConstructor*| construct(|int| inData) { + data = inData; + return this; + } + |void| printData() { + println(data); + } +}; + +|int| main() { + |ClassWithConstructor| object.construct(4); + //ClassWithConstructor object; + //object.construct(4); + object.printData(); + |int| a = 8; + println(a); + |ClassWithConstructor*| objPtr = new()->construct(11); + objPtr->printData(); + delete(objPtr); + return 0; +} diff --git a/tests/destructorTest.expected_results b/tests/destructorTest.expected_results new file mode 100644 index 0000000..b96d8a0 --- /dev/null +++ b/tests/destructorTest.expected_results @@ -0,0 +1 @@ +Hello Destructors! diff --git a/tests/destructorTest.krak b/tests/destructorTest.krak new file mode 100644 index 0000000..a63276f --- /dev/null +++ b/tests/destructorTest.krak @@ -0,0 +1,28 @@ +import io; + +typedef DestructorPrint { + |char*| myStr; + |DestructorPrint*| construct(|char*| str) { + myStr = str; + return this; + } + |void| destruct() { + println(myStr); + } +}; + +typedef NoDistruction { + |int| a; + |void| dummyFunc() {} +}; + +|void| indirPrint() { + |DestructorPrint| testObj.construct("Hello Destructors!"); + |NoDistruction| dummy; +} + +|int| main() { + indirPrint(); + return 0; +} + diff --git a/tests/emptyBracesFunction.expected_results b/tests/emptyBracesFunction.expected_results new file mode 100644 index 0000000..1621dff --- /dev/null +++ b/tests/emptyBracesFunction.expected_results @@ -0,0 +1 @@ +It was nothing diff --git a/tests/emptyBracesFunction.krak b/tests/emptyBracesFunction.krak new file mode 100644 index 0000000..d02cbd7 --- /dev/null +++ b/tests/emptyBracesFunction.krak @@ -0,0 +1,9 @@ +import io; + +|void| nothing() {} + +|int| main() { + nothing(); + println("It was nothing"); + return 0; +} diff --git a/tests/functionMultipleTemplateTest.expected_results b/tests/functionMultipleTemplateTest.expected_results new file mode 100644 index 0000000..81f5bd9 --- /dev/null +++ b/tests/functionMultipleTemplateTest.expected_results @@ -0,0 +1 @@ +22.141590 diff --git a/tests/functionMultipleTemplateTest.krak b/tests/functionMultipleTemplateTest.krak new file mode 100644 index 0000000..a30f9d5 --- /dev/null +++ b/tests/functionMultipleTemplateTest.krak @@ -0,0 +1,13 @@ +import io; + +template |void| addAndPrint(|T| a, |J| b) { + print(a+b); +} + +|int| main() { + + addAndPrint(10,12.14159); + print("\n"); + + return 0; +} diff --git a/tests/functionOrderingTest.expected_results b/tests/functionOrderingTest.expected_results new file mode 100644 index 0000000..48082f7 --- /dev/null +++ b/tests/functionOrderingTest.expected_results @@ -0,0 +1 @@ +12 diff --git a/tests/functionOrderingTest.krak b/tests/functionOrderingTest.krak new file mode 100644 index 0000000..c26f5a9 --- /dev/null +++ b/tests/functionOrderingTest.krak @@ -0,0 +1,17 @@ +import io; + +|int| ret1() { + return ret2() / 2; +} + + +|int| main() { + print(ret1()); + print(ret2()); + print("\n"); + return 0; +} + +|int| ret2() { + return 2; +} diff --git a/tests/functionTemplateTest.expected_results b/tests/functionTemplateTest.expected_results new file mode 100644 index 0000000..2bd5a0a --- /dev/null +++ b/tests/functionTemplateTest.expected_results @@ -0,0 +1 @@ +22 diff --git a/tests/functionTemplateTest.krak b/tests/functionTemplateTest.krak new file mode 100644 index 0000000..e6b2597 --- /dev/null +++ b/tests/functionTemplateTest.krak @@ -0,0 +1,13 @@ +import io; + +template |T| addAndPrint(|T| a, |T| b) { + print(a+b); + return a+b; +} + +|int| main() { + addAndPrint(10,12); + print("\n"); + + return 0; +} diff --git a/tests/memTest.expected_results b/tests/memTest.expected_results new file mode 100644 index 0000000..abd8421 --- /dev/null +++ b/tests/memTest.expected_results @@ -0,0 +1,3 @@ +11 +Hello decent memory! Quite a nice feeling + diff --git a/tests/memTest.krak b/tests/memTest.krak new file mode 100644 index 0000000..6ddbac9 --- /dev/null +++ b/tests/memTest.krak @@ -0,0 +1,27 @@ +import mem; +import io; + +typedef AnObject { + |int| a; + |int| b; + |char*| c; + + |void| print() { + print(a+b); + print("\n"); + print(c); + print("\n"); + } +}; + + +|int| main() { + |AnObject*| ptr = new(); + ptr->a = 4; + ptr->b = 7; + ptr->c = "Hello decent memory! Quite a nice feeling\n"; + ptr->print(); + delete(ptr); + + return 0; +} diff --git a/tests/moreComplexObjectTest.expected_results b/tests/moreComplexObjectTest.expected_results new file mode 100644 index 0000000..8b751d2 --- /dev/null +++ b/tests/moreComplexObjectTest.expected_results @@ -0,0 +1,2 @@ +742 +1337 diff --git a/tests/moreComplexObjectTest.krak b/tests/moreComplexObjectTest.krak new file mode 100644 index 0000000..2c06e6b --- /dev/null +++ b/tests/moreComplexObjectTest.krak @@ -0,0 +1,29 @@ +import io; + +typedef firstObject { + |int| objectNum; + |int| other; + |void| print() { + print(other); + } + |void| printInd() { + print(); + } +}; + +typedef Int int; + +|Int| aliasNum; + +|int| main() { + |firstObject| wooObject; + wooObject.objectNum = 7; + print(wooObject.objectNum); + |firstObject*| objPtr = &wooObject; + objPtr->objectNum = 42; + print(objPtr->objectNum); + print("\n"); + objPtr->other = 1337; + objPtr->printInd(); + print("\n"); +} diff --git a/tests/moreObjectTemplateTest.expected_results b/tests/moreObjectTemplateTest.expected_results new file mode 100644 index 0000000..38c003f --- /dev/null +++ b/tests/moreObjectTemplateTest.expected_results @@ -0,0 +1 @@ +45Hello!Hello!Hello! diff --git a/tests/moreObjectTemplateTest.krak b/tests/moreObjectTemplateTest.krak new file mode 100644 index 0000000..6c7ae78 --- /dev/null +++ b/tests/moreObjectTemplateTest.krak @@ -0,0 +1,37 @@ +import io; +import trivial_container; + +typedef RegularObject { + |int| num; + |trivialContainer| innerContainer; + |void| set(|char*| message, |int| number) { + innerContainer.data = message; + num = number; + } + |char*| get() { + return innerContainer.data; + } + |void| print() { + print(num); + innerContainer.print(); + } +}; + +typedef MyIntContainer trivialContainer; +|MyIntContainer| roundabout; +|RegularObject| outsideDec; + +|void| print(|trivialContainer| toPrint) { + print(toPrint.data); +} + +|int| main() { + roundabout.data = 4; + outsideDec.set("Hello!", 5); + roundabout.print(); + outsideDec.print(); + print(outsideDec.get()); + print(outsideDec.innerContainer); + print("\n"); + return 0; +} diff --git a/tests/objectOrderingTest.expected_results b/tests/objectOrderingTest.expected_results new file mode 100644 index 0000000..48082f7 --- /dev/null +++ b/tests/objectOrderingTest.expected_results @@ -0,0 +1 @@ +12 diff --git a/tests/objectOrderingTest.krak b/tests/objectOrderingTest.krak new file mode 100644 index 0000000..4812bb8 --- /dev/null +++ b/tests/objectOrderingTest.krak @@ -0,0 +1,27 @@ +import io; + +typedef objectA { + |int| a; +}; + +typedef BigObject { + |objectA| a; + |objectB| b; + |int| add() { + return a.a + b.b; + } +}; + +typedef objectB { + |int| b; +}; + + +|int| main() { + |BigObject| c; + c.a.a = 4; + c.b.b = 8; + print(c.add()); + print("\n"); + return 0; +} diff --git a/tests/runTests.sh b/tests/runTests.sh new file mode 100755 index 0000000..f86e0bf --- /dev/null +++ b/tests/runTests.sh @@ -0,0 +1,14 @@ +#!/bin/bash + +krakenPath="../build/kraken" +testDir=${1:-"../tests"} +ext=${2:-"krak"} + +fileList="" +for dir in `find ${testDir} -type f -name "*.${ext}"`; do + filename=$(basename ${dir}) + filename="${filename%.*}" + fileList+=\ $testDir\/$filename +done + +${krakenPath} "--test" ${fileList} diff --git a/tests/simpleFunctionTest.expected_results b/tests/simpleFunctionTest.expected_results new file mode 100644 index 0000000..635328e --- /dev/null +++ b/tests/simpleFunctionTest.expected_results @@ -0,0 +1 @@ +1919 diff --git a/tests/simpleFunctionTest.krak b/tests/simpleFunctionTest.krak new file mode 100644 index 0000000..2e45927 --- /dev/null +++ b/tests/simpleFunctionTest.krak @@ -0,0 +1,14 @@ +import io; + +|int| addAndPrintInt(|int| a, |int| b) { + print(a+b); + return a+b; +} + +|int| main() { + + print(addAndPrintInt(7,12)); + print("\n"); + + return 0; +} diff --git a/tests/simpleObjectMultipleTemplateTest.expected_results b/tests/simpleObjectMultipleTemplateTest.expected_results new file mode 100644 index 0000000..2452da9 --- /dev/null +++ b/tests/simpleObjectMultipleTemplateTest.expected_results @@ -0,0 +1,4 @@ +a: 24 +b: Hello World +a: Pi incoming +b: 3.14159 - Fooled you! txt pi. C is being weird with floats. Not a Kraken problem. Ahh Well. diff --git a/tests/simpleObjectMultipleTemplateTest.krak b/tests/simpleObjectMultipleTemplateTest.krak new file mode 100644 index 0000000..f3615e4 --- /dev/null +++ b/tests/simpleObjectMultipleTemplateTest.krak @@ -0,0 +1,30 @@ +import io; + + +typedef template TemplateTest { + |T| a; + |J| b; + |void| print() { + print("a: "); + print(a); + print("\n"); + print("b: "); + print(b); + print("\n"); + } +}; + +|int| main() { + + |TemplateTest| test; + |TemplateTest| test2; + test.a = 24; + test.b = "Hello World"; + test2.a = "Pi incoming"; + test2.b = "3.14159 - Fooled you! txt pi. C is being weird with floats. Not a Kraken problem. Ahh Well."; + + test.print(); + test2.print(); + + return 0; +} diff --git a/tests/simpleObjectTemplateTest.expected_results b/tests/simpleObjectTemplateTest.expected_results new file mode 100644 index 0000000..40928fd --- /dev/null +++ b/tests/simpleObjectTemplateTest.expected_results @@ -0,0 +1,4 @@ +a: 5 +b: 7 +a: 9 +b: Hello Templates! diff --git a/tests/simpleObjectTemplateTest.krak b/tests/simpleObjectTemplateTest.krak new file mode 100644 index 0000000..7aeebc2 --- /dev/null +++ b/tests/simpleObjectTemplateTest.krak @@ -0,0 +1,30 @@ +import io; + + +typedef template TemplateTest { + |int| a; + |T| b; + |void| print() { + print("a: "); + print(a); + print("\n"); + print("b: "); + print(b); + print("\n"); + } +}; + +|int| main() { + + |TemplateTest| test; + |TemplateTest| test2; + test.a = 5; + test.b = 7; + test2.a = 9; + test2.b = "Hello Templates!"; + + test.print(); + test2.print(); + + return 0; +} diff --git a/tests/simpleObjectTest.expected_results b/tests/simpleObjectTest.expected_results new file mode 100644 index 0000000..e1617e8 --- /dev/null +++ b/tests/simpleObjectTest.expected_results @@ -0,0 +1 @@ +57 diff --git a/tests/simpleObjectTest.krak b/tests/simpleObjectTest.krak new file mode 100644 index 0000000..3e8f14f --- /dev/null +++ b/tests/simpleObjectTest.krak @@ -0,0 +1,18 @@ + +import io; + +typedef FirstObject { + |int| objectNum; + |void| PrintSelf(|int| a) { + print(objectNum); + print(a); + } +}; + +|int| main() { + |FirstObject| wooObject; + wooObject.objectNum = 5; + wooObject.PrintSelf(7); + print("\n"); + return 0; +} diff --git a/tests/templateTest.expected_results b/tests/templateTest.expected_results new file mode 100644 index 0000000..15fa1a4 --- /dev/null +++ b/tests/templateTest.expected_results @@ -0,0 +1,8 @@ +a: 5 +b: 7 +1337 +a: 9 +b: Hello Templates! +Woooo nesting! +From another file! Whoh! +1919 diff --git a/tests/templateTest.krak b/tests/templateTest.krak new file mode 100644 index 0000000..8843126 --- /dev/null +++ b/tests/templateTest.krak @@ -0,0 +1,52 @@ +import io; +import trivial_container; + +typedef template TemplateTest { + |int| a; + |T| b; + |trivialContainer| c; + |void| print() { + print("a: "); + print(a); + print("\n"); + print("b: "); + print(b); + print("\n"); + c.print(); + print("\n"); + } +}; + +typedef MyInt int; + +|MyInt| c; + + +template |T| addAndPrint(|T| a, |T| b) { + print(a+b); + return a+b; +} + +|int| main() { + |TemplateTest| test; + |TemplateTest| test2; + test.a = 5; + test.b = 7; + test.c.data = 1337; + test2.a = 9; + test2.b = "Hello Templates!"; + test2.c.data = "Woooo nesting!"; + + test.print(); + test2.print(); + + |trivialContainer| testImport; + testImport.data = "From another file! Whoh!"; + testImport.print(); + print("\n"); + + print(addAndPrint(7,12)); + print("\n"); + + return 0; +} diff --git a/tests/testArrayNotation.expected_results b/tests/testArrayNotation.expected_results new file mode 100644 index 0000000..6e68a0f --- /dev/null +++ b/tests/testArrayNotation.expected_results @@ -0,0 +1 @@ +777 diff --git a/tests/testArrayNotation.krak b/tests/testArrayNotation.krak new file mode 100644 index 0000000..9b04b25 --- /dev/null +++ b/tests/testArrayNotation.krak @@ -0,0 +1,13 @@ +import io; +import mem; + +|int| main() { + |int| b; + |int*| a = &b; + a [ 0 ] = 7; + print(a [ 0 ] ); + print(*a); + print(b); + print("\n"); + return 0; +} diff --git a/tests/traitsTest.expected_results b/tests/traitsTest.expected_results new file mode 100644 index 0000000..603431e --- /dev/null +++ b/tests/traitsTest.expected_results @@ -0,0 +1,9 @@ +No Traits +First Trait +Second Trait +Both Traits + +First Trait +Second Trait +Both Traits +No Traits diff --git a/tests/traitsTest.krak b/tests/traitsTest.krak new file mode 100644 index 0000000..566e5ed --- /dev/null +++ b/tests/traitsTest.krak @@ -0,0 +1,75 @@ +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>(beta); + OneTwoFunc>(gamma); + OneTwoFunc>(delta); + + //We can't pass along our inner part, so let's just make sure that it is the right object. + //epsilon.proveSpecilized(); + + return 0; +} diff --git a/tests/typeExpr.expected_results b/tests/typeExpr.expected_results new file mode 100644 index 0000000..de78180 --- /dev/null +++ b/tests/typeExpr.expected_results @@ -0,0 +1,2 @@ +4 +8 diff --git a/tests/typeExpr.krak b/tests/typeExpr.krak new file mode 100644 index 0000000..e7dcae2 --- /dev/null +++ b/tests/typeExpr.krak @@ -0,0 +1,20 @@ +import io; + +typedef ClassWithConstructor { + |int| data; + |ClassWithConstructor*| construct(|int| inData) { + data = inData; + return this; + } + |void| printData() { + println(data); + } +}; + +|int| main() { + |ClassWithConstructor| object.construct(4); + object.printData(); + |int| a = 8; + println(a); + return 0; +} diff --git a/tests/vectorTest.expected_results b/tests/vectorTest.expected_results new file mode 100644 index 0000000..c7ae395 --- /dev/null +++ b/tests/vectorTest.expected_results @@ -0,0 +1,2 @@ +1337 +Destroyed! diff --git a/tests/vectorTest.krak b/tests/vectorTest.krak new file mode 100644 index 0000000..579fe24 --- /dev/null +++ b/tests/vectorTest.krak @@ -0,0 +1,28 @@ +import io; +import mem; +import vector; + +typedef AbleToBeDestroyed (Destructable) { + |void| destruct() { + println("Destroyed!"); + } +}; + +|int| main() { + |vector| intVec.construct(); + intVec.addEnd(1); + intVec.addEnd(3); + intVec.addEnd(3); + intVec.addEnd(7); + for (|int| i = 0; i < intVec.size; i++;) + print(intVec.at(i)); + + println(); + + |vector*| desVec = new>()->construct(); + |AbleToBeDestroyed| testDestruct; + desVec->addEnd(testDestruct); + delete>(desVec); + + return 0; +} diff --git a/true_triple_quoted_string_regex.txt b/true_triple_quoted_string_regex.txt deleted file mode 100644 index a14076b..0000000 --- a/true_triple_quoted_string_regex.txt +++ /dev/null @@ -1,9 +0,0 @@ -This is the true regex for triple quoted strings, but it segfaults my regex code.... - -triple_quoted_string = "\"\"\"((\"\"(`|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|<|>|\?| )+)|(\"(`|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|<|>|\?| )+))*(`|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|<|>|\?| )*(((`|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|<|>|\?| )+\")|((`|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|<|>|\?| )+\"\")|((`|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|<|>|\?| )+))*\"\"\"" ; \ No newline at end of file