diff --git a/cpp/src/CMakeLists.txt b/cpp/src/CMakeLists.txt index 2f998dd..82c04c7 100644 --- a/cpp/src/CMakeLists.txt +++ b/cpp/src/CMakeLists.txt @@ -1,228 +1,228 @@ cmake_minimum_required(VERSION 2.8.11) project(xreate) cmake_policy(SET CMP0022 NEW) message("MODULES" ${CMAKE_MODULE_PATH}) # LLVM #====================== FIND_PACKAGE (LLVM REQUIRED) set(LLVM_VERSION ${LLVM_VERSION_MAJOR}.${LLVM_VERSION_MINOR}) message(STATUS "Found LLVM ${LLVM_PACKAGE_VERSION}") message("LLVM LIB PATH:" ${LLVM_LIBRARY_DIRS}) message(STATUS "Using LLVMConfig.cmake in: ${LLVM_DIR}") INCLUDE_DIRECTORIES(${LLVM_INCLUDE_DIRS}) message(STATUS "INCLUDE DIR: ${LLVM_INCLUDE_DIRS}") add_definitions(${LLVM_DEFINITIONS}) message("LLVM DEFS: " ${LLVM_DEFINITIONS}) llvm_map_components_to_libnames(LLVM_LIBS core nativecodegen native executionengine mcjit support option) message("LLVM LIBS: " ${LLVM_LIBS}) # CLANG #====================== set(CLANG_LIBS clangCodeGen clangASTMatchers clangQuery clangTooling clangFrontend clangSerialization clangDriver clangParse clangSema clangAnalysis clangAST clangEdit clangLex clangBasic ) # POTASSCO #====================== set(POTASSCO_PATH "/opt/potassco/clingo" CACHE PATH "Path to potassco sources") set(POTASSCO_INCLUDE_PATH ${POTASSCO_PATH}/libgringo ${POTASSCO_PATH}/libclasp ${POTASSCO_PATH}/libclingo ${POTASSCO_PATH}/libprogram_opts ${POTASSCO_PATH}/liblp ) INCLUDE_DIRECTORIES(${POTASSCO_INCLUDE_PATH}) set(LIBCLASP_LIBS clingo clasp gringo program_opts reify lp ) message("CLASP LIBS: " ${LIBCLASP_LIBS}) # OTHER DEPENDENCIES #=========================== set(JEAYESON_INCLUDE_PATH ${CMAKE_HOME_DIRECTORY}/../vendors/jeayeson/include/ ) INCLUDE_DIRECTORIES(${JEAYESON_INCLUDE_PATH}) # COCO #=========================== set(COCO_EXECUTABLE "" CACHE PATH "Path to coco executable") set(COCO_FRAMES_PATH "" CACHE PATH "Path to coco frames") set(COCO_GRAMMAR_PATH ${CMAKE_HOME_DIRECTORY}/../grammar/) set(COCO_SOURCE_FILES_MAIN ${COCO_GRAMMAR_PATH}/main/Parser.cpp ${COCO_GRAMMAR_PATH}/main/Scanner.cpp ) set(COCO_SOURCE_FILES_MODULES ${COCO_GRAMMAR_PATH}/modules/Parser.cpp ${COCO_GRAMMAR_PATH}/modules/Scanner.cpp ) set(COCO_SOURCE_FILES ${COCO_SOURCE_FILES_MODULES} ${COCO_SOURCE_FILES_MAIN}) INCLUDE_DIRECTORIES(${COCO_GRAMMAR_PATH}) add_custom_command(OUTPUT ${COCO_SOURCE_FILES_MAIN} COMMAND ${COCO_GRAMMAR_PATH}/gen-grammar main ${COCO_EXECUTABLE} ${COCO_FRAMES_PATH} WORKING_DIRECTORY ${COCO_GRAMMAR_PATH} MAIN_DEPENDENCY ${COCO_GRAMMAR_PATH}/xreate.ATG ) add_custom_command(OUTPUT ${COCO_SOURCE_FILES_MODULES} COMMAND ${COCO_GRAMMAR_PATH}/gen-grammar modules ${COCO_EXECUTABLE} ${COCO_FRAMES_PATH} WORKING_DIRECTORY ${COCO_GRAMMAR_PATH} MAIN_DEPENDENCY ${COCO_GRAMMAR_PATH}/modules.ATG ) message(STATUS "COCO GRAMMAR BUILD STATUS:" ${COCO_OUTPUT}) # XREATE #====================== set(SOURCE_FILES modules.cpp ast.cpp xreatemanager.cpp misc/xreatemanager-decorators.cpp compilation/pointerarithmetic.cpp compilation/transformations.cpp compilation/transformersaturation.cpp pass/compilepass.cpp pass/dfapass.cpp analysis/dfagraph.cpp pass/versionspass.cpp compilation/targetinterpretation.cpp attachments.cpp ExternLayer.cpp analysis/cfagraph.cpp analysis/aux.cpp compilation/containers.cpp compilation/advanced.cpp clasplayer.cpp compilation/latecontextcompiler2.cpp query/context.cpp llvmlayer.cpp utils.cpp pass/abstractpass.cpp pass/cfapass.cpp pass/adhocpass.cpp contextrule.cpp query/containers.cpp pass/interpretationpass.cpp analysis/DominatorsTreeAnalysisProvider.cpp misc/serialization/expressionserializer.cpp ) set(XREATE_INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/ ) INCLUDE_DIRECTORIES(${XREATE_INCLUDE_DIRS}) set(XREATE_PRIVATE_INCLUDE_DIRS ${XREATE_INCLUDE_DIRS} ${COCO_GRAMMAR_PATH} ${JEAYESON_INCLUDE_PATH} ${LLVM_INCLUDE_DIRS} ${POTASSCO_INCLUDE_PATH} ) -add_library(${PROJECT_NAME} SHARED ${SOURCE_FILES} ${COCO_SOURCE_FILES}) +add_library(${PROJECT_NAME} SHARED ${COCO_SOURCE_FILES} ${SOURCE_FILES}) target_link_libraries(${PROJECT_NAME}) target_include_directories(${PROJECT_NAME} INTERFACE ${XREATE_INCLUDE_DIRS} ${COCO_GRAMMAR_PATH} ${JEAYESON_INCLUDE_PATH} ${LLVM_INCLUDE_DIRS} ${POTASSCO_INCLUDE_PATH} ) get_directory_property(DEFINITIONS_ALL DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} COMPILE_DEFINITIONS) message("definitions all: " ${DEFINITIONS_ALL}) target_compile_definitions(${PROJECT_NAME} INTERFACE ${DEFINITIONS_ALL}) get_directory_property(COMPILATION_OPTIONS_ALL DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} COMPILE_OPTIONS) message("compilations all: " ${COMPILATION_OPTIONS_ALL}) target_compile_options(${PROJECT_NAME} INTERFACE ${COMPILATION_OPTIONS_ALL}) SET_PROPERTY(TARGET ${PROJECT_NAME} PROPERTY INTERFACE_LINK_LIBRARIES ${LIBCLASP_LIBS} ${CLANG_LIBS} ${LLVM_LIBS} tbb boost_system boost_filesystem ) #${CLANG_LIBS} #set (LINK_INTERFACE_LIBRARIES "") # FUNCTION(PREPEND var prefix) # SET(listVar "") # FOREACH(f ${ARGN}) # LIST(APPEND listVar "${prefix}/${f}") # ENDFOREACH(f) # SET(${var} "${listVar}" PARENT_SCOPE) # ENDFUNCTION(PREPEND) #set(COTIRE_UNITY_SOURCE_MAXIMUM_NUMBER_OF_INCLUDES "-j4") #cotire(xreate) # MACRO (ADD_PCH_RULE _header_filename _src_list) # SET(_gch_filename "${_header_filename}.gch") # LIST(APPEND ${_src_list} ${_gch_filename}) # SET (_args ${CMAKE_CXX_FLAGS}) # LIST(APPEND _args -c ${_header_filename} -o ${_gch_filename}) # GET_DIRECTORY_PROPERTY(DIRINC INCLUDE_DIRECTORIES) # foreach (_inc ${DIRINC}) # LIST(APPEND _args "-I" ${_inc}) # endforeach(_inc ${DIRINC}) # SEPARATE_ARGUMENTS(_args) # add_custom_command(OUTPUT ${_gch_filename} # COMMAND rm -f ${_gch_filename} # COMMAND ${CMAKE_CXX_COMPILER} ${CMAKE_CXX_COMPILER_ARG1} ${_args} # DEPENDS ${_header_filename}) # ENDMACRO(ADD_PCH_RULE _header_filename _src_list) # ADD_PCH_RULE (${CMAKE_HOME_DIRECTORY}/src/ast.h SOURCE_FILES) # ADD_PCH_RULE (${CMAKE_HOME_DIRECTORY}/src/llvmlayer.h SOURCE_FILES) # ADD_PCH_RULE (${CMAKE_HOME_DIRECTORY}/src/clasplayer.h SOURCE_FILES) # ADD_PCH_RULE (${CMAKE_HOME_DIRECTORY}/src/pass/abstractpass.h SOURCE_FILES) diff --git a/cpp/src/analysis/DominatorsTreeAnalysisProvider.cpp b/cpp/src/analysis/DominatorsTreeAnalysisProvider.cpp index 9bd280d..99a1a64 100644 --- a/cpp/src/analysis/DominatorsTreeAnalysisProvider.cpp +++ b/cpp/src/analysis/DominatorsTreeAnalysisProvider.cpp @@ -1,233 +1,239 @@ /* * To change this license header, choose License Headers in Project Properties. * To change this template file, choose Tools | Templates * and open the template in the editor. */ /* * File: DominatorsTreeAnalysisProvider.cpp * Author: pgess * * Created on May 13, 2016, 11:39 AM */ #include "analysis/cfagraph.h" #include "analysis/DominatorsTreeAnalysisProvider.h" #include "llvm/ADT/GraphTraits.h" #include "llvm/Support/GenericDomTreeConstruction.h" #include "llvm/Support/GenericDomTree.h" #include #include #include using namespace std; using namespace xreate; using namespace boost; using namespace boost::bimaps; -struct ControlFlowTree; +namespace xreate{ namespace dominators { +struct ControlFlowTree; struct Node { ScopePacked scope; ControlFlowTree* tree; }; /* bool operator !=(const Node& a, const Node& b){ return (a.tree != b.tree) || (a.scope != b.scope); } Node& operator++(Node& a){ ++a.scope; return a; } */ struct ControlFlowTree{ typedef bimap, multiset_of> CHILD_RELATIONS; CHILD_RELATIONS edges; std::vector nodes; Node* entry = nullptr; size_t size; ControlFlowTree(const size_t nodesCount): nodes(nodesCount), size(nodesCount){ } static ControlFlowTree* build(const ClaspLayer* engine){ ControlFlowTree* tree = new ControlFlowTree(engine->getScopesCount()); - xreate::analysis::CFAGraph* graph = engine->dataCFA.get(); + cfa::CFAGraph* graph = engine->dataCFA.get(); for (const auto& edge: graph->__parentScopeRelations){ tree->edges.insert(CHILD_RELATIONS::value_type(edge.second, edge.first)); } for (const auto& edge: graph->__callRelations){ unsigned int calleeFunction = edge.right; ScopePacked caller = edge.left; auto range = graph->__parentFunctionRelations.right.equal_range(calleeFunction); for (auto& i=range.first; i!= range.second; ++i){ tree->edges.insert(CHILD_RELATIONS::value_type(caller, i->second)); } } for (size_t i=0; isize; ++i){ tree->nodes[i]= Node{(unsigned int) i, tree}; } return tree; } std::list getRootFunctions() const{ size_t idMax = size; size_t id =0; std::list results; auto i = edges.right.begin(); while (id < idMax) { if (i!= edges.right.end() && i->first == id){ i = edges.right.upper_bound(i->first); } else { results.push_back(id); } ++id; } return std::move(results); } }; +}} //end of namespace xreate::dominators namespace llvm { + using namespace xreate::dominators; + template <> struct GraphTraits { typedef Node* nodes_iterator; typedef Node NodeType; typedef std::function Transformer; typedef typename boost::transform_iterator ChildIteratorType; static ChildIteratorType child_begin(const nodes_iterator& node) { auto range = node->tree->edges.left.equal_range(node->scope); Transformer x = [node](auto edge){return &node->tree->nodes[edge.second];}; return boost::make_transform_iterator(range.first, x); } static ChildIteratorType child_end(const nodes_iterator& node) { auto range = node->tree->edges.left.equal_range(node->scope); Transformer x = [node](auto edge){return &node->tree->nodes[edge.second];}; return boost::make_transform_iterator(range.second, x); } }; template <> struct GraphTraits> { typedef Node* nodes_iterator; typedef Node NodeType; typedef std::function Transformer; typedef typename boost::transform_iterator ChildIteratorType; static ChildIteratorType child_begin(const nodes_iterator& node) { auto range = node->tree->edges.right.equal_range(node->scope); Transformer x = [node](auto edge){return &node->tree->nodes[edge.second];}; return boost::make_transform_iterator(range.first, x); } static ChildIteratorType child_end(const nodes_iterator& node) { auto range = node->tree->edges.right.equal_range(node->scope); Transformer x = [node](auto edge){return &node->tree->nodes[edge.second];}; return boost::make_transform_iterator(range.second, x); } }; template <> struct GraphTraits: public GraphTraits { static NodeType* getEntryNode(ControlFlowTree* F) { if (F->entry) return F->entry; list&& roots = F->getRootFunctions(); assert(roots.size()==1); return F->entry = &F->nodes[roots.front()]; } static nodes_iterator nodes_begin(ControlFlowTree* F) { return &F->nodes[0]; } static nodes_iterator nodes_end(ControlFlowTree* F) { return &F->nodes[F->size]; } static size_t size(ControlFlowTree* F) { return F->size; } }; } -class xreate::DominatorTree: public llvm::DominatorTreeBase { +namespace xreate{ namespace dominators { +class DominatorTree: public llvm::DominatorTreeBase { public: DominatorsTreeAnalysisProvider::Dominators dominators; DominatorTree(bool isPostDom): llvm::DominatorTreeBase(isPostDom) {} void run(ControlFlowTree& program){ recalculate(program); //extract dominators info for (auto& entry: DomTreeNodes){ if (!entry.getFirst()) continue; dominators.emplace(entry.getFirst()->scope, make_pair(entry.getSecond()->getDFSNumIn(), entry.getSecond()->getDFSNumOut())); } } void print(std::ostringstream& output, const std::string& atom) const { boost::format formatAtom(atom + "(%1%, range(%2%, %3%))."); for (auto entry: dominators){ output << formatAtom % (entry.first) % (entry.second.first) % (entry.second.second) << endl; } } }; void DominatorsTreeAnalysisProvider::run(const ClaspLayer* engine){ boost::scoped_ptr program(ControlFlowTree::build(engine)); treeForwardDominators->run(*program); treePostDominators->run(*program); } void DominatorsTreeAnalysisProvider::print(std::ostringstream& output) const{ treeForwardDominators->print(output, "cfa_forwdom"); treePostDominators->print(output, "cfa_postdom"); } const DominatorsTreeAnalysisProvider::Dominators& DominatorsTreeAnalysisProvider::getForwardDominators() const{ return treeForwardDominators->dominators; } const DominatorsTreeAnalysisProvider::Dominators& DominatorsTreeAnalysisProvider::getPostDominators() const{ return treePostDominators->dominators; } DominatorsTreeAnalysisProvider::DominatorsTreeAnalysisProvider() : treeForwardDominators(new DominatorTree(false)) , treePostDominators(new DominatorTree(true)) {} DominatorsTreeAnalysisProvider::~DominatorsTreeAnalysisProvider() {} +}} //end of namespace xreate::dominators //void //CodeScopesTree::print(){ // typedef llvm::GraphTraits Traits; // for (size_t i=0; i" << (*j)->scope << endl; // } // } //} \ No newline at end of file diff --git a/cpp/src/analysis/DominatorsTreeAnalysisProvider.h b/cpp/src/analysis/DominatorsTreeAnalysisProvider.h index 5574891..c9a274f 100644 --- a/cpp/src/analysis/DominatorsTreeAnalysisProvider.h +++ b/cpp/src/analysis/DominatorsTreeAnalysisProvider.h @@ -1,44 +1,44 @@ /* * To change this license header, choose License Headers in Project Properties. * To change this template file, choose Tools | Templates * and open the template in the editor. */ /* * File: DominatorsTreeAnalysisProvider.h * Author: pgess * * Created on May 13, 2016, 11:39 AM */ #ifndef DOMINATORSTREEANALYSISPROVIDER_H #define DOMINATORSTREEANALYSISPROVIDER_H #include "clasplayer.h" #include -namespace xreate{ +namespace xreate{namespace dominators{ class DominatorTree; class DominatorsTreeAnalysisProvider: public IAnalysisData { public: typedef std::pair DominatedRange; typedef std::map Dominators; DominatorsTreeAnalysisProvider(); virtual ~DominatorsTreeAnalysisProvider(); void run(const ClaspLayer* engine); void print(std::ostringstream& output) const; const Dominators& getForwardDominators() const; const Dominators& getPostDominators() const; private: boost::scoped_ptr treeForwardDominators; boost::scoped_ptr treePostDominators; }; -} +}} //end of namespace xreate::dominators #endif /* DOMINATORSTREEANALYSISPROVIDER_H */ diff --git a/cpp/src/analysis/cfagraph.cpp b/cpp/src/analysis/cfagraph.cpp index be428ed..5a2d7e6 100644 --- a/cpp/src/analysis/cfagraph.cpp +++ b/cpp/src/analysis/cfagraph.cpp @@ -1,166 +1,166 @@ /* * File: CFAGraph.cpp * Author: pgess * * Created on June 27, 2016, 2:09 PM */ #include "analysis/cfagraph.h" #include "analysis/aux.h" -using namespace xreate::analysis; +using namespace xreate::cfa; using namespace std; void CFAGraph::print(std::ostringstream& output) const { const std::string& atomBinding = Config::get("clasp.bindings.function"); const std::string& atomBindingScope = Config::get("clasp.bindings.scope"); //show function tags int counterTags = 0; std::ostringstream bufFunctionNames; boost::format formatFunction("function(%1%)."); boost::format formatBind(atomBinding + "(%1%, %2%)."); for (auto function: this->__nodesFunction.left) { const auto tags = this->__functionTags.equal_range(function.first); if (tags.first == tags.second) { //no tags bufFunctionNames << "; " << function.second ; continue; } output << formatFunction % (function.second) << std::endl; for (const auto& tag_: boost::make_iterator_range(tags)){ const Expression& tag = tag_.second; list tagRaw = xreate::analysis::compile(tag); assert(tagRaw.size() == 1); output << formatBind % (function.second) % (tagRaw.front()) << endl; ++counterTags; } } if (bufFunctionNames.tellp()){ output << formatFunction % (bufFunctionNames.str().substr(2)) << std::endl; } if (counterTags == 0) { output << "%no functtion tags at all" << endl; } //declare scopes boost::format formatScope("scope(0..%1%)."); output << formatScope % (__clasp->getScopesCount() - 1) << std::endl; //show context rules: for (auto rule: this->__contextRules) { output << ContextRule(rule.second).compile(rule.first) << std::endl; }; //show scope tags: counterTags = 0; boost::format formatScopeBind(atomBindingScope + "(%1%, %2%, strong)."); for (auto entry: this->__scopeTags) { ScopePacked scopeId = entry.first; const Expression& tag = entry.second; list tagRaw = xreate::analysis::compile(tag); assert(tagRaw.size() == 1); output << formatScopeBind % scopeId %(tagRaw.front()) << endl; ++counterTags; } if (counterTags == 0) { output << "%scope tags: no tags at all" << endl; } output << endl << "%\t\tStatic analysis: CFA" << endl; //parent connections //TOTEST CFG parent function boost::format formatFunctionParent("cfa_parent(%1%, function(%2%))."); for (const auto &relation: this->__parentFunctionRelations) { const string& function = this->__nodesFunction.left.at(relation.right); output << formatFunctionParent % relation.left % function << endl; } //TOTEST CFG parent scope boost::format formatScopeParent("cfa_parent(%1%, scope(%2%))."); for (const auto &relation: this->__parentScopeRelations) { output << formatScopeParent % relation.first % relation.second << endl; } //call connections boost::format formatCall("cfa_call(%1%, %2%)."); for (const auto &relation: this->__callRelations) { const ScopePacked scopeFrom = relation.left; const string& functionTo = this->__nodesFunction.left.at(relation.right); output << formatCall % (scopeFrom) % (functionTo) << endl; } //function specializations descrtiption //SECTIONTAG late-context cfa_function_specializations boost::format formatSpecializations("cfa_function_specializations(%1%, %2%)."); const list& functions = __clasp->ast->getAllFunctions(); for (auto f: functions){ if (f->guardContext.isValid()){ list guardRaw = xreate::analysis::compile(f->guardContext); assert(guardRaw.size() == 1); output << formatSpecializations % (f->getName()) % (guardRaw.front()) << endl; } } } void CFAGraph::addFunctionAnnotations(const std::string& function, const std::map& tags) { unsigned int fid = registerNodeFunction(function); for (auto& tag: tags){ __functionTags.emplace(fid, tag.second); } } void CFAGraph::addScopeAnnotations(const ScopePacked& scope, const std::vector& tags){ for (Expression tag: tags){ __scopeTags.emplace(scope, tag); } } void CFAGraph::addContextRules(const ScopePacked& scope, const std::vector& rules){ for (Expression rule: rules){ __contextRules.emplace(scope, rule); } } void CFAGraph::addCallConnection(const ScopePacked& scopeFrom, const std::string& functionTo) { unsigned int idFuncTo = registerNodeFunction(functionTo); __callRelations.insert(CALL_RELATIONS::value_type(scopeFrom, idFuncTo)); } void CFAGraph::addParentConnection(const ScopePacked& scope, const std::string& functionParent){ __parentFunctionRelations.insert(PARENT_FUNCTION_RELATIONS::value_type(scope, registerNodeFunction(functionParent))); } void CFAGraph::addParentConnection(const ScopePacked& scope, const ScopePacked& scopeParent){ __parentScopeRelations.emplace(scope, scopeParent); } unsigned int CFAGraph::registerNodeFunction(const std::string& fname){ auto pos = __nodesFunction.left.insert(make_pair(__nodesFunction.size(), fname)); return pos.first->first; } diff --git a/cpp/src/analysis/cfagraph.h b/cpp/src/analysis/cfagraph.h index a60499a..7372446 100644 --- a/cpp/src/analysis/cfagraph.h +++ b/cpp/src/analysis/cfagraph.h @@ -1,56 +1,56 @@ /* * File: CFAGraph.h * Author: pgess * * Created on June 27, 2016, 2:09 PM */ #ifndef CFAGRAPH_H #define CFAGRAPH_H #include "clasplayer.h" -namespace xreate {namespace analysis { +namespace xreate {namespace cfa { class CFAGraph: public IAnalysisData { public: typedef boost::bimap> PARENT_FUNCTION_RELATIONS; PARENT_FUNCTION_RELATIONS __parentFunctionRelations; std::map __parentScopeRelations; typedef boost::bimap< boost::bimaps::multiset_of, boost::bimaps::multiset_of, boost::bimaps::set_of_relation<> > CALL_RELATIONS; CALL_RELATIONS __callRelations; boost::bimap __nodesFunction; std::multimap __functionTags; std::multimap __scopeTags; std::multimap __contextRules; void print(std::ostringstream& output) const; CFAGraph(ClaspLayer* engine): __clasp(engine){} void addFunctionAnnotations(const std::string& function, const std::map& tags); void addScopeAnnotations(const ScopePacked& scope, const std::vector&tags); void addContextRules(const ScopePacked& scope, const std::vector&rules); void addCallConnection(const ScopePacked& scopeFrom, const std::string& functionTo); void addParentConnection(const ScopePacked& scope, const std::string& functionParent); void addParentConnection(const ScopePacked& scope, const ScopePacked& scopeParent); // void addScopeRetIdentifier(const ScopePacked& scope, const SymbolPacked& identifier); private: ClaspLayer* __clasp; unsigned int registerNodeFunction(const std::string& fname); }; -}} +}} //end of namespace xreate::cfa #endif /* CFAGRAPH_H */ diff --git a/cpp/src/analysis/dfagraph.cpp b/cpp/src/analysis/dfagraph.cpp index b1f52dc..46c448c 100644 --- a/cpp/src/analysis/dfagraph.cpp +++ b/cpp/src/analysis/dfagraph.cpp @@ -1,250 +1,245 @@ #include "analysis/dfagraph.h" #include "analysis/aux.h" #include -using namespace xreate; -using namespace xreate::analysis; using namespace std; - -namespace xreate { - namespace analysis { +namespace xreate { namespace dfa { void DFAGraph::print(std::ostringstream& output) const { std::set symbols; output << endl << "%\t\tStatic analysis: DFA" << endl; std::vector>::const_iterator i1; std::vector::const_iterator i2; boost::format formatDfaConnection("dfa_connection(%1%, %2%, %3%)."); for (i1 = this->__edges.begin(), i2 = this->__data.begin(); i1 != this->__edges.end(); ++i1, ++i2) { string edgeName; switch (*i2) { case DFGConnection::WEAK: edgeName = "weak"; break; case DFGConnection::STRONG: edgeName = "strong"; break; case DFGConnection::PROTOTYPE: edgeName = "proto"; break; } output << formatDfaConnection - % formatSymbol(i1->first) - % formatSymbol(i1->second) + % analysis::formatSymbol(i1->first) + % analysis::formatSymbol(i1->second) % edgeName << " %" << this->__clasp->getHintForPackedSymbol(i1->first) << " - " << this->__clasp->getHintForPackedSymbol(i1->second) << endl; symbols.insert(i1->first); symbols.insert(i1->second); } boost::format formatDfaDependency("dfa_dependency(%1%, %2%)."); for (auto i = this->__dependencies.begin(); i != this->__dependencies.end(); ++i) { output << formatDfaDependency - % formatSymbol(i->first) - % formatSymbol(i->second) + % analysis::formatSymbol(i->first) + % analysis::formatSymbol(i->second) << " %" << this->__clasp->getHintForPackedSymbol(i->first) << " - " << this->__clasp->getHintForPackedSymbol(i->second) << endl; } boost::format formatBind("bind(%1%, %2%)."); for (const pair& tag : this->__tags) { for (string variant : xreate::analysis::compile(tag.second)) { output << formatBind - % formatSymbol(tag.first) + % analysis::formatSymbol(tag.first) % (variant) << "%" << this->__clasp->getHintForPackedSymbol(tag.first) << endl; } symbols.insert(tag.first); } for (const SymbolPacked& s : symbols) { - output << "v(" << formatSymbol(s) << ")." + output << "v(" << analysis::formatSymbol(s) << ")." << " %" << this->__clasp->getHintForPackedSymbol(s) << endl; } } class VisitorAddTag : public boost::static_visitor<> { public: void operator()(const SymbolPacked& symbol) { __graph->__tags.emplace(symbol, move(__tag)); } void operator()(SymbolAnonymous& symbol) { symbol.tags.push_back(move(__tag)); } void operator()(const SymbolInvalid& symbol) { assert(false && "Undefined behaviour"); } VisitorAddTag(DFAGraph * const dfagraph, Expression&& tag) : __graph(dfagraph), __tag(tag) { } private: DFAGraph * const __graph; Expression __tag; }; class VisitorAddLink : public boost::static_visitor<> { public: void operator()(const SymbolPacked& nodeFrom) { if (!__graph->isConnected(__nodeTo, nodeFrom)) { __graph->__edges.emplace_back(__nodeTo, nodeFrom); __graph->__data.push_back(__link); DFAGraph::EdgeId eid = __graph->__edges.size() - 1; __graph->__outEdges.emplace(nodeFrom, eid); } } void operator()(const SymbolAnonymous& symbolFrom) { switch (__link) { case DFGConnection::WEAK: { //virtual symbol to hold transient annotations SymbolPacked symbPivot = __graph->createAnonymousSymbol(symbolFrom.scope); __graph->addConnection(symbPivot, symbolFrom, DFGConnection::STRONG); __graph->addConnection(__nodeTo, symbPivot, DFGConnection::WEAK); break; } case DFGConnection::STRONG: { for (const Expression& tag : symbolFrom.tags) { __graph->__tags.emplace(__nodeTo, tag); } break; } default: assert(false && "Undefined behavior"); } } void operator()(const SymbolInvalid&) { if (__link == DFGConnection::STRONG) return; if (__link == DFGConnection::WEAK) return; assert(false && "Undefined behavior"); } VisitorAddLink(DFAGraph * const dfagraph, const SymbolPacked& nodeTo, DFGConnection link) : __graph(dfagraph), __nodeTo(nodeTo), __link(link) { } private: DFAGraph * const __graph; SymbolPacked __nodeTo; DFGConnection __link; }; class VisitorGetDependencyConnection : public boost::static_visitor> { public: list operator()(const SymbolPacked & nodeFrom) { return { nodeFrom }; } list operator()(const SymbolAnonymous & nodeFrom) { return nodeFrom.dependencies; } list operator()(const SymbolInvalid&) { assert(false && "Undefined behavior"); } VisitorGetDependencyConnection(DFAGraph * const g) : graph(g) { } DFAGraph * const graph; }; class VisitorSetDependencyConnection : public boost::static_visitor<> { public: void operator()(SymbolPacked& nodeTo) { VisitorGetDependencyConnection visitorGetDepenencies(graph); auto deps = boost::apply_visitor(visitorGetDepenencies, nodeFrom); for (const SymbolPacked& dep : deps) { graph->__dependencies.emplace(nodeTo, dep); } } void operator()(SymbolAnonymous& nodeTo) { VisitorGetDependencyConnection visitorGetDepenencies(graph); auto deps = boost::apply_visitor(visitorGetDepenencies, nodeFrom); for (const SymbolPacked& dep : deps) { nodeTo.dependencies.push_back(dep); } } void operator()(SymbolInvalid&) { assert(false && "Undefined behavior"); } VisitorSetDependencyConnection(DFAGraph * const g, SymbolNode s) : graph(g), nodeFrom(s) { } DFAGraph * const graph; SymbolNode nodeFrom; }; bool DFAGraph::isConnected(const SymbolPacked& identifierTo, const SymbolPacked& identifierFrom) { auto range = __outEdges.equal_range(identifierFrom); for (std::multimap::iterator edge = range.first; edge != range.second; ++edge) { if (__edges[edge->second].second == identifierTo) return true; } return false; } void DFAGraph::addConnection(const SymbolPacked& nodeTo, const SymbolNode& nodeFrom, DFGConnection link) { VisitorAddLink visitor(this, nodeTo, link); boost::apply_visitor(visitor, nodeFrom); } void DFAGraph::addDependencyConnection(SymbolNode& identifierTo, SymbolNode& identifierFrom) { VisitorSetDependencyConnection visitor(this, identifierFrom); boost::apply_visitor(visitor, identifierTo); } void DFAGraph::addAnnotation(SymbolNode& node, Expression&& tag) { VisitorAddTag visitor(this, move(tag)); boost::apply_visitor(visitor, node); } SymbolPacked DFAGraph::createAnonymousSymbol(const ScopePacked& scope) { return SymbolPacked(ScopedSymbol{__countAnonymousSymbols++, 0}, scope, true); } - } -} \ No newline at end of file +}} //end of namespace xreate::dfa \ No newline at end of file diff --git a/cpp/src/analysis/dfagraph.h b/cpp/src/analysis/dfagraph.h index 7962c77..5d6e513 100644 --- a/cpp/src/analysis/dfagraph.h +++ b/cpp/src/analysis/dfagraph.h @@ -1,60 +1,60 @@ /* * File: dfa.h * Author: pgess * * Created on June 27, 2016, 1:50 PM */ #ifndef DFA_H #define DFA_H #include "clasplayer.h" -namespace xreate {namespace analysis { +namespace xreate {namespace dfa { struct SymbolAnonymous { SymbolAnonymous(unsigned int symbolId): id(symbolId){} unsigned int id; std::list tags; ScopePacked scope; std::list dependencies; }; struct SymbolInvalid { }; typedef boost::variant SymbolNode; class DFAGraph: public IAnalysisData{ friend class VisitorAddTag; friend class VisitorAddLink; friend class VisitorGetDependencyConnection; friend class VisitorSetDependencyConnection; public: DFAGraph(ClaspLayer* engine): __clasp(engine){} SymbolPacked createAnonymousSymbol(const ScopePacked& scope); void addAnnotation(SymbolNode& identifier, Expression&& tag); void addConnection(const SymbolPacked& identifierTo, const SymbolNode& identifierFrom, DFGConnection link); void addDependencyConnection(SymbolNode& identifierTo, SymbolNode& identifierFrom); bool isConnected(const SymbolPacked& identifierTo, const SymbolPacked& identifierFrom); void print(std::ostringstream& output) const; private: typedef unsigned int EdgeId; std::vector> __edges; std::multimap __outEdges; std::vector __data; std::multimap __tags; std::multimap __dependencies; unsigned int __countAnonymousSymbols=0; ClaspLayer* __clasp; }; -}} +}} // end of namespace xreate::dfa #endif /* DFA_H */ diff --git a/cpp/src/ast.cpp b/cpp/src/ast.cpp index f50b3d3..2a890b2 100644 --- a/cpp/src/ast.cpp +++ b/cpp/src/ast.cpp @@ -1,925 +1,934 @@ #include "ast.h" #include "ExternLayer.h" #include #include namespace std{ - std::size_t hash::operator()(xreate::ScopedSymbol const& s) const {return s.id ^ (s.version << 2);} bool equal_to::operator()(const xreate::ScopedSymbol& __x, const xreate::ScopedSymbol& __y) const { return __x.id == __y.id && __x.version == __y.version; } + + size_t + hash::operator()(xreate::Symbol const& s) const{ + return hash()(s.identifier) ^ ((long int) s.scope << 1); + } + + bool + equal_to::operator()(const xreate::Symbol& __x, const xreate::Symbol& __y) const{ + return __x == __y; + }; } using namespace std; namespace xreate { Atom::Atom(const std::wstring& value) { __value = wstring_to_utf8(value); } Atom::Atom(std::string && name) : __value(name) {} const std::string& Atom::get() const { return __value; } Atom::Atom(wchar_t* value) { //DEBT reconsider number literal recognition __value = wcstol(value, 0, 10); } Atom::Atom(int value) : __value(value) { } double Atom::get()const { return __value; } Atom::Atom(const std::wstring& value) { assert(value.size() >=2); __value = wstring_to_utf8(value.substr(1, value.size() -2)); } const std::string& Atom::get() const { return __value; } class ExpressionHints { public: static bool isStringValueValid(const Expression& e) { switch (e.__state) { case Expression::INVALID: assert(false); case Expression::IDENT: case Expression::STRING: return true; case Expression::NUMBER: case Expression::BINDING: case Expression::VARIANT: return false; case Expression::COMPOUND: { switch (e.op) { case Operator::CALL: return true; default: return false; } } } return false; } static bool isDoubleValueValid(const Expression& e) { switch (e.__state) { case Expression::NUMBER: case Expression::VARIANT: return true; case Expression::INVALID: assert(false); case Expression::IDENT: case Expression::STRING: case Expression::COMPOUND: case Expression::BINDING: return false; } return false; } }; class TypesResolver { private: const AST* ast; std::map scope; std::map signatures; ExpandedType expandType(const TypeAnnotation &t, const std::vector &args = std::vector()) { return TypesResolver(ast, scope, signatures)(t, args); } std::vector expandOperands(const std::vector& operands) { std::vector pack; pack.reserve(operands.size()); std::transform(operands.begin(), operands.end(), std::inserter(pack, pack.end()), [this](const TypeAnnotation & t) { return expandType(t); }); return pack; } public: TypesResolver(const AST* root, const std::map& scopeOuter = std::map(), std::map signaturesOuter = std::map()) : ast(root), scope(scopeOuter), signatures(signaturesOuter) { } ExpandedType operator()(const TypeAnnotation &t, const std::vector &args = std::vector()) { //assert(args.size() == t.bindings.size()); // invalid number of arguments for (size_t i = 0; i < args.size(); ++i) { scope[t.bindings.at(i)] = args.at(i); } switch (t.__operator) { case TypeOperator::ARRAY: { assert(t.__operands.size() == 1); Expanded elTy = expandType(t.__operands.at(0)); return ExpandedType(TypeAnnotation(tag_array, elTy, 0)); } case TypeOperator::STRUCT: { assert(t.__operands.size()); std::vector&& pack = expandOperands(t.__operands); auto tnew = TypeAnnotation(TypeOperator::STRUCT, move(pack)); tnew.fields = t.fields; return ExpandedType(move(tnew)); }; case TypeOperator::CALL: { std::string alias = t.__valueCustom; //find in local scope: TypeAnnotation ty; if (scope.count(alias)) { ty = scope.at(alias); } else if (ast->__indexTypeAliases.count(alias)) { ty = ast->__indexTypeAliases.at(alias); } else { assert(false && "Undefined or external type"); } std::vector&& operands = expandOperands(t.__operands); TypeAnnotation signature(TypeOperator::CALL, move(operands)); signature.__valueCustom = alias; if (signatures.count(signature)) { auto link = TypeAnnotation(TypeOperator::LINK,{}); link.conjuctionId = signatures.at(signature); return ExpandedType(move(link)); } int cid = signatures.size(); signatures[signature] = cid; TypeAnnotation tyResult = expandType(ty, operands); tyResult.conjuctionId = cid; return ExpandedType(move(tyResult)); }; case TypeOperator::CUSTOM: { std::string alias = t.__valueCustom; /* if (signatures.count(alias)) { return ExpandedType(TypeAnnotation(TypeOperator::LINK, {t})); } signatures[alias].emplace(t); */ //find in local scope: if (scope.count(alias)) { return expandType(scope.at(alias)); } // find in general scope: if (ast->__indexTypeAliases.count(alias)) { return expandType(ast->__indexTypeAliases.at(t.__valueCustom)); } //if type is unknown keep it as is. return ExpandedType(TypeAnnotation(t)); }; case TypeOperator::ACCESS: { std::string alias = t.__valueCustom; ExpandedType tyAlias = ExpandedType(TypeAnnotation()); //find in local scope: if (scope.count(alias)) { tyAlias = expandType(scope.at(alias)); //find in global scope: } else if ((ast->__indexTypeAliases.count(alias))) { tyAlias = expandType(ast->__indexTypeAliases.at(alias)); } else { assert(false && "Undefined or external type"); } assert(tyAlias->__operator == TypeOperator::STRUCT); for (const string& field : t.fields) { auto fieldIt = std::find(tyAlias->fields.begin(), tyAlias->fields.end(), field); assert(fieldIt != tyAlias->fields.end() && "unknown field"); int fieldId = fieldIt - tyAlias->fields.begin(); tyAlias = expandType(tyAlias->__operands.at(fieldId)); } return tyAlias; } case TypeOperator::TUPLE: { assert(t.__operands.size()); std::vector pack; pack.reserve(t.__operands.size()); std::transform(t.__operands.begin(), t.__operands.end(), std::inserter(pack, pack.end()), [this](const TypeAnnotation & t) { return expandType(t); }); return ExpandedType(TypeAnnotation(TypeOperator::TUPLE, move(pack))); } case TypeOperator::VARIANT: { return ExpandedType(TypeAnnotation(t)); } case TypeOperator::NONE: { return ExpandedType(TypeAnnotation(t)); } default: assert(false); } assert(false); return ExpandedType(TypeAnnotation()); } }; TypeAnnotation::TypeAnnotation() : __operator(TypeOperator::NONE), __value(TypePrimitive::Invalid) {} TypeAnnotation::TypeAnnotation(TypePrimitive typ) : __value(typ) { } TypeAnnotation::TypeAnnotation(TypeOperator op, std::initializer_list operands) : __operator(op), __operands(operands) { } TypeAnnotation::TypeAnnotation(TypeOperator op, std::vector&& operands) : __operator(op), __operands(operands) { } TypeAnnotation::TypeAnnotation(llvm_array_tag, TypeAnnotation typ, int size) : TypeAnnotation(TypeOperator::ARRAY,{typ}) { __size = size; } bool TypeAnnotation::isValid() const{ return !(__value == TypePrimitive::Invalid && __operator == TypeOperator::NONE); } bool TypeAnnotation::operator<(const TypeAnnotation& t) const { if (__operator != t.__operator) return __operator < t.__operator; if (__operator == TypeOperator::NONE) return __value < t.__value; if (__operator == TypeOperator::CALL || __operator == TypeOperator::CUSTOM || __operator == TypeOperator::ACCESS) { if (__valueCustom != t.__valueCustom) return __valueCustom < t.__valueCustom; } return __operands < t.__operands; } /* TypeAnnotation (struct_tag, std::initializer_list) {} */ void TypeAnnotation::addBindings(std::vector>&& params) { bindings.reserve(bindings.size() + params.size()); std::transform(params.begin(), params.end(), std::inserter(bindings, bindings.end()), [](const Atom& ident) { return ident.get(); }); } void TypeAnnotation::addFields(std::vector>&& listFields) { fields.reserve(fields.size() + listFields.size()); std::transform(listFields.begin(), listFields.end(), std::inserter(fields, fields.end()), [](const Atom& ident) { return ident.get(); }); } unsigned int Expression::nextVacantId = 0; Expression::Expression(const Atom& number) : Expression() { __state=NUMBER; op=Operator::NONE; __valueD=number.get(); } Expression::Expression(const Atom& a) : Expression(){ __state=STRING; op=Operator::NONE; __valueS=a.get(); } Expression::Expression(const Atom &ident) : Expression() { __state=IDENT; op=Operator::NONE; __valueS=ident.get(); } Expression::Expression(const Operator &oprt, std::initializer_list params) : Expression() { __state=COMPOUND; op=oprt; if (op == Operator::CALL) { assert(params.size() > 0); Expression arg = *params.begin(); assert(arg.__state == Expression::IDENT); __valueS = std::move(arg.__valueS); operands.insert(operands.end(), params.begin() + 1, params.end()); return; } operands.insert(operands.end(), params.begin(), params.end()); } void Expression::setOp(Operator oprt) { op = oprt; switch (op) { case Operator::NONE: __state = INVALID; break; default: __state = COMPOUND; break; } } void Expression::addArg(Expression &&arg) { operands.push_back(arg); } void Expression::addTags(const std::list tags) const{ std::transform(tags.begin(), tags.end(), std::inserter(this->tags, this->tags.end()), [](const Expression& tag){ return make_pair(tag.getValueString(), tag); }); } void Expression::addBindings(std::initializer_list> params) { addBindings(params.begin(), params.end()); } void Expression::bindType(TypeAnnotation t) { type = move(t); } void Expression::addBlock(ManagedScpPtr scope) { blocks.push_back(scope.operator->()); } const std::vector& Expression::getOperands() const { return operands; } double Expression::getValueDouble() const { return __valueD; } const std::string& Expression::getValueString() const { return __valueS; } void Expression::setValue(const Atom&& v) { __valueS = v.get(); } void Expression::setValueDouble(double value) { __valueD = value; } bool Expression::isValid() const { return (__state != INVALID); } bool Expression::isDefined() const { return (__state != BINDING); } Expression::Expression() : __state(INVALID), op(Operator::NONE), id(nextVacantId++) { } namespace details { namespace incomplete { AST::AST() { Attachments::init(); Attachments::init(); } void AST::addInterfaceData(const ASTInterface& interface, Expression&& data) { __interfacesData.emplace(interface, move(data)); } void AST::addDFAData(Expression &&data) { __dfadata.push_back(data); } void AST::addExternData(ExternData &&data) { __externdata.insert(__externdata.end(), data.entries.begin(), data.entries.end()); } void AST::add(Function* f) { __functions.push_back(f); __indexFunctions.emplace(f->getName(), __functions.size() - 1); } void AST::add(MetaRuleAbstract *r) { __rules.push_back(r); } void AST::add(TypeAnnotation t, Atom alias) { if (t.__operator == TypeOperator::VARIANT) { for (int i = 0, size = t.fields.size(); i < size; ++i) { __dictVariants.emplace(t.fields[i], make_pair(t, i)); } } __indexTypeAliases.emplace(alias.get(), move(t)); } ManagedScpPtr AST::add(CodeScope* scope) { this->__scopes.push_back(scope); return ManagedScpPtr(this->__scopes.size() - 1, &this->__scopes); } std::string AST::getModuleName() { const std::string name = "moduleTest"; return name; } ManagedPtr AST::findFunction(const std::string& name) { int count = __indexFunctions.count(name); if (!count) { return ManagedFnPtr::Invalid(); } assert(count == 1); auto range = __indexFunctions.equal_range(name); return ManagedPtr(range.first->second, &this->__functions); } std::list AST::getAllFunctions() const { const size_t size = __functions.size(); std::list result; for (size_t i = 0; i < size; ++i) { result.push_back(ManagedFnPtr(i, &this->__functions)); } return result; } //TASK select default specializations std::list AST::getFunctionVariants(const std::string& name) const { auto functions = __indexFunctions.equal_range(name); std::list result; std::transform(functions.first, functions.second, inserter(result, result.end()), [this](auto f) { return ManagedFnPtr(f.second, &this->__functions); }); return result; } template<> ManagedPtr AST::begin() { return ManagedPtr(0, &this->__functions); } template<> ManagedPtr AST::begin() { return ManagedPtr(0, &this->__scopes); } template<> ManagedPtr AST::begin() { return ManagedPtr(0, &this->__rules); } bool AST::recognizeVariantIdentifier(Expression& identifier) { assert(identifier.__state == Expression::IDENT); std::string variant = identifier.getValueString(); if (!__dictVariants.count(variant)) { return false; } auto record = __dictVariants.at(variant); const TypeAnnotation& typ = record.first; identifier.__state = Expression::VARIANT; identifier.setValueDouble(record.second); identifier.type = typ; return true; } void AST::postponeIdentifier(CodeScope* scope, const Expression& id) { bucketUnrecognizedIdentifiers.emplace(scope, id); } void AST::recognizePostponedIdentifiers() { for(const auto& identifier: bucketUnrecognizedIdentifiers){ if (!identifier.first->recognizeIdentifier(identifier.second)){ //exception: Ident not found std::cout << "Unknown symbol: "<< identifier.second.getValueString() << std::endl; assert(false && "Symbol not found"); } } } xreate::AST* AST::finalize() { //all finalization steps: recognizePostponedIdentifiers(); return reinterpret_cast(this); } }} //namespace details::incomplete Expanded AST::findType(const std::string& name) { // find in general scope: if (__indexTypeAliases.count(name)) return expandType(__indexTypeAliases.at(name)); //if type is unknown keep it as is. TypeAnnotation t(TypeOperator::CUSTOM,{}); t.__valueCustom = name; return ExpandedType(move(t)); } Expanded AST::expandType(const TypeAnnotation &t) const { return TypesResolver(this)(t); } Function::Function(const Atom& name) : __entry(new CodeScope(0)) { __name = name.get(); } void Function::addTag(Expression&& tag, const TagModifier mod) { string name = tag.getValueString(); __tags.emplace(move(name), move(tag)); } const std::map& Function::getTags() const { return __tags; } CodeScope* Function::getEntryScope() const { return __entry; } void Function::addBinding(Atom && name, Expression&& argument) { __entry->addBinding(move(name), move(argument)); } const std::string& Function::getName() const { return __name; } ScopedSymbol CodeScope::registerIdentifier(const Expression& identifier) { VariableVersion version = Attachments::get(identifier, VERSION_NONE); auto result = __identifiers.emplace(identifier.getValueString(), __vCounter); if (result.second){ ++__vCounter; return {__vCounter-1, version}; } return {result.first->second, version}; } bool CodeScope::recognizeIdentifier(const Expression& identifier) const{ VariableVersion version = Attachments::get(identifier, VERSION_NONE); const std::string& name = identifier.getValueString(); //search identifier in the current block if (__identifiers.count(name)){ VNameId id = __identifiers.at(name); Symbol s; s.identifier = ScopedSymbol{id, version}; s.scope = const_cast(this); Attachments::put(identifier, s); return true; } //search in the parent scope if (__parent) { return __parent->recognizeIdentifier(identifier); } return false; } ScopedSymbol CodeScope::getSymbol(const std::string& alias){ assert(__identifiers.count(alias)); VNameId id = __identifiers.at(alias); return {id, VERSION_NONE}; } void CodeScope::addBinding(Expression&& var, Expression&& argument) { argument.__state = Expression::BINDING; __bindings.push_back(var.getValueString()); ScopedSymbol binding = registerIdentifier(var); __declarations[binding] = move(argument); } void CodeScope::addDeclaration(Expression&& var, Expression&& body) { ScopedSymbol s = registerIdentifier(var); __declarations[s] = move(body); } CodeScope::CodeScope(CodeScope* parent) : __parent(parent) { } CodeScope::~CodeScope() { } void CodeScope::setBody(const Expression &body) { __declarations[ScopedSymbol::RetSymbol] = body; } Expression& CodeScope::getBody() { return __declarations[ScopedSymbol::RetSymbol]; } const Expression& CodeScope::getDeclaration(const Symbol& symbol) { CodeScope* self = symbol.scope; return self->getDeclaration(symbol.identifier); } const Expression& CodeScope::getDeclaration(const ScopedSymbol& symbol){ assert(__declarations.count(symbol) && "Symbol's declaration not found"); return __declarations.at(symbol); } void RuleArguments::add(const Atom &arg, DomainAnnotation typ) { emplace_back(arg.get(), typ); } void RuleGuards::add(Expression&& e) { push_back(e); } MetaRuleAbstract:: MetaRuleAbstract(RuleArguments&& args, RuleGuards&& guards) : __args(std::move(args)), __guards(std::move(guards)) { } MetaRuleAbstract::~MetaRuleAbstract() { } RuleWarning:: RuleWarning(RuleArguments&& args, RuleGuards&& guards, Expression&& condition, Atom&& message) : MetaRuleAbstract(std::move(args), std::move(guards)), __message(message.get()), __condition(condition) { } RuleWarning::~RuleWarning() { } void RuleWarning::compile(ClaspLayer& layer) { //TODO restore addRuleWarning //layer.addRuleWarning(*this); } bool operator<(const ScopedSymbol& s1, const ScopedSymbol& s2) { return (s1.id < s2.id) || (s1.id==s2.id && s1.version < s2.version); } bool operator==(const ScopedSymbol& s1, const ScopedSymbol& s2) { return (s1.id == s2.id) && (s1.version == s2.version); } bool operator<(const Symbol& s1, const Symbol& s2) { return (s1.scope < s2.scope) || (s1.scope == s2.scope && s1.identifier < s2.identifier); } bool operator==(const Symbol& s1, const Symbol& s2) { return (s1.scope == s2.scope) && (s1.identifier == s2.identifier); } bool operator<(const Expression&a, const Expression&b) { if (a.__state != b.__state) return a.__state < b.__state; assert(a.__state != Expression::INVALID); switch (a.__state) { case Expression::IDENT: case Expression::STRING: case Expression::VARIANT: return a.getValueString() < b.getValueString(); case Expression::NUMBER: return a.getValueDouble() < b.getValueDouble(); case Expression::COMPOUND: { assert(a.blocks.size() == 0); assert(b.blocks.size() == 0); if (a.op != b.op){ return a.op < b.op; } bool flagAValid = ExpressionHints::isStringValueValid(a); bool flagBValid = ExpressionHints::isStringValueValid(b); if (flagAValid != flagBValid) { return flagAValid < flagBValid; } if (flagAValid){ if (a.getValueString() != b.getValueString()) { return a.getValueString() < b.getValueString(); } } flagAValid = ExpressionHints::isDoubleValueValid(a); flagBValid = ExpressionHints::isDoubleValueValid(b); if (flagAValid != flagBValid) { return flagAValid < flagBValid; } if (flagAValid){ if (a.getValueDouble() != b.getValueDouble()) { return a.getValueDouble() < b.getValueDouble(); } } if (a.operands.size() != b.operands.size()) { return (a.operands.size() < b.operands.size()); } for (size_t i = 0; i < a.operands.size(); ++i) { bool result = a.operands[i] < b.operands[i]; if (result) return true; } return false; } case Expression::BINDING: case Expression::INVALID: assert(false); } return false; } bool Expression::operator==(const Expression& other) const { if (this->__state != other.__state) return false; if (ExpressionHints::isStringValueValid(*this)) { if (this->__valueS != other.__valueS) return false; } if (ExpressionHints::isDoubleValueValid(*this)) { if (this->__valueD != other.__valueD) return false; } if (this->__state != Expression::COMPOUND) { return true; } if (this->op != other.op) { return false; } if (this->operands.size() != other.operands.size()) { return false; } for (size_t i = 0; ioperands.size(); ++i) { if (!(this->operands[i] == other.operands[i])) return false; } assert(!this->blocks.size()); assert(!other.blocks.size()); return true; } const ScopedSymbol ScopedSymbol::RetSymbol = ScopedSymbol{0, VERSION_NONE}; } diff --git a/cpp/src/ast.h b/cpp/src/ast.h index 87dbecc..3ca65f2 100644 --- a/cpp/src/ast.h +++ b/cpp/src/ast.h @@ -1,562 +1,573 @@ #ifndef AST_H #define AST_H #include "attachments.h" #include #include #include #include #include #include #include #include "utils.h" #include namespace llvm { class Value; } +namespace xreate{ + struct ScopedSymbol; + struct Symbol; +} + +namespace std +{ + template<> + struct hash{ + std::size_t operator()(xreate::ScopedSymbol const& s) const; + }; + + template<> + struct equal_to{ + bool operator()(const xreate::ScopedSymbol& __x, const xreate::ScopedSymbol& __y) const; + }; + + template<> + struct hash{ + size_t operator()(xreate::Symbol const& s) const; + }; + + template<> + struct equal_to{ + bool operator()(const xreate::Symbol& __x, const xreate::Symbol& __y) const; + }; +} + namespace xreate { struct String_t { }; struct Identifier_t { }; struct Number_t { }; struct Type_t { }; template class Atom { }; //DEBT hold for all atoms/identifiers Parser::Token data, like line:col position template<> class Atom { public: Atom(const std::wstring& value); Atom(std::string && name); const std::string& get() const; private: std::string __value; }; template<> class Atom { public: Atom(wchar_t* value); Atom(int value); double get()const; private: double __value; }; template<> class Atom { public: Atom(const std::wstring& value); const std::string& get() const; private: std::string __value; }; enum class TypePrimitive { Invalid, Bool, I8, I32, I64, Num, Int, Float, String }; - enum class TypeOperator { - NONE, CALL, CUSTOM, VARIANT, ARRAY, TUPLE, STRUCT, ACCESS, LINK - }; +enum class TypeOperator { + NONE, CALL, CUSTOM, VARIANT, ARRAY, TUPLE, STRUCT, ACCESS, LINK +}; - struct llvm_array_tag { - }; +struct llvm_array_tag { +}; - struct struct_tag { - }; - const llvm_array_tag tag_array = llvm_array_tag(); - const struct_tag tag_struct = struct_tag(); +struct struct_tag { +}; +const llvm_array_tag tag_array = llvm_array_tag(); +const struct_tag tag_struct = struct_tag(); - class TypeAnnotation { - public: - TypeAnnotation(); - TypeAnnotation(const Atom& typ); - TypeAnnotation(TypePrimitive typ); - TypeAnnotation(llvm_array_tag, TypeAnnotation typ, int size); - - TypeAnnotation(TypeOperator op, std::initializer_list operands); - TypeAnnotation(TypeOperator op, std::vector&& operands); - void addBindings(std::vector>&& params); - void addFields(std::vector>&& listFields); - bool operator<(const TypeAnnotation& t) const; - // TypeAnnotation (struct_tag, std::initializer_list); - - bool isValid() const; - - TypeOperator __operator = TypeOperator::NONE; - - std::vector __operands; - TypePrimitive __value; - std::string __valueCustom; - int conjuctionId = -1; //conjunction point id (relevant for recursive types) - - uint64_t __size = 0; - std::vector fields; - std::vector bindings; - private: - }; +class TypeAnnotation { +public: + TypeAnnotation(); + TypeAnnotation(const Atom& typ); + TypeAnnotation(TypePrimitive typ); + TypeAnnotation(llvm_array_tag, TypeAnnotation typ, int size); + + TypeAnnotation(TypeOperator op, std::initializer_list operands); + TypeAnnotation(TypeOperator op, std::vector&& operands); + void addBindings(std::vector>&& params); + void addFields(std::vector>&& listFields); + bool operator<(const TypeAnnotation& t) const; + // TypeAnnotation (struct_tag, std::initializer_list); + + bool isValid() const; + + TypeOperator __operator = TypeOperator::NONE; + + std::vector __operands; + TypePrimitive __value; + std::string __valueCustom; + int conjuctionId = -1; //conjunction point id (relevant for recursive types) + + uint64_t __size = 0; + std::vector fields; + std::vector bindings; +private: +}; - enum class Operator { - ADD, SUB, MUL, DIV, - EQU, NE, NEG, LSS, - LSE, GTR, GTE, LIST, - LIST_RANGE, LIST_NAMED, - CALL, CALL_INTRINSIC, NONE, - IMPL/* implication */, MAP, - FOLD, FOLD_INF, LOOP_CONTEXT, - INDEX, IF, SWITCH, SWITCH_ADHOC, - CASE, CASE_DEFAULT, LOGIC_AND, - ADHOC, CONTEXT_RULE - }; +enum class Operator { + ADD, SUB, MUL, DIV, + EQU, NE, NEG, LSS, + LSE, GTR, GTE, LIST, + LIST_RANGE, LIST_NAMED, + CALL, CALL_INTRINSIC, NONE, + IMPL/* implication */, MAP, + FOLD, FOLD_INF, LOOP_CONTEXT, + INDEX, IF, SWITCH, SWITCH_ADHOC, + CASE, CASE_DEFAULT, LOGIC_AND, + ADHOC, CONTEXT_RULE +}; - class Function; - class AST; - class CodeScope; - class MetaRuleAbstract; +class Function; +class AST; +class CodeScope; +class MetaRuleAbstract; - template - struct ManagedPtr { - - static ManagedPtr Invalid() { - return ManagedPtr(); - } - - ManagedPtr() : __storage(0) { - } - - ManagedPtr(unsigned int id, const std::vector* storage) - : __id(id), __storage(storage) { - } - - Target& - operator*() const { - assert(isValid() && "Invalid Ptr"); - return *__storage->at(__id); - } - - void operator=(const ManagedPtr& other) { - __id = other.__id; - __storage = other.__storage; - } - - bool - operator==(const ManagedPtr& other) { - return isValid() && (__id == other.__id); - } - - Target* - operator->() const noexcept { - assert(isValid() && "Invalid Ptr"); - return __storage->at(__id); - } - - inline bool isValid() const { - return (__storage) && (0 <= __id) && (__id < __storage->size()); - } - - inline operator bool() const { - return isValid(); - } - - ManagedPtr& operator++() { - ++__id; - return *this; - } - - inline unsigned int id() const { - return __id; - } - - private: - unsigned int __id = 0; - const std::vector * __storage = 0; - }; +template +struct ManagedPtr { - typedef ManagedPtr ManagedFnPtr; - typedef ManagedPtr ManagedScpPtr; - typedef ManagedPtr ManagedRulePtr; - const ManagedScpPtr NO_SCOPE = ManagedScpPtr(UINT_MAX, 0); - - //To update ExpressionHints in case of any changes - struct Expression { - friend class CodeScope; - friend class ClaspLayer; - friend class CFAPass; - friend class ExpressionHints; - - Expression(const Operator &oprt, std::initializer_list params); - Expression(const Atom& ident); - Expression(const Atom& number); - Expression(const Atom& a); - - Expression(); - - void setOp(Operator oprt); - void addArg(Expression&& arg); - void addBindings(std::initializer_list> params); - void bindType(TypeAnnotation t); - - template - void addBindings(InputIt paramsBegin, InputIt paramsEnd); - void addTags(const std::list tags) const; - void addBlock(ManagedScpPtr scope); - - const std::vector& getOperands() const; - double getValueDouble() const; - void setValueDouble(double value); - const std::string& getValueString() const; - void setValue(const Atom&& v); - bool isValid() const; - bool isDefined() const; - + static ManagedPtr Invalid() { + return ManagedPtr(); + } - bool operator==(const Expression& other) const; + ManagedPtr() : __storage(0) { + } - enum { - INVALID, COMPOUND, IDENT, NUMBER, STRING, VARIANT, BINDING - } __state = INVALID; - - Operator op; - unsigned int id; - std::vector bindings; - std::map __indexBindings; - std::vector operands; - TypeAnnotation type; - - mutable std::map tags; - std::list blocks; - - private: - std::string __valueS; - double __valueD; - - static unsigned int nextVacantId; - }; - - bool operator< (const Expression&, const Expression&); + ManagedPtr(unsigned int id, const std::vector* storage) + : __id(id), __storage(storage) { + } - template - void Expression::addBindings(InputIt paramsBegin, InputIt paramsEnd) { - size_t index = bindings.size(); - - std::transform(paramsBegin, paramsEnd, std::inserter(bindings, bindings.end()), - [&index, this] (const Atom atom) { - std::string key = atom.get(); - this->__indexBindings[key] = index++; - return key; - }); + Target& + operator*() const { + assert(isValid() && "Invalid Ptr"); + return *__storage->at(__id); } - typedef std::list ExpressionList; + void operator=(const ManagedPtr& other) { + __id = other.__id; + __storage = other.__storage; + } - enum class TagModifier { - NONE, ASSERT, REQUIRE - }; + bool + operator==(const ManagedPtr& other) { + return isValid() && (__id == other.__id); + } - enum class DomainAnnotation { - FUNCTION, VARIABLE - }; + Target* + operator->() const noexcept { + assert(isValid() && "Invalid Ptr"); + return __storage->at(__id); + } - class RuleArguments : public std::vector> - { - public: - void add(const Atom& name, DomainAnnotation typ); - }; + inline bool isValid() const { + return (__storage) && (0 <= __id) && (__id < __storage->size()); + } - class RuleGuards : public std::vector { - public: - void add(Expression&& e); - }; + inline operator bool() const { + return isValid(); + } + ManagedPtr& operator++() { + ++__id; + return *this; + } - class ClaspLayer; - class LLVMLayer; + inline unsigned int id() const { + return __id; + } - class MetaRuleAbstract { - public: - MetaRuleAbstract(RuleArguments&& args, RuleGuards&& guards); - virtual ~MetaRuleAbstract(); - virtual void compile(ClaspLayer& layer) = 0; - protected: - RuleArguments __args; - RuleGuards __guards; - }; +private: + unsigned int __id = 0; + const std::vector * __storage = 0; +}; + +typedef ManagedPtr ManagedFnPtr; +typedef ManagedPtr ManagedScpPtr; +typedef ManagedPtr ManagedRulePtr; +const ManagedScpPtr NO_SCOPE = ManagedScpPtr(UINT_MAX, 0); + +//To update ExpressionHints in case of any changes +struct Expression { + friend class CodeScope; + friend class ClaspLayer; + friend class CFAPass; + friend class ExpressionHints; + + Expression(const Operator &oprt, std::initializer_list params); + Expression(const Atom& ident); + Expression(const Atom& number); + Expression(const Atom& a); + + Expression(); + + void setOp(Operator oprt); + void addArg(Expression&& arg); + void addBindings(std::initializer_list> params); + void bindType(TypeAnnotation t); + + template + void addBindings(InputIt paramsBegin, InputIt paramsEnd); + void addTags(const std::list tags) const; + void addBlock(ManagedScpPtr scope); + + const std::vector& getOperands() const; + double getValueDouble() const; + void setValueDouble(double value); + const std::string& getValueString() const; + void setValue(const Atom&& v); + bool isValid() const; + bool isDefined() const; + + + bool operator==(const Expression& other) const; + + enum { + INVALID, COMPOUND, IDENT, NUMBER, STRING, VARIANT, BINDING + } __state = INVALID; + + Operator op; + unsigned int id; + std::vector bindings; + std::map __indexBindings; + std::vector operands; + TypeAnnotation type; + + mutable std::map tags; + std::list blocks; + +private: + std::string __valueS; + double __valueD; + + static unsigned int nextVacantId; +}; + +bool operator< (const Expression&, const Expression&); + +template +void Expression::addBindings(InputIt paramsBegin, InputIt paramsEnd) { + size_t index = bindings.size(); + + std::transform(paramsBegin, paramsEnd, std::inserter(bindings, bindings.end()), + [&index, this] (const Atom atom) { + std::string key = atom.get(); + this->__indexBindings[key] = index++; + return key; + }); +} + +typedef std::list ExpressionList; + +enum class TagModifier { + NONE, ASSERT, REQUIRE +}; - class RuleWarning : public MetaRuleAbstract { - friend class ClaspLayer; +enum class DomainAnnotation { + FUNCTION, VARIABLE +}; + +class RuleArguments : public std::vector> +{ public: - RuleWarning(RuleArguments&& args, RuleGuards&& guards, Expression&& condition, Atom&& message); - virtual void compile(ClaspLayer& layer); - ~RuleWarning(); + void add(const Atom& name, DomainAnnotation typ); +}; - private: - std::string __message; - Expression __condition; - }; +class RuleGuards : public std::vector { +public: + void add(Expression&& e); +}; - typedef unsigned int VNameId; - - typedef int VariableVersion; - const VariableVersion VERSION_NONE = -2; - const VariableVersion VERSION_INIT = 0; - - template<> - struct AttachmentsDict - { - typedef VariableVersion Data; - static const unsigned int key = 6; - }; - - struct ScopedSymbol{ - VNameId id; - VariableVersion version; - - static const ScopedSymbol RetSymbol; - }; - - struct Symbol { - ScopedSymbol identifier; - CodeScope * scope; - }; - - template<> - struct AttachmentsDict - { - typedef Symbol Data; - static const unsigned int key = 7; - }; - -} -namespace std + +class ClaspLayer; +class LLVMLayer; + +class MetaRuleAbstract { +public: + MetaRuleAbstract(RuleArguments&& args, RuleGuards&& guards); + virtual ~MetaRuleAbstract(); + virtual void compile(ClaspLayer& layer) = 0; +protected: + RuleArguments __args; + RuleGuards __guards; +}; + +class RuleWarning : public MetaRuleAbstract { + friend class ClaspLayer; +public: + RuleWarning(RuleArguments&& args, RuleGuards&& guards, Expression&& condition, Atom&& message); + virtual void compile(ClaspLayer& layer); + ~RuleWarning(); + +private: + std::string __message; + Expression __condition; +}; + +typedef unsigned int VNameId; + +typedef int VariableVersion; +const VariableVersion VERSION_NONE = -2; +const VariableVersion VERSION_INIT = 0; + +template<> +struct AttachmentsDict { - template<> - struct hash{ - std::size_t operator()(xreate::ScopedSymbol const& s) const; - }; + typedef VariableVersion Data; + static const unsigned int key = 6; +}; - template<> - struct equal_to{ - bool operator()(const xreate::ScopedSymbol& __x, const xreate::ScopedSymbol& __y) const; - }; -} +struct ScopedSymbol{ + VNameId id; + VariableVersion version; -namespace xreate { + static const ScopedSymbol RetSymbol; +}; + +struct Symbol { + ScopedSymbol identifier; + CodeScope * scope; +}; +template<> +struct AttachmentsDict +{ + typedef Symbol Data; + static const unsigned int key = 7; +}; - typedef std::pair Tag; +typedef std::pair Tag; - bool operator<(const ScopedSymbol& s1, const ScopedSymbol& s2); - bool operator==(const ScopedSymbol& s1, const ScopedSymbol& s2); - bool operator<(const Symbol& s1, const Symbol& s2); - bool operator==(const Symbol& s1, const Symbol& s2); +bool operator<(const ScopedSymbol& s1, const ScopedSymbol& s2); +bool operator==(const ScopedSymbol& s1, const ScopedSymbol& s2); +bool operator<(const Symbol& s1, const Symbol& s2); +bool operator==(const Symbol& s1, const Symbol& s2); class CodeScope { friend class Function; friend class PassManager; public: CodeScope(CodeScope* parent = 0); void setBody(const Expression& body); Expression& getBody(); void addDeclaration(Expression&& var, Expression&& body); void addBinding(Expression&& var, Expression&& argument); static const Expression& getDeclaration(const Symbol& symbol); const Expression& getDeclaration(const ScopedSymbol& symbol); ~CodeScope(); std::vector __bindings; std::map __identifiers; CodeScope* __parent; //TODO move __definitions to SymbolsAttachments data //NOTE: definition of return type has zero(0) variable index std::unordered_map __declarations; std::vector tags; std::vector contextRules; private: VNameId __vCounter = 1; ScopedSymbol registerIdentifier(const Expression& identifier); public: bool recognizeIdentifier(const Expression& identifier) const; ScopedSymbol getSymbol(const std::string& alias); }; class Function { friend class Expression; friend class CodeScope; friend class AST; public: Function(const Atom& name); void addBinding(Atom && name, Expression&& argument); void addTag(Expression&& tag, const TagModifier mod); const std::string& getName() const; const std::map& getTags() const; CodeScope* getEntryScope() const; CodeScope* __entry; std::string __name; bool isPrefunction = false; //SECTIONTAG adhoc Function::isPrefunction flag Expression guardContext; private: std::map __tags; }; class ExternData; struct ExternEntry { std::string package; std::vector headers; }; typedef Expanded ExpandedType; enum ASTInterface { CFA, DFA, Extern, Adhoc }; struct FunctionSpecialization { std::string guard; size_t id; }; struct FunctionSpecializationQuery { std::unordered_set context; }; template<> struct AttachmentsId{ static unsigned int getId(const Expression& expression){ return expression.id; } }; template<> struct AttachmentsId{ static unsigned int getId(const Symbol& s){ return s.scope->__declarations.at(s.identifier).id; } }; template<> struct AttachmentsId{ static unsigned int getId(const ManagedFnPtr& f){ const Symbol symbolFunction{ScopedSymbol::RetSymbol, f->getEntryScope()}; return AttachmentsId::getId(symbolFunction); } }; namespace details { namespace incomplete { class AST { public: AST(); //TASK extern and DFA interfaces move into addInterfaceData /** * DFA Interface */ void addDFAData(Expression&& data); /** * Extern Interface */ void addExternData(ExternData&& data); void addInterfaceData(const ASTInterface& interface, Expression&& data); void add(Function* f); void add(MetaRuleAbstract* r); ManagedScpPtr add(CodeScope* scope); std::string getModuleName(); ManagedPtr findFunction(const std::string& name); typedef std::multimap FUNCTIONS_REGISTRY; std::list getAllFunctions() const; std::list getFunctionVariants(const std::string& name) const; template ManagedPtr begin(); std::vector __externdata; std::list __dfadata; //TODO move to more appropriate place std::list __rawImports; //TODO move to more appropriate place std::multimap __interfacesData; //TODO CFA data here. private: std::vector __rules; std::vector __functions; std::vector __scopes; FUNCTIONS_REGISTRY __indexFunctions; // ***** TYPES SECTION ***** public: std::map __indexTypeAliases; void add(TypeAnnotation t, Atom alias); // ***** SYMBOL RECOGNITION ***** //TODO revisit enums/variants, move to codescope bool recognizeVariantIdentifier(Expression& identifier); private: std::map> __dictVariants; public: std::set> bucketUnrecognizedIdentifiers; public: void postponeIdentifier(CodeScope* scope, const Expression& id); void recognizePostponedIdentifiers(); xreate::AST* finalize(); }; template<> ManagedPtr AST::begin(); template<> ManagedPtr AST::begin(); template<> ManagedPtr AST::begin(); } } // namespace details::incomplete class AST: public details::incomplete::AST{ public: AST(): details::incomplete::AST() {} ExpandedType expandType(const TypeAnnotation &t) const; ExpandedType findType(const std::string& name); }; } #endif // AST_H diff --git a/cpp/src/clasplayer.cpp b/cpp/src/clasplayer.cpp index 4073851..519f176 100644 --- a/cpp/src/clasplayer.cpp +++ b/cpp/src/clasplayer.cpp @@ -1,275 +1,275 @@ #include "clasplayer.h" #include #include "utils.h" #include #include #include #include "analysis/aux.h" #include "analysis/DominatorsTreeAnalysisProvider.h" #include "analysis/cfagraph.h" #include "analysis/dfagraph.h" using namespace std; //TODO escape identifiers started with upper case symbol namespace xreate { void ClaspLayer::printWarnings(std::ostream& out) { const std::string warningTag = "warning"; auto warningsRange = __model.equal_range(warningTag); for (auto warning=warningsRange.first; warning!= warningsRange.second; ++warning) { unsigned int warningId; Gringo::Symbol params; std::tie(warningId, params) = parse(warning->second); cout << "Warning: " << __warnings.at(warningId) << " "; params.print(out); out< warnings; cout << "Model: " << endl; const string& atomBindVar = Config::get("clasp.bindings.variable"); const string& atomBindFunc = Config::get("clasp.bindings.function"); const string& atomBindScope = Config::get("clasp.bindings.scope"); for (Gringo::Symbol atom : model.atoms(clingo_show_type_atoms)) { atom.print(cout); cout <<" | "<< endl; string atomName(atom.name().c_str()); if (atomName == atomBindVar || atomName == atomBindFunc || atomName == atomBindScope){ string name = std::get<1>(parse(atom)).name().c_str(); __model.emplace(move(name), move(atom)); } __model.emplace(atomName, move(atom)); } return true; } void - ClaspLayer::setCFAData(xreate::analysis::CFAGraph* graph) { + ClaspLayer::setCFAData(xreate::cfa::CFAGraph* graph) { dataCFA.reset(graph); } void - ClaspLayer::setDFAData(xreate::analysis::DFAGraph* graph){ + ClaspLayer::setDFAData(xreate::dfa::DFAGraph* graph){ dataDFA.reset(graph); } void ClaspLayer::addRuleWarning(const RuleWarning &rule) { //__partGeneral << rule << endl; list domains; boost::format formatDef("%1%(%2%)"); std::transform(rule.__args.begin(), rule.__args.end(), std::inserter(domains, domains.begin()), [&formatDef](const std::pair &argument) { string domain; switch (argument.second) { case DomainAnnotation::FUNCTION: domain = "function"; break; case DomainAnnotation::VARIABLE: domain = "variable"; break; } return boost::str(formatDef % domain % argument.first); }); list vars; std::transform(rule.__args.begin(), rule.__args.end(), std::inserter(vars, vars.begin()), [](const std::pair &argument) { return argument.first.c_str(); }); list> guardsRaw; std::transform(rule.__guards.begin(), rule.__guards.end(), std::inserter(guardsRaw, guardsRaw.begin()), [this](const Expression &guard) { return xreate::analysis::compile(guard); }); const list& guards = xreate::analysis::multiplyLists(std::move(guardsRaw)); list &&branches = xreate::analysis::compileNeg(rule.__condition); boost::format formatWarning("warning(%1%, (%2%)):- %3%, %4%, %5%."); for (const string &guardsJoined: guards) for (const string &branch: branches) { unsigned int hook = registerWarning(string(rule.__message)); __partGeneral << formatWarning %(hook) %(boost::algorithm::join(vars, ", ")) %(branch) %(guardsJoined) %(boost::algorithm::join(domains, ", ")) <__rawImports) { std::ifstream file(fn); if (!file) continue; while(!file.eof()){ string line; std::getline(file, line); out << line << endl; } } } void ClaspLayer::addRawScript(std::string&& script){ __partGeneral << script; } void ClaspLayer::run() { involveImports(); if (this->dataDFA){ this->dataDFA->print(__partGeneral); } if (this->dataCFA){ this->dataCFA->print(__partGeneral); } - DominatorsTreeAnalysisProvider providerDominators; + dominators::DominatorsTreeAnalysisProvider providerDominators; providerDominators.run(this); providerDominators.print(__partGeneral); ostringstream program; program << __partTags.str() << __partGeneral.str(); cout << FYEL(program.str()) << endl; std::vector args{"clingo", nullptr}; DefaultGringoModule moduleDefault; Gringo::Scripts scriptsDefault(moduleDefault); ClingoLib ctl(scriptsDefault, 0, args.data(), {}, 0); ctl.add("base", {}, program.str()); ctl.ground({{"base", {}}}, nullptr); // solve Gringo::SolveResult result = ctl.solve([this](Gringo::Model const &model) { this->handleSolution(model); return true; }, {}); if (result.satisfiable() == Gringo::SolveResult::Satisfiable) { cout << FGRN("SUCCESSFULLY") << endl; } else { cout << FRED("UNSUCCESSFULLY") << endl; } // invoke all query plugins to process clasp data for (auto q: __queries) { q.second->init(this); } } ClaspLayer::ClaspLayer() { } ClaspLayer::ModelFragment ClaspLayer::query(const std::string& atom) { if (! __model.count(atom)){ return boost::none; } return ModelFragment(__model.equal_range(atom)); } ScopePacked ClaspLayer::pack(CodeScope* const scope) { auto pos = __indexScopes.emplace(scope, __indexScopes.size()); if (pos.second) __registryScopes.push_back(scope); return pos.first->second; } size_t ClaspLayer::getScopesCount() const{ return __registryScopes.size(); } SymbolPacked ClaspLayer::pack(const Symbol& symbol, std::string hintSymbolName) { SymbolPacked result(symbol.identifier.id, symbol.identifier.version, pack(symbol.scope)); __indexSymbolNameHints.emplace(result, hintSymbolName); return result; } Symbol ClaspLayer::unpack(const SymbolPacked& symbol) { return Symbol{ScopedSymbol{symbol.identifier, symbol.version}, __registryScopes[symbol.scope]}; }; std::string ClaspLayer::getHintForPackedSymbol(const SymbolPacked& symbol){ if (!symbol.categoryTransient) { auto result = __indexSymbolNameHints.find(symbol); return (result == __indexSymbolNameHints.end())? "" : result->second; } else { return "anonym(" + to_string(symbol.identifier) + ")"; } } bool operator==(const SymbolPacked& s1, const SymbolPacked& s2) { return s1.identifier == s2.identifier && s1.scope == s2.scope; } bool operator<(const SymbolPacked& s1, const SymbolPacked& s2) { return s1.scope < s2.scope || (s1.scope == s2.scope && s1.identifier < s2.identifier); } IQuery* ClaspLayer::registerQuery(IQuery *query, const QueryId& id) { return __queries.emplace(id, query).first->second; } IQuery* ClaspLayer::getQuery(const QueryId& id){ assert(__queries.count(id) && "Undefined query"); return __queries.at(id); } } \ No newline at end of file diff --git a/cpp/src/clasplayer.h b/cpp/src/clasplayer.h index 1bfe432..525868d 100644 --- a/cpp/src/clasplayer.h +++ b/cpp/src/clasplayer.h @@ -1,233 +1,236 @@ #ifndef CLASPLAYER_H #define CLASPLAYER_H #include "ast.h" #include "contextrule.h" #include #include #include #include #include #include #include #include namespace xreate { typedef unsigned int ScopePacked; struct SymbolPacked { VNameId identifier; VariableVersion version; ScopePacked scope; bool categoryTransient; SymbolPacked(): categoryTransient(false){} SymbolPacked(ScopedSymbol i, ScopePacked s, bool isTransient = false): identifier(i.id), version(i.version), scope(s), categoryTransient(isTransient){} SymbolPacked(VNameId symbolId, VariableVersion symbolVersion, ScopePacked symbolScope, bool isTransient = false) : identifier(symbolId), version(symbolVersion), scope(symbolScope), categoryTransient(isTransient){} }; bool operator==(const SymbolPacked& s1, const SymbolPacked& s2); bool operator<(const SymbolPacked& s1, const SymbolPacked& s2); enum class DFGConnection { STRONG, WEAK, PROTOTYPE }; class IAnalysisData { public: void print(std::ostringstream& output) const; virtual ~IAnalysisData(){}; }; class IQuery { public: virtual void init(ClaspLayer* clasp) = 0; virtual ~IQuery() {} }; enum class QueryId { ContainersQuery, ContextQuery, PtrvalidQuery }; - namespace analysis{ + namespace dfa{ class DFAGraph; + } + + namespace cfa { class CFAGraph; } class ClaspLayer { friend class ContextRule; //PROVIDERS: public: - boost::scoped_ptr dataDFA; - void setDFAData(xreate::analysis::DFAGraph* graph); + boost::scoped_ptr dataDFA; + void setDFAData(xreate::dfa::DFAGraph* graph); - boost::scoped_ptr dataCFA; - void setCFAData(xreate::analysis::CFAGraph* graph); + boost::scoped_ptr dataCFA; + void setCFAData(xreate::cfa::CFAGraph* graph); void addRawScript(std::string&& script); private: void involveImports(); //QUERIES public: IQuery* registerQuery(IQuery* query, const QueryId& id); IQuery* getQuery(const QueryId& id); template static std::tuple parse(const Gringo::Symbol& atom); typedef std::multimap::const_iterator ModelIterator; typedef boost::optional> ModelFragment; ModelFragment query(const std::string& atom); size_t getScopesCount() const; SymbolPacked pack(const Symbol& symbol, std::string hintSymbolName = ""); ScopePacked pack(CodeScope * const scope); Symbol unpack(const SymbolPacked& symbol); std::string getHintForPackedSymbol(const SymbolPacked& symbol); private: std::map __queries; std::multimap __model; std::map __indexSymbolNameHints; std::unordered_map __indexScopes; std::vector __registryScopes; //WARNINGS //TODO move to separate provider/query public: void addRuleWarning(const RuleWarning &rule); unsigned int registerWarning(std::string &&message); private: std::map __warnings; void printWarnings(std::ostream& out); //DEFAULT public: AST *ast; ClaspLayer(); void run(); private: std::ostringstream __partTags; std::ostringstream __partGeneral; bool handleSolution(Gringo::Model const &model); }; template struct ParseImplAtom { static typ get(const Gringo::Symbol& atom) { return atom.num(); } }; template<> struct ParseImplAtom { static std::string get(const Gringo::Symbol& atom) { switch (atom.type()) { case Gringo::SymbolType::Str: return atom.string().c_str(); case Gringo::SymbolType::Fun: return atom.name().c_str(); default: break; } assert(false && "Inappropriate symbol type"); } }; template<> struct ParseImplAtom { static SymbolPacked get(const Gringo::Symbol& atom) { auto result = ClaspLayer::parse(atom); return SymbolPacked(std::get<0>(result), std::get<1>(result), std::get<2>(result)); } }; template<> struct ParseImplAtom { static Gringo::Symbol get(const Gringo::Symbol& atom) { return atom; } }; template<> struct ParseImplAtom { static Expression get(const Gringo::Symbol& atom) { switch (atom.type()) { case Gringo::SymbolType::Num: return Expression(atom.num()); case Gringo::SymbolType::Str: return Expression(std::string(atom.string().c_str())); case Gringo::SymbolType::Fun: { //ID if (!atom.args().size){ return Expression(std::string(atom.name().c_str())); } //FUNC Expression result(Operator::CALL,{Expression(std::string(atom.name().c_str()))}); for (const Gringo::Symbol& arg : atom.args()) { result.addArg(ParseImplAtom::get(arg)); } return result; } default: { assert(false); } } } }; template struct Parse_Impl { static void parse(Tuple& tup, Gringo::SymSpan::iterator arg) { const size_t tupleSize = std::tuple_size::value; typedef typename std::tuple_element < tupleSize - index, Tuple>::type ElType; ElType& el = std::get < tupleSize - index > (tup); Gringo::Symbol atom = *arg; el = ParseImplAtom::get(atom); Parse_Impl ::parse(tup, ++arg); } }; template struct Parse_Impl { static void parse(Tuple& tup, Gringo::SymSpan::iterator arg) { } }; template std::tuple ClaspLayer::parse(const Gringo::Symbol& atom) { typedef std::tuple < Types...> Tuple; Tuple tup; Parse_Impl::value>::parse(tup, atom.args().first); return tup; } } #endif \ No newline at end of file diff --git a/cpp/src/compilation/latecontextcompiler2.cpp b/cpp/src/compilation/latecontextcompiler2.cpp index 7008044..93bdb9d 100644 --- a/cpp/src/compilation/latecontextcompiler2.cpp +++ b/cpp/src/compilation/latecontextcompiler2.cpp @@ -1,193 +1,193 @@ /* * LateContextCompiler2.cpp * * Created on: 10 февр. 2016 * Author: pgess */ //TOTEST default variants - do not enable specialization context in order to check default variant invocation #include "latecontextcompiler2.h" #include "llvmlayer.h" #include "pass/compilepass.h" #include "query/context.h" #include using namespace std; -namespace xreate { +namespace xreate {namespace context{ const string topicSpecializationAtom = "specialization"; const string topicDependencyAtom = "dependency"; typedef ExpressionSerialization::Code DomainId; typedef ExpressionSerialization::Serializer Domain; //TODO implement variantDefault; llvm::Value* compileDecisionSelector(llvm::IRBuilder<>& builder, llvm::Value* selector, std::vector vectorVariants, llvm::Value* variantDefault=nullptr){ assert(vectorVariants.size()>0); llvm::IntegerType* ty32 = llvm::Type::getInt32Ty(llvm::getGlobalContext()); llvm::Type* tyElement = vectorVariants[0]->getType(); llvm::Type* tyVariants = llvm::VectorType::get(tyElement, vectorVariants.size()); llvm::Value* vectorRaw = llvm::ConstantVector::getNullValue(tyVariants); for(DomainId i=0; iqueryContext; __sizeOfDemand = context->getFunctionDemand(function->function->getName()).size(); } llvm::Value* LateContextCompiler2::findFunction(const std::string& calleeName, llvm::Function* specializationDefault, ScopePacked scopeCaller){ const string& functionName = function->function->getName(); ContextQuery* context = pass->queryContext; llvm::IRBuilder<>& builder = pass->man->llvm->builder; const FunctionDemand& demand = context->getFunctionDemand(functionName); const std::list& specializations = pass->man->root->getFunctionVariants(calleeName); //independent decision: Expression topic(Operator::CALL, {(Atom(string(topicSpecializationAtom))), (Atom(string(calleeName))), (Atom(scopeCaller))}); assert(demand.right.count(topic) && "Can't determine specialization for the function"); size_t topicId = demand.right.at(topic); llvm::Value* topicDecisionRaw = builder.CreateExtractValue(this->rawContextArgument, llvm::ArrayRef{(unsigned) topicId}); const Domain& specializationsDomain= context->getTopicDomain(topic); std::vector vectorVariants; vectorVariants.reserve(specializationsDomain.size()); for (const ManagedFnPtr& f: specializations){ if (!f->guardContext.isValid()) continue; const auto& variantId = specializationsDomain.getIdOptional(f->guardContext); if (variantId){ if (vectorVariants.size() < *variantId + 1) { vectorVariants.resize(*variantId + 1); } vectorVariants[*variantId] = pass->getFunctionUnit(f)->compile(); } } return compileDecisionSelectorAsSwitch(topicDecisionRaw, vectorVariants, specializationDefault); } llvm::Value* LateContextCompiler2::compileContextArgument(const std::string& callee, ScopePacked scopeCaller){ const std::string& atomDependentDecision = Config::get("clasp.context.decisions.dependent"); llvm::IRBuilder<>& builder = pass->man->llvm->builder; ContextQuery* context = pass->queryContext; const string& functionName = function->function->getName(); const Decisions& dictStaticDecisions = context->getFinalDecisions(scopeCaller); const FunctionDemand& demandCallee = context->getFunctionDemand(callee); const FunctionDemand& demandSelf = context->getFunctionDemand(functionName); llvm::IntegerType* ty32 = llvm::Type::getInt32Ty(llvm::getGlobalContext()); llvm::Type* tyDemand = llvm::ArrayType::get(ty32, demandCallee.size()); //builder.CreateAlloca(tyDemand, llvm::ConstantInt::get(ty32, 1)); llvm::Value* res = llvm::ConstantArray::getNullValue(tyDemand); for (size_t i=0, size = demandCallee.size(); irawContextArgument, llvm::ArrayRef{(unsigned) topicId}); } else if (dictStaticDecisions.count(topic)){ //static final decision: const Expression& decision = dictStaticDecisions.at(topic); const Domain& domainOfTopic = context->getTopicDomain(topic); const DomainId& decisionCode = domainOfTopic.getId(decision); decisionRaw = llvm::ConstantInt::get(ty32, decisionCode); } else { //dependent decision decisionRaw = compileDependentDecision(topic, scopeCaller); } res = builder.CreateInsertValue(res, decisionRaw, llvm::ArrayRef{(unsigned) i}); } return res; } llvm::Value* LateContextCompiler2::compileDependentDecision(const Expression& topic, ScopePacked scopeCaller){ const string& functionName = function->function->getName(); ContextQuery* context = pass->queryContext; llvm::IRBuilder<>& builder = pass->man->llvm->builder; llvm::IntegerType* ty32 = llvm::Type::getInt32Ty(llvm::getGlobalContext()); const FunctionDemand& demandSelf = context->getFunctionDemand(functionName); const Expression topicDependency = Expression(Operator::CALL, {Atom(string(topicDependencyAtom)), topic, Atom(scopeCaller)}); const Domain& demandOfTopic = context->getTopicDomain(topic); const Domain& domainOfTopicDependency = context->getTopicDomain(topicDependency); //dependent decision vector vectorDecisions(domainOfTopicDependency.size(), llvm::UndefValue::get(ty32)); for (const std::pair& entry: context->getDependentDecision(scopeCaller,topic)){ vectorDecisions[domainOfTopicDependency.getId(entry.first)]= llvm::ConstantInt::get(ty32, demandOfTopic.getId(entry.second)); } size_t topicDependencyId = demandSelf.right.at(topicDependency); llvm::Value* decisionRaw = builder.CreateExtractValue(this->rawContextArgument, llvm::ArrayRef{(unsigned) topicDependencyId}); auto result = compileDecisionSelector(pass->man->llvm->builder, decisionRaw, vectorDecisions); return result; } llvm::Value* LateContextCompiler2::compileDecisionSelectorAsSwitch(llvm::Value* selector, std::vector vectorVariants, llvm::Function* variantDefault){ llvm::IRBuilder<>& builder = pass->man->llvm->builder; llvm::IntegerType* ty32 = llvm::Type::getInt32Ty(llvm::getGlobalContext()); llvm::BasicBlock* blockDefault = llvm::BasicBlock::Create(llvm::getGlobalContext(), "caseDefault", this->function->raw); llvm::BasicBlock *blockEpilog = llvm::BasicBlock::Create(llvm::getGlobalContext(), "VariantDeterminationEnd", this->function->raw); llvm::SwitchInst* instrSwitch = builder.CreateSwitch(selector, blockDefault, vectorVariants.size()); builder.SetInsertPoint(blockEpilog); llvm::PHINode *result = builder.CreatePHI(variantDefault->getType(), vectorVariants.size(), "callee"); for (size_t i=0; ifunction->raw); builder.SetInsertPoint(blockCase); builder.CreateBr(blockEpilog); result->addIncoming(vectorVariants[i], blockCase); instrSwitch->addCase(llvm::ConstantInt::get(ty32, i), blockCase); } builder.SetInsertPoint(blockDefault); builder.CreateBr(blockEpilog); result->addIncoming(variantDefault, blockDefault); builder.SetInsertPoint(blockEpilog); return result; } size_t LateContextCompiler2::getFunctionDemandSize() const { return __sizeOfDemand; } -} /* namespace xreate */ +}} /* namespace xreate::context */ diff --git a/cpp/src/compilation/latecontextcompiler2.h b/cpp/src/compilation/latecontextcompiler2.h index abb12e1..8d8234d 100644 --- a/cpp/src/compilation/latecontextcompiler2.h +++ b/cpp/src/compilation/latecontextcompiler2.h @@ -1,51 +1,51 @@ /* * LateContextCompiler2.h * * Created on: 10 февр. 2016 * Author: pgess */ //TOTEST compile several context arguments #ifndef LATECONTEXTCOMPILER2_H_ #define LATECONTEXTCOMPILER2_H_ #include "serialization.h" namespace llvm { class Value; class Function; } namespace xreate { class CompilePass; namespace compilation { class FunctionUnit; }} -namespace xreate { +namespace xreate {namespace context{ typedef unsigned int ScopePacked; class LateContextCompiler2 { public: llvm::Value* rawContextArgument = nullptr; LateContextCompiler2(compilation::FunctionUnit* f, CompilePass* p); llvm::Value* findFunction(const std::string& calleeName, llvm::Function* specializationDefault, ScopePacked scopeCaller); llvm::Value* compileContextArgument(const std::string& callee, ScopePacked scopeCaller); size_t getFunctionDemandSize() const; private: //boost::bimap __decisions; //std::vector __scheme; compilation::FunctionUnit* function; CompilePass* pass; size_t __sizeOfDemand; llvm::Value* compileDependentDecision(const Expression& topic, ScopePacked scopeCaller); llvm::Value* compileDecisionSelectorAsSwitch(llvm::Value* selector, std::vector vectorVariants, llvm::Function* variantDefault); }; -} /* namespace xreate */ +}} /* namespace xreate::context */ #endif /* LATECONTEXTCOMPILER2_H_ */ \ No newline at end of file diff --git a/cpp/src/compilation/pointerarithmetic.cpp b/cpp/src/compilation/pointerarithmetic.cpp index 307c174..ed1e020 100644 --- a/cpp/src/compilation/pointerarithmetic.cpp +++ b/cpp/src/compilation/pointerarithmetic.cpp @@ -1,31 +1,31 @@ /* * pointerarithmetic.cpp * * Author: pgess * Created on March 29, 2017, 11:52 AM */ #include "pointerarithmetic.h" #include "llvmlayer.h" #include using namespace llvm; -namespace xreate { namespace compilation { +namespace xreate { namespace pointerarithmetic { llvm::Value* -PointerArithmetic::add(llvm::Value *left, llvm::Value *right, Context context, const std::string& hintVarDecl){ +PointerArithmetic::add(llvm::Value *left, llvm::Value *right, compilation::Context context, const std::string& hintVarDecl){ LLVMLayer* llvm = context.pass->man->llvm; if (left->getType()->isPointerTy() && right->getType()->isIntegerTy()){ std::vector indexes{right}; //{llvm::ConstantInt::get(llvm::Type::getInt32Ty(llvm::getGlobalContext()), 0)}; //indexes.push_back(right); return llvm->builder.CreateGEP(left, llvm::ArrayRef(indexes), hintVarDecl); } return nullptr; } } } \ No newline at end of file diff --git a/cpp/src/compilation/pointerarithmetic.h b/cpp/src/compilation/pointerarithmetic.h index 5302d7b..14fe7f6 100644 --- a/cpp/src/compilation/pointerarithmetic.h +++ b/cpp/src/compilation/pointerarithmetic.h @@ -1,29 +1,29 @@ /* * File: pointerarithmetic.h * Author: pgess * * Created on March 29, 2017, 11:52 AM */ #ifndef POINTERARITHMETIC_H #define POINTERARITHMETIC_H #include "pass/compilepass.h" namespace llvm { class Value; } -namespace xreate { namespace compilation { +namespace xreate { namespace pointerarithmetic { class PointerArithmetic { public: - static llvm::Value* add(llvm::Value *left, llvm::Value *right, Context context, const std::string& hintVarDecl); + static llvm::Value* add(llvm::Value *left, llvm::Value *right, compilation::Context context, const std::string& hintVarDecl); }; } } #endif /* POINTERARITHMETIC_H */ diff --git a/cpp/src/compilation/scopedecorators.h b/cpp/src/compilation/scopedecorators.h index ac469ad..0c6aa78 100644 --- a/cpp/src/compilation/scopedecorators.h +++ b/cpp/src/compilation/scopedecorators.h @@ -1,129 +1,129 @@ /* * File: scopedecorators.h * Author: pgess * * Created on February 24, 2017, 11:35 AM */ #ifndef SCOPEDECORATORS_H #define SCOPEDECORATORS_H #include "ast.h" #include "compilation/targetinterpretation.h" #include "compilation/versions.h" #include "compilation/transformations.h" namespace xreate { class CompilePass; namespace compilation { class AbstractCodeScopeUnit; class FunctionUnit; template class CachedScopeDecorator: public Parent{ typedef CachedScopeDecorator SELF; public: CachedScopeDecorator(CodeScope* codeScope, FunctionUnit* f, CompilePass* compilePass): Parent(codeScope, f, compilePass){} void bindArg(llvm::Value* value, std::string&& alias) { //ensure existence of an alias assert(Parent::scope->__identifiers.count(alias)); //memorize new value for an alias ScopedSymbol id{Parent::scope->__identifiers.at(alias), VERSION_NONE}; __rawVars[id] = value; } void bindArg(llvm::Value* value, const ScopedSymbol& s) { __rawVars[s] = value; } llvm::Value* compile(const std::string& hintBlockDecl="") override{ if (__rawVars.count(ScopedSymbol::RetSymbol)){ return __rawVars[ScopedSymbol::RetSymbol]; } return Parent::compile(hintBlockDecl); } llvm::Value* processSymbol(const Symbol& s, std::string hintRetVar) override{ CodeScope* scope = s.scope; SELF* self = dynamic_cast(Parent::function->getScopeUnit(scope)); if (self->__rawVars.count(s.identifier)){ return self->__rawVars[s.identifier]; } //Declaration could be overriden Expression declaration = CodeScope::getDeclaration(s); if (!declaration.isDefined()){ if (self->__declarationsOverriden.count(s.identifier)){ declaration = self->__declarationsOverriden[s.identifier]; } else { assert(false); //in case of binding there should be raws provided. } } return self->__rawVars[s.identifier] = Parent::processSymbol(s, hintRetVar); } void overrideDeclaration(const Symbol binding, Expression&& declaration){ SELF* self = dynamic_cast(Parent::function->getScopeUnit(binding.scope)); self->__declarationsOverriden.emplace(binding.identifier, std::move(declaration)); } void registerChildScope(std::shared_ptr scope){ __childScopes.push_back(scope); } void reset(){ __rawVars.clear(); __declarationsOverriden.clear(); __childScopes.clear(); } private: std::unordered_map __declarationsOverriden; std::unordered_map __rawVars; std::list> __childScopes; }; typedef CachedScopeDecorator< compilation::TransformationsScopeDecorator< - compilation::InterpretationScopeDecorator< - compilation::VersionsScopeDecorator>>> + interpretation::InterpretationScopeDecorator< + versions::VersionsScopeDecorator>>> DefaultScopeUnit; } //end of compilation namespace struct CachedScopeDecoratorTag; struct VersionsScopeDecoratorTag; template<> struct DecoratorsDict{ typedef compilation::CachedScopeDecorator< compilation::TransformationsScopeDecorator< - compilation::InterpretationScopeDecorator< - compilation::VersionsScopeDecorator>>> result; + interpretation::InterpretationScopeDecorator< + versions::VersionsScopeDecorator>>> result; }; template<> struct DecoratorsDict{ - typedef compilation::VersionsScopeDecorator< + typedef versions::VersionsScopeDecorator< compilation::BasicCodeScopeUnit> result; }; } //end of xreate #endif /* SCOPEDECORATORS_H */ diff --git a/cpp/src/compilation/targetinterpretation.cpp b/cpp/src/compilation/targetinterpretation.cpp index 047f4ef..3c79321 100644 --- a/cpp/src/compilation/targetinterpretation.cpp +++ b/cpp/src/compilation/targetinterpretation.cpp @@ -1,441 +1,442 @@ /* * File: targetinterpretation.cpp * Author: pgess * * Created on June 29, 2016, 6:45 PM */ #include "compilation/targetinterpretation.h" #include "pass/interpretationpass.h" #include "llvmlayer.h" #include "compilation/scopedecorators.h" #include #include #include using namespace std; +using namespace xreate::compilation; -namespace xreate{ namespace compilation { +namespace xreate{ namespace interpretation{ const Expression EXPRESSION_FALSE = Expression(Atom(0)); const Expression EXPRESSION_TRUE = Expression(Atom(1)); //Expression //InterpretationScope::compile(const Expression& expression){} CodeScope* InterpretationScope::processOperatorIf(const Expression& expression){ const Expression& exprCondition = process(expression.getOperands()[0]); if (exprCondition == EXPRESSION_TRUE){ return expression.blocks.front(); } return expression.blocks.back(); } CodeScope* InterpretationScope::processOperatorSwitch(const Expression& expression) { const Expression& exprCondition = process(expression.operands[0]); bool flagHasDefault = expression.operands[1].op == Operator::CASE_DEFAULT; //TODO check that one and only one case variant is appropriate for (size_t size = expression.operands.size(), i= flagHasDefault? 2: 1; igetScope(exprCase.blocks.front())->processScope() == exprCondition){ return exprCase.blocks.back(); } } if (flagHasDefault){ const Expression& exprCaseDefault = expression.operands[1]; return exprCaseDefault.blocks.front(); } assert(false && "Switch has no appropriate variant"); return nullptr; } llvm::Value* InterpretationScope::compileHybrid(const InterpretationOperator& op, const Expression& expression, const Context& context){ switch(op){ case IF_INTERPRET_CONDITION: { CodeScope* scopeResult = processOperatorIf(expression); llvm::Value* result = context.function->getScopeUnit(scopeResult)->compile(); return result; } case SWITCH_INTERPRET_CONDITION:{ CodeScope* scopeResult = processOperatorSwitch(expression); llvm::Value* result = context.function->getScopeUnit(scopeResult)->compile(); return result; } case FOLD_INTERPRET_INPUT: { //initialization const Expression& exprInput = process(expression.getOperands()[0]); assert(exprInput.op == Operator::LIST); CodeScope* scopeBody = expression.blocks.front(); const string& nameEl = expression.bindings[0]; Symbol symbEl{ScopedSymbol{scopeBody->__identifiers.at(nameEl), VERSION_NONE}, scopeBody}; const std::string& idAccum = expression.bindings[1]; llvm::Value* rawAccum = context.scope->process(expression.getOperands()[1]); InterpretationScope* intrBody = function->getScope(scopeBody); auto unitBody = Decorators::getInterface(context.function->getScopeUnit(scopeBody)); const std::vector elementsInput= exprInput.getOperands(); for (size_t i=0; ireset(); unitBody->reset(); Expression exprElement = elementsInput[i]; intrBody->overrideBinding(exprElement, nameEl); unitBody->overrideDeclaration(symbEl, move(exprElement)); unitBody->bindArg(rawAccum, string(idAccum)); rawAccum = unitBody->compile(); } return rawAccum; } /* case FOLD_INF_INTERPRET_INOUT{ } */ case CALL_INTERPRET_PARTIAL: { const std::string &calleeName = expression.getValueString(); AbstractCodeScopeUnit* scopeUnitSelf = context.scope; ManagedFnPtr callee = this->function->man->ast->findFunction(calleeName); const FunctionInterpretationData& calleeData = FunctionInterpretationHelper::getSignature(callee); std::vector argsActual; PIFSignature sig; sig.declaration = callee; for(size_t no=0, size = expression.operands.size(); no < size; ++no){ const Expression& op = expression.operands[no]; if (calleeData.signature.at(no) == INTR_ONLY){ sig.bindings.push_back(process(op)); continue; } argsActual.push_back(scopeUnitSelf->process(op)); } TargetInterpretation* man = dynamic_cast(this->function->man); PIFunction* pifunction = man->getFunction(move(sig)); llvm::Function* raw = pifunction->compile(); boost::scoped_ptr statement(new CallStatementRaw(raw, man->pass->man->llvm)); return (*statement)(move(argsActual)); } default: break; } assert(false&& "Unknown hybrid operator"); return nullptr; } llvm::Value* InterpretationScope::compile(const Expression& expression, const Context& context){ const InterpretationData& data = Attachments::get(expression); if (data.op != InterpretationOperator::NONE){ return compileHybrid(data.op, expression, context); } Expression result = process(expression); return context.scope->process(result); } Expression InterpretationScope::process(const Expression& expression){ switch (expression.__state){ case Expression::INVALID: assert(false); case Expression::VARIANT: case Expression::NUMBER: case Expression::STRING: return expression; case Expression::IDENT:{ Symbol s = Attachments::get(expression); return Parent::processSymbol(s); } case Expression::COMPOUND: break; default: assert(false); } switch (expression.op) { case Operator::EQU: { const Expression& left = process(expression.operands[0]); const Expression& right = process(expression.operands[1]); if (left == right) return EXPRESSION_TRUE; return EXPRESSION_FALSE; } case Operator::NE: { const Expression& left = process(expression.operands[0]); const Expression& right = process(expression.operands[1]); if (left == right) return EXPRESSION_FALSE; return EXPRESSION_TRUE; } case Operator::LOGIC_AND: { assert(expression.operands.size() == 1); return process (expression.operands[0]); } // case Operator::LOGIC_OR: case Operator::CALL: { const std::string &fnName = expression.getValueString(); ManagedFnPtr fnAst = this->function->man->ast->findFunction(fnName); InterpretationFunction* fnUnit = this->function->man->getFunction(fnAst); vector args; args.reserve(expression.getOperands().size()); for(size_t i=0, size = expression.getOperands().size(); iprocess(args); } case Operator::IF:{ CodeScope* scopeResult = processOperatorIf(expression); return function->getScope(scopeResult)->processScope(); } case Operator::SWITCH: { CodeScope* scopeResult = processOperatorSwitch(expression); return function->getScope(scopeResult)->processScope(); } case Operator::INDEX: { const Expression& exprKey = process(expression.operands[1]); const Expression& exprData = process(expression.operands[0]); if (exprKey.__state == Expression::STRING){ const string& key = exprKey.getValueString(); assert(exprData.__indexBindings.count(key)); return exprData.operands[exprData.__indexBindings.at(key)]; } if (exprKey.__state == Expression::NUMBER){ int key = exprKey.getValueDouble(); return exprData.operands[key]; } assert(false); } case Operator::FOLD: { const Expression& exprInput = process(expression.getOperands()[0]); const Expression& exprInit = process(expression.getOperands()[1]); const std::string& argEl = expression.bindings[0]; const std::string& argAccum = expression.bindings[1]; InterpretationScope* body = function->getScope(expression.blocks.front()); Expression accum = exprInit; for(size_t size=exprInput.getOperands().size(), i=0; ioverrideBinding(exprInput.getOperands()[i], argEl); body->overrideBinding(accum, argAccum); accum = body->processScope(); } return accum; } // case Operator::MAP: { // break; // } default: break; } return expression; } InterpretationFunction* TargetInterpretation::getFunction(FunctionUnit* unit){ if (__dictFunctionsByUnit.count(unit)) { return __dictFunctionsByUnit.at(unit); } InterpretationFunction* f = new InterpretationFunction(unit->function, this); __dictFunctionsByUnit.emplace(unit, f); assert(__functions.emplace(unit->function.id(), f).second); return f; } PIFunction* TargetInterpretation::getFunction(PIFSignature&& sig){ auto f = __pifunctions.find(sig); if (f != __pifunctions.end()){ return f->second; } PIFunction* result = new PIFunction(PIFSignature(sig), __pifunctions.size(), this); __pifunctions.emplace(move(sig), result); assert(__dictFunctionsByUnit.emplace(result->functionUnit, result).second); return result; } InterpretationScope* TargetInterpretation::transformContext(const Context& c){ return this->getFunction(c.function)->getScope(c.scope->scope); } llvm::Value* TargetInterpretation::compile(const Expression& expression, const Context& ctx){ return transformContext(ctx)->compile(expression, ctx); } InterpretationFunction::InterpretationFunction(const ManagedFnPtr& function, Target* target) : Function(function, target) {} Expression InterpretationFunction::process(const std::vector& args){ InterpretationScope* body = getScope(__function->__entry); for(size_t i=0, size = args.size(); ioverrideBinding(args.at(i), string(body->scope->__bindings.at(i))); } return body->processScope(); } // Partial function interpretation typedef BasicFunctionDecorator PIFunctionUnitParent; class PIFunctionUnit: public PIFunctionUnitParent{ public: PIFunctionUnit(ManagedFnPtr f, std::set&& arguments, size_t id, CompilePass* p) : PIFunctionUnitParent(f, p), argumentsActual(move(arguments)), __id(id) {} protected: std::vector prepareArguments(){ LLVMLayer* llvm = PIFunctionUnitParent::pass->man->llvm; AST* ast = PIFunctionUnitParent::pass->man->root; CodeScope* entry = PIFunctionUnitParent::function->__entry; std::vector signature; for(size_t no: argumentsActual){ VNameId argId = entry->__identifiers.at(entry->__bindings.at(no)); ScopedSymbol arg{argId, VERSION_NONE}; signature.push_back(llvm->toLLVMType(ast->expandType(entry->__declarations.at(arg).type))); } return signature; } llvm::Function::arg_iterator prepareBindings(){ CodeScope* entry = PIFunctionUnitParent::function->__entry; AbstractCodeScopeUnit* entryCompilation = PIFunctionUnitParent::getScopeUnit(entry); llvm::Function::arg_iterator fargsI = PIFunctionUnitParent::raw->arg_begin(); for(size_t no: argumentsActual){ ScopedSymbol arg{entry->__identifiers.at(entry->__bindings.at(no)), VERSION_NONE}; entryCompilation->bindArg(&*fargsI, arg); fargsI->setName(entry->__bindings.at(no)); ++fargsI; } return fargsI; } virtual std::string prepareName(){ return PIFunctionUnitParent::prepareName() + "_" + std::to_string(__id); } private: std::set argumentsActual; size_t __id; }; PIFunction::PIFunction(PIFSignature&& sig, size_t id, TargetInterpretation* target) : InterpretationFunction(sig.declaration, target), signatureInstance(move(sig)) { const FunctionInterpretationData& functionData = FunctionInterpretationHelper::getSignature(signatureInstance.declaration); std::set argumentsActual; for (size_t no=0, size=functionData.signature.size(); no < size; ++no){ if (functionData.signature.at(no) != INTR_ONLY){ argumentsActual.insert(no); } } functionUnit = new PIFunctionUnit(signatureInstance.declaration, move(argumentsActual), id, target->pass); CodeScope* entry = signatureInstance.declaration->__entry; auto entryUnit = Decorators::getInterface<>(functionUnit->getEntry()); InterpretationScope* entryIntrp = InterpretationFunction::getScope(entry); for(size_t no=0, sigNo=0, size = entry->__bindings.size(); no < size; ++no){ if (functionData.signature.at(no) == INTR_ONLY){ entryIntrp->overrideBinding(signatureInstance.bindings[sigNo], entry->__bindings[no]); VNameId argId = entry->__identifiers.at(entry->__bindings[no]); Symbol argSymbol{ScopedSymbol{argId, VERSION_NONE}, entry}; entryUnit->overrideDeclaration(argSymbol, Expression(signatureInstance.bindings[sigNo])); ++sigNo; } } } llvm::Function* PIFunction::compile(){ llvm::Function* raw = functionUnit->compile(); return raw; } bool operator<(const PIFSignature& lhs, const PIFSignature& rhs){ if (lhs.declaration.id() != rhs.declaration.id()) { return lhs.declaration.id() < rhs.declaration.id(); } return lhs.bindings < rhs.bindings; } bool operator<(const PIFSignature& lhs, PIFunction* const rhs){ return lhs < rhs->signatureInstance; } bool operator<(PIFunction* const lhs, const PIFSignature& rhs){ return lhs->signatureInstance < rhs; } }} diff --git a/cpp/src/compilation/targetinterpretation.h b/cpp/src/compilation/targetinterpretation.h index 7b7acdd..a36b08a 100644 --- a/cpp/src/compilation/targetinterpretation.h +++ b/cpp/src/compilation/targetinterpretation.h @@ -1,134 +1,130 @@ /* * To change this license header, choose License Headers in Project Properties. * To change this template file, choose Tools | Templates * and open the template in the editor. */ /* * File: targetstatic.h * Author: pgess * * Created on July 2, 2016, 1:25 PM */ #ifndef TARGETSTATIC_H #define TARGETSTATIC_H #include "ast.h" #include "pass/compilepass.h" #include "compilation/targets.h" #include "pass/interpretationpass.h" -namespace xreate{ namespace compilation { - -class TargetInterpretation; -class InterpretationScope; -class InterpretationFunction; +namespace xreate{ namespace interpretation{ + class TargetInterpretation; + class InterpretationScope; + class InterpretationFunction; +}} +namespace xreate{ namespace compilation{ template <> - struct TargetInfo { + struct TargetInfo { typedef Expression Result; - typedef InterpretationScope Scope; - typedef InterpretationFunction Function; - }; - -class InterpretationScope: public Scope{ + typedef interpretation::InterpretationScope Scope; + typedef interpretation::InterpretationFunction Function; + }; +}} + +namespace xreate{ namespace interpretation{ +class InterpretationScope: public compilation::Scope{ typedef Scope Parent; public: - InterpretationScope(CodeScope* scope, Function* f): Parent(scope, f) {} + InterpretationScope(CodeScope* scope, compilation::Function* f): Parent(scope, f) {} Expression process(const Expression& expression) override; - llvm::Value* compile(const Expression& expression, const Context& context); + llvm::Value* compile(const Expression& expression, const compilation::Context& context); private: - llvm::Value* compileHybrid(const InterpretationOperator& op, const Expression& expression, const Context& context); + llvm::Value* compileHybrid(const InterpretationOperator& op, const Expression& expression, const compilation::Context& context); //llvm::Value* compilePartialFnCall(const Expression& expression, const Context& context); CodeScope* processOperatorIf(const Expression& expression); CodeScope* processOperatorSwitch(const Expression& expression); }; -class InterpretationFunction: public Function{ +class InterpretationFunction: public compilation::Function{ public: - InterpretationFunction(const ManagedFnPtr& function, Target* target); + InterpretationFunction(const ManagedFnPtr& function, compilation::Target* target); Expression process(const std::vector& args); }; /* * Partially interpreted function signature */ struct PIFSignature{ ManagedFnPtr declaration; std::vector bindings; }; class PIFunctionUnit; class PIFunction: public InterpretationFunction{ public: PIFunctionUnit* functionUnit; PIFSignature signatureInstance; PIFunction(PIFSignature&& sig, size_t id, TargetInterpretation* target); llvm::Function* compile(); }; bool operator<(const PIFSignature& lhs, PIFunction* const rhs); bool operator<(PIFunction* const lhs, const PIFSignature& rhs); -class TargetInterpretation: public Target{ +class TargetInterpretation: public compilation::Target{ public: TargetInterpretation(AST* root, CompilePass* passCompilation): Target(root), pass(passCompilation){} //target: public: - InterpretationFunction* getFunction(FunctionUnit* unit); + InterpretationFunction* getFunction(compilation::FunctionUnit* unit); PIFunction* getFunction(PIFSignature&& sig); private: std::map __pifunctions; - std::map __dictFunctionsByUnit; + std::map __dictFunctionsByUnit; //self: public: CompilePass* pass; - llvm::Value* compile(const Expression& expression, const Context& ctx); + llvm::Value* compile(const Expression& expression, const compilation::Context& ctx); private: - InterpretationScope* transformContext(const Context& c); + InterpretationScope* transformContext(const compilation::Context& c); }; template class InterpretationScopeDecorator: public Parent{ public: - InterpretationScopeDecorator(CodeScope* codeScope, FunctionUnit* f, CompilePass* compilePass): Parent(codeScope, f, compilePass){} + InterpretationScopeDecorator(CodeScope* codeScope, compilation::FunctionUnit* f, CompilePass* compilePass): Parent(codeScope, f, compilePass){} virtual llvm::Value* process(const Expression& expr, const std::string& hintVarDecl){ const InterpretationData& data = Attachments::get(expr, {ANY, NONE}); bool flagInterpretationEligible = (data.resolution == INTR_ONLY || data.op != InterpretationOperator::NONE); if (flagInterpretationEligible){ - Context ctx{this, this->function, this->pass}; + compilation::Context ctx{this, this->function, this->pass}; return Parent::pass->targetInterpretation->compile(expr, ctx); } return Parent::process(expr, hintVarDecl); } }; - - - -} //end of compilation - -struct InterpretationScopeDecoratorTag; - -} //end of xreate +}} //end of xreate:: interpretation #endif /* TARGETSTATIC_H */ //transformers: // template<> // struct TransformerInfo { // static const int id = 1; // }; \ No newline at end of file diff --git a/cpp/src/compilation/versions.h b/cpp/src/compilation/versions.h index e1f9b0d..bc958e6 100644 --- a/cpp/src/compilation/versions.h +++ b/cpp/src/compilation/versions.h @@ -1,127 +1,125 @@ /* * versions.cpp * * Author: pgess * Created on January 21, 2017, 1:24 PM */ #include "pass/versionspass.h" #include "pass/compilepass.h" namespace xreate { - -class CompilePass; + class CompilePass; namespace compilation { + class AbstractCodeScopeUnit; + class FunctionUnit; +} -class AbstractCodeScopeUnit; -class FunctionUnit; - +namespace versions{ template class VersionsScopeDecorator: public Parent{ typedef VersionsScopeDecorator SELF; public: - VersionsScopeDecorator(CodeScope* codeScope, FunctionUnit* f, CompilePass* compilePass): Parent(codeScope, f, compilePass){} + VersionsScopeDecorator(CodeScope* codeScope, compilation::FunctionUnit* f, CompilePass* compilePass): Parent(codeScope, f, compilePass){} virtual llvm::Value* processSymbol(const Symbol& s, std::string hintSymbol=""){ if (Attachments::exists(s)){ const std::list dependencies = Attachments::get(s); for(const Symbol& symbolDependent: dependencies){ processSymbol(symbolDependent); } } llvm::Value* result = Parent::processSymbol(s, hintSymbol); if (s.identifier.version == VERSION_INIT){ llvm::Value* storage = SELF::processIntrinsicInit(result->getType(), hintSymbol); setSymbolStorage(s, storage); processIntrinsicCopy(result, storage); - return AbstractCodeScopeUnit::pass->man->llvm->builder.CreateLoad(storage); + return compilation::AbstractCodeScopeUnit::pass->man->llvm->builder.CreateLoad(storage); } else if (s.identifier.version != VERSION_NONE){ Symbol symbolInitVersion = getSymbolInitVersion(s); llvm::Value* storage = getSymbolStorage(symbolInitVersion); processIntrinsicCopy(result, storage); - return AbstractCodeScopeUnit::pass->man->llvm->builder.CreateLoad(storage); + return compilation::AbstractCodeScopeUnit::pass->man->llvm->builder.CreateLoad(storage); } return result; } llvm::Value* processIntrinsicInit(llvm::Type* typeStorage, const std::string& hintVarDecl=""){ llvm::IntegerType* tyInt = llvm::Type::getInt32Ty(llvm::getGlobalContext()); llvm::ConstantInt* constOne = llvm::ConstantInt::get(tyInt, 1, false); - return AbstractCodeScopeUnit::pass->man->llvm->builder.CreateAlloca(typeStorage, constOne, hintVarDecl); + return compilation::AbstractCodeScopeUnit::pass->man->llvm->builder.CreateAlloca(typeStorage, constOne, hintVarDecl); } void processIntrinsicCopy(llvm::Value* value, llvm::Value* storage){ - AbstractCodeScopeUnit::pass->man->llvm->builder.CreateStore(value, storage); + compilation::AbstractCodeScopeUnit::pass->man->llvm->builder.CreateStore(value, storage); } private: std::map __symbolStorage; static Symbol getSymbolInitVersion(const Symbol& s){ return Symbol{ScopedSymbol{s.identifier.id, VERSION_INIT}, s.scope}; } llvm::Value* getSymbolStorage(const Symbol& s){ return __symbolStorage.at(s); } void setSymbolStorage(const Symbol& s, llvm::Value* storage){ __symbolStorage[s] = storage; } }; -} //end of compilation namespace -} //end of xreate namespace - +} } //end of namespace xreate::versions // llvm::Value* // processIntrinsicInitAndCopy(){ // // } //llvm::Value* //process(const Expression& expr, const std::string& hintVarDecl){ // case Operator::CALL_INTRINSIC: { // enum INRINSIC{INIT, COPY}; // // const ExpandedType& typSymbol = pass->man->root->expandType(expr.type); // // INTRINSIC op = (INTRINSIC) expr.getValueDouble(); // // switch (op){ // case INIT: { // llvm::Type* typSymbolRaw = l.toLLVMType(typSymbol); // // // return storage; // } // // case COPY: { // llvm::Type* typSymbolRaw = l.toLLVMType(typSymbol); // llvm::value* valueOriginal = process(expr.getOperands()[0], hintVarDecl); // llvm::Value* storage = l.builder.CreateAlloca(typSymbolRaw, constOne, hintVarDecl); // llvm::Value* valueCopy = l.builder.CreateStore(valueOriginal, storage); // // return valueCopy; // } // } // return; // } //} //}; \ No newline at end of file diff --git a/cpp/src/misc/xreatemanager-decorators.cpp b/cpp/src/misc/xreatemanager-decorators.cpp index 242d45e..7f414ac 100644 --- a/cpp/src/misc/xreatemanager-decorators.cpp +++ b/cpp/src/misc/xreatemanager-decorators.cpp @@ -1,67 +1,67 @@ /* * xreatemanager-decorators.cpp * * Author: pgess * Created on July 16, 2017, 4:40 PM */ #include "misc/xreatemanager-decorators.h" #include "main/Parser.h" #include "pass/compilepass.h" #include "pass/adhocpass.h" #include "pass/cfapass.h" #include "pass/dfapass.h" #include "pass/interpretationpass.h" #include "pass/versionspass.h" namespace xreate { void XreateManagerDecoratorBase::prepareCode(std::string&& code){ grammar::main::Scanner scanner(reinterpret_cast(code.c_str()), code.size()); grammar::main::Parser parser(&scanner); parser.Parse(); assert(!parser.errors->count && "Parser errors"); PassManager::prepare(parser.root->finalize()); } void XreateManagerDecoratorBase::prepareCode(FILE* code){ grammar::main::Scanner scanner(code); grammar::main::Parser parser(&scanner); parser.Parse(); assert(!parser.errors->count && "Parser errors"); PassManager::prepare(parser.root->finalize()); } void XreateManagerDecoratorBase::analyse(){ CompilePass::prepareQueries(clasp); clasp->run(); } void XreateManagerDecoratorFull::initPasses(){ - CFAPass* passCFG = new CFAPass(this); + cfa::CFAPass* passCFG = new cfa::CFAPass(this); //TODO is it really DFGPass needs CFGpass? - registerPass(new DFAPass(this), PassId::DFGPass, passCFG); + registerPass(new dfa::DFAPass(this), PassId::DFGPass, passCFG); registerPass(passCFG, PassId::CFGPass); - this->registerPass(new AdhocPass(this), PassId::AdhocPass); - this->registerPass(new InterpretationPass(this), PassId::InterpretationPass); - this->registerPass(new VersionsPass(this), PassId::VersionsPass); + this->registerPass(new adhoc::AdhocPass(this), PassId::AdhocPass); + this->registerPass(new interpretation::InterpretationPass(this), PassId::InterpretationPass); + this->registerPass(new versions::VersionsPass(this), PassId::VersionsPass); } void* XreateManagerDecoratorFull::run() { std::unique_ptr compiler(new CompilePass(this)); compiler->run(); llvm->print(); llvm->initJit(); return llvm->getFunctionPointer(compiler->getEntryFunction()); } } //namespace xreate diff --git a/cpp/src/misc/xreatemanager-modules.h b/cpp/src/misc/xreatemanager-modules.h index bff07cf..27688d9 100644 --- a/cpp/src/misc/xreatemanager-modules.h +++ b/cpp/src/misc/xreatemanager-modules.h @@ -1,110 +1,110 @@ /* * File: PassManagerModular.h * Author: pgess * * Created on June 22, 2017, 5:32 PM */ #ifndef PASSMANAGERMODULAR_H #define PASSMANAGERMODULAR_H #include "ast.h" #include "modules.h" #include "modules/Parser.h" #include "main/Parser.h" -namespace xreate{ +namespace xreate{namespace modules { template class XreateManagerDecoratorModules: public Parent{ public: XreateManagerDecoratorModules(): __registry(new ModulesRegistry()){} void prepareCode(std::string&& code) override { - grammar::modules::Scanner scannerModules(reinterpret_cast(code.c_str()), code.size()); + Scanner scannerModules(reinterpret_cast(code.c_str()), code.size()); std::list listIncludedFiles; parseModulesGrammar(scannerModules, listIncludedFiles); grammar::main::Scanner scannerMain(reinterpret_cast(code.c_str()), code.size()); parseMainGrammar(scannerMain, listIncludedFiles); } void prepareCode(FILE* code) override { - grammar::modules::Scanner scannerModules(code); + Scanner scannerModules(code); std::list listIncludedFiles; parseModulesGrammar(scannerModules, listIncludedFiles); grammar::main::Scanner scannerMain(code); parseMainGrammar(scannerMain, listIncludedFiles); } private: ModulesRegistry* __registry; - void parseModulesGrammar(grammar::modules::Scanner& scanner, std::list& listIncludedFiles){ + void parseModulesGrammar(Scanner& scanner, std::list& listIncludedFiles){ ModulesSolver solver(__registry); - grammar::modules::Parser parser(&scanner); + Parser parser(&scanner); parser.Parse(); parser.module.__path = ""; solver.init("", parser.module); std::list modulesExternal = solver.run(parser.module); std::string programBase = solver.__program.str(); for (const std::string module: modulesExternal){ parseModulesGrammar(module, programBase, listIncludedFiles); } } void parseModulesGrammar(const std::string& path, std::string base, std::list& listIncludedFiles){ FILE* input = fopen(path.c_str(), "r"); assert(input != nullptr); - grammar::modules::Scanner scanner(input); - grammar::modules::Parser parser(&scanner); + Scanner scanner(input); + Parser parser(&scanner); parser.Parse(); parser.module.__path = path; fclose(input); ModulesSolver solver(__registry); solver.init(base, parser.module); std::list&& modulesExternal = solver.run(parser.module); std::string programBase = solver.__program.str(); for (const std::string module: modulesExternal){ parseModulesGrammar(module, programBase, listIncludedFiles); } listIncludedFiles.push_back(path); } void parseMainGrammar(grammar::main::Scanner& scanner, std::list& listIncludedFiles){ details::incomplete::AST* ast = new AST; grammar::main::Parser parser(&scanner); parser.root = ast; parser.Parse(); assert(!parser.errors->count && "Parser errors"); for (auto file: listIncludedFiles){ FILE* fileContent = fopen(file.c_str(), "r"); grammar::main::Scanner scanner(fileContent); grammar::main::Parser parser(&scanner); parser.root = ast; parser.Parse(); fclose(fileContent); assert(!parser.errors->count && "Parser errors"); } PassManager::prepare(ast->finalize()); } }; -} //end namespace xreate +}} //end namespace xreate::modules #endif /* PASSMANAGERMODULAR_H */ diff --git a/cpp/src/modules.cpp b/cpp/src/modules.cpp index c5e87fe..421ec5d 100644 --- a/cpp/src/modules.cpp +++ b/cpp/src/modules.cpp @@ -1,175 +1,175 @@ /* * modules.cpp * * Author: pgess * Created on July 22, 2017, 5:13 PM */ #include "modules.h" #include "modules/Parser.h" #include "analysis/aux.h" #include #include #include #include #include namespace fs = boost::filesystem; -namespace xreate { +namespace xreate { namespace modules{ void ModuleRecord::addModuleQuery(const Expression& query){ __queries.push_back(query); } void ModuleRecord::addControllerPath(const std::string& path){ __controllers.push_back(path); } void ModuleRecord::addDiscoveryPath(const std::string& path){ __discoveries.push_back(path); } void ModuleRecord::addProperty(const Expression& prop){ __properties.push_back(prop); } void ModulesSolver::loadControllers(const ModuleRecord& module){ for (const std::string& pathController: module.__controllers){ std::fstream fileContent(pathController); __program << fileContent.rdbuf(); } } void ModulesSolver::extractProperties(const ModuleRecord& module){ unsigned int moduleId = __registry->getModuleHash(module.__path); const std::string atomProperty = "bind_module"; boost::format formatProperty(atomProperty + "(%1%, %2%)."); for (const Expression& property: module.__properties){ std::list reprProp = xreate::analysis::compile(property); assert(reprProp.size()== 1); __program << (formatProperty % moduleId % reprProp.front()) << std::endl; } } void ModulesSolver::discoverModules(const ModuleRecord& moduleClient){ std::regex extXreate("\\.xreate$", std::regex::basic); for(const std::string& path: moduleClient.__discoveries){ for(fs::directory_entry e: fs::recursive_directory_iterator(path)) { if (fs::is_regular_file(e.status())){ if (!std::regex_search(e.path().string(), extXreate)) continue; FILE* script = fopen(e.path().c_str(), "r"); - grammar::modules::Scanner scanner(script); - grammar::modules::Parser parser(&scanner); + Scanner scanner(script); + Parser parser(&scanner); parser.Parse(); assert(!parser.errors->count && "Discovery errors"); parser.module.__path = e.path().c_str(); extractProperties(parser.module); fclose(script); } } } } void ModulesSolver::extractRequirements(const ModuleRecord& module){ const std::string atomQuery = "module_require"; boost::format formatProperty(atomQuery + "(%1%, %2%)."); unsigned int moduleId = __registry->getModuleHash(module.__path); for (const Expression& query: module.__queries){ std::list reprQuery = xreate::analysis::compile(query); assert(reprQuery.size()== 1); __program << (formatProperty % moduleId % reprQuery.front()) << std::endl; } } void ModulesSolver::add(const std::string& base){ __program << base; } void ModulesSolver::init(const std::string& programBase, const ModuleRecord& module){ add(programBase); extractRequirements(module); extractProperties(module); loadControllers(module); discoverModules(module); std::cout << __program.str() << std::endl; } std::list ModulesSolver::run(const ModuleRecord& module){ const std::string atomDecision = "module_include"; unsigned int moduleId = __registry->getModuleHash(module.__path); std::list result; std::vector args{"clingo", nullptr}; DefaultGringoModule moduleDefault; Gringo::Scripts scriptsDefault(moduleDefault); ClingoLib ctl(scriptsDefault, 0, args.data(), {}, 0); ctl.add("base", {}, __program.str()); ctl.ground({{"base", {}}}, nullptr); ctl.solve([&atomDecision, this, &result, moduleId](Gringo::Model const &model) { for (Gringo::Symbol atom : model.atoms(clingo_show_type_atoms)) { std::cout << atom << std::endl; if (std::strcmp(atom.name().c_str(), atomDecision.c_str())==0){ auto rowDecision = ClaspLayer::parse(atom); unsigned int moduleIdActual = std::get<0>(rowDecision); if (moduleIdActual == moduleId){ Gringo::Symbol moduleDecided = std::get<1>(rowDecision); switch (moduleDecided.type()) { case Gringo::SymbolType::Str: result.push_back(moduleDecided.string().c_str()); break; case Gringo::SymbolType::Num: result.push_back(__registry->getModuleNameByHash(moduleDecided.num())); break; default: assert(false && "Inappropriate symbol type"); } } } } return true; }, {}); return result; } const std::string& ModulesRegistry::getModuleNameByHash(unsigned int hash){ auto result = __registry.right.find(hash); assert(result != __registry.right.end()); return result->second; } unsigned int ModulesRegistry::getModuleHash(const std::string& moduleName){ auto result = __registry.left.insert(Hash::left_value_type(moduleName, __registry.size())); return result.first->second; } -} //namespace xreate +}} //namespace xreate::modules diff --git a/cpp/src/modules.h b/cpp/src/modules.h index 39c2e97..0e2d150 100644 --- a/cpp/src/modules.h +++ b/cpp/src/modules.h @@ -1,76 +1,76 @@ /* * File: modules.h * Author: pgess * * Created on July 22, 2017, 5:11 PM */ #ifndef MODULES_H #define MODULES_H #include "ast.h" #include #ifndef FRIENDS_MODULES_TESTS #define FRIENDS_MODULES_TESTS #endif -namespace xreate { +namespace xreate { namespace modules{ class ModulesRegistry{ public: const std::string& getModuleNameByHash(unsigned int hash); unsigned int getModuleHash(const std::string& moduleName); private: typedef boost::bimap Hash; Hash __registry; }; class ModulesSolver; class ModuleRecord { FRIENDS_MODULES_TESTS friend class ModulesSolver; public: void addModuleQuery(const Expression& query); void addControllerPath(const std::string& path); void addDiscoveryPath(const std::string& path); void addProperty(const Expression& prop); private: std::list __queries; std::list __controllers; std::list __discoveries; std::list __properties; public: std::string __path; }; class ModulesSolver{ FRIENDS_MODULES_TESTS public: ModulesSolver(ModulesRegistry *registry): __registry(registry) {} void loadControllers(const ModuleRecord& module); void discoverModules(const ModuleRecord& moduleClient); void extractProperties(const ModuleRecord& module); void extractRequirements(const ModuleRecord& module); void add(const std::string& base); void init(const std::string& programBase, const ModuleRecord& module); std::list run(const ModuleRecord& module); private: ModulesRegistry* __registry; public: std::ostringstream __program; }; -} //end namespace xreate +}} //end namespace xreate::modules #endif /* MODULES_H */ \ No newline at end of file diff --git a/cpp/src/pass/adhocpass.cpp b/cpp/src/pass/adhocpass.cpp index 35e3c50..b7bdd7e 100644 --- a/cpp/src/pass/adhocpass.cpp +++ b/cpp/src/pass/adhocpass.cpp @@ -1,95 +1,95 @@ /* * adhoc.cpp * * Created on: Nov 28, 2015 * Author: pgess */ #include "pass/adhocpass.h" #include "query/context.h" -namespace xreate { +namespace xreate { namespace adhoc { AdhocExpression::AdhocExpression(): Expression(Operator::ADHOC, {}) {} AdhocExpression::AdhocExpression(const Expression& base): Expression(base) {} void AdhocExpression::setCommand(const Expression& comm){ this->addTags({Expression(Operator::CALL, {Atom("adhoc"), comm})}); } Expression AdhocExpression::getCommand() const{ assert(this->tags.count("adhoc")); return this->tags.at("adhoc").getOperands().at(0); } AdhocScheme* AdhocPass::findAssotiatedScheme(CodeScope* entry){ const ScopePacked scopeId = man->clasp->pack(entry); - const Domain& domain = queryContext->getContext(scopeId); + const context::Domain& domain = queryContext->getContext(scopeId); AdhocScheme* scheme = nullptr; for (const Expression& context: domain){ if (context.__state != Expression::IDENT) continue; if (__schemes.count(context.getValueString())){ assert(!scheme && "Can't determine relevant scheme, ambiguous context"); scheme = __schemes.at(context.getValueString()); } } assert(scheme && "Context doesn't define any ad hoc scheme"); return scheme; } const TypeAnnotation& AdhocScheme::getResultType(){ return __resultType; } CodeScope* AdhocScheme::getCommandImplementation(const Expression& comm) { assert(comm.__state == Expression::IDENT); const std::string commSerialized = comm.getValueString(); assert(__commands.count(commSerialized) && "Command isn't defined for a selected scheme"); return __commands.at(commSerialized); } AdhocScheme::AdhocScheme(const Expression& scheme): __resultType(scheme.type), __name(scheme.getValueString()) { Expression exprCasesList = scheme.getOperands()[0]; for (const Expression& exprSingleCase: exprCasesList.getOperands()){ std::string command = exprSingleCase.tags.begin()->second.getValueString(); CodeScope* blockImpl = *(exprSingleCase.blocks.begin()); __commands.emplace(command, blockImpl); } } const std::string& AdhocScheme::getName(){ return __name; } void AdhocPass::run(){ - queryContext = reinterpret_cast(man->clasp->registerQuery(new ContextQuery(), QueryId::ContextQuery)); + queryContext = reinterpret_cast(man->clasp->registerQuery(new context::ContextQuery(), QueryId::ContextQuery)); auto range = man->root->__interfacesData.equal_range(ASTInterface::Adhoc); for (auto i=range.first; i!= range.second; ++i){ AdhocScheme* scheme = new AdhocScheme(i->second); __schemes.emplace(scheme->getName(), scheme); } } -} +}} //end of namespace xreate::adhoc diff --git a/cpp/src/pass/adhocpass.h b/cpp/src/pass/adhocpass.h index 561ebfa..0508f52 100644 --- a/cpp/src/pass/adhocpass.h +++ b/cpp/src/pass/adhocpass.h @@ -1,59 +1,58 @@ /* * adhoc.h * * Created on: Nov 28, 2015 * Author: pgess */ //SECTIONTAG adhoc pass #ifndef SRC_INSTRUCTIONS_ADHOC_H_ #define SRC_INSTRUCTIONS_ADHOC_H_ #include "abstractpass.h" #ifndef FRIENDS_ADHOC #define FRIENDS_ADHOC #endif -namespace xreate { - -class ContextQuery; +namespace xreate { namespace context { + class ContextQuery; +}} +namespace xreate{ namespace adhoc{ class AdhocScheme { public: AdhocScheme(const Expression& scheme); CodeScope* getCommandImplementation(const Expression& comm); const TypeAnnotation& getResultType(); const std::string& getName(); private: TypeAnnotation __resultType; std::string __name; std::map __commands; }; class AdhocExpression: public Expression{ public: AdhocExpression(); AdhocExpression(const Expression& base); void setCommand(const Expression& comm); Expression getCommand() const; }; class AdhocPass: public AbstractPass { FRIENDS_ADHOC - public: AdhocPass(PassManager* manager): AbstractPass(manager) {} void run() override; - AdhocScheme* findAssotiatedScheme(CodeScope* entry); private: std::map __schemes; - ContextQuery* queryContext; + context::ContextQuery* queryContext; }; -} +}} //end of namespace xreate::adhoc #endif /* SRC_INSTRUCTIONS_ADHOC_H_ */ diff --git a/cpp/src/pass/cfapass.cpp b/cpp/src/pass/cfapass.cpp index 80f3034..da51821 100644 --- a/cpp/src/pass/cfapass.cpp +++ b/cpp/src/pass/cfapass.cpp @@ -1,100 +1,100 @@ #include "cfapass.h" #include "analysis/cfagraph.h" #include using namespace std; -using namespace xreate; +using namespace xreate::cfa; void CFAPass::initSignatures(){ auto range = man->root->__interfacesData.equal_range(CFA); for (auto i = range.first; i!= range.second; ++i){ __signatures.emplace(i->second.op, i->second); } } void CFAPass::run(){ initSignatures(); return AbstractPass::run(); } void CFAPass::finish() { man->clasp->setCFAData(move(__context.graph)); return AbstractPass::finish(); } void CFAPass::processFnCall(ManagedFnPtr function, PassContext context) { ClaspLayer* clasp = man->clasp; __context.graph->addCallConnection(clasp->pack(context.scope), function->getName()); return AbstractPass::processFnCall(function, context); } void CFAPass::processFnCallUncertain(ManagedFnPtr function, PassContext context){ ClaspLayer* clasp = man->clasp; __context.graph->addCallConnection(clasp->pack(context.scope), function->getName()); return AbstractPass::processFnCallUncertain(function, context); } void CFAPass::process(CodeScope* scope, PassContext context, const std::string& hintBlockDecl){ ClaspLayer* clasp = man->clasp; CodeScope* scopeParent = context.scope; ScopePacked scopeId = clasp->pack(scope); if (scopeParent){ __context.graph->addParentConnection(scopeId, clasp->pack(scopeParent)); } else { __context.graph->addParentConnection(scopeId, context.function->getName()); } //TOTEST scope annotations //SECTIONTAG context gather scope annotations __context.graph->addScopeAnnotations(scopeId, scope->tags); __context.graph->addContextRules(scopeId, scope->contextRules); return AbstractPass::process(scope, context, hintBlockDecl); } //TOTEST scope annotations via scheme void CFAPass::process(const Expression& expression, PassContext context, const std::string& varDecl){ ClaspLayer* clasp = man->clasp; if (expression.__state == Expression::COMPOUND){ Operator op= expression.op; if (__signatures.count(op)) { assert(expression.blocks.size()); for (const auto& scheme: boost::make_iterator_range(__signatures.equal_range(expression.op))) { __context.graph->addScopeAnnotations(clasp->pack(expression.blocks.front()), scheme.second.getOperands()); } } } return AbstractPass::process(expression, context, varDecl); } void CFAPass::process(ManagedFnPtr function) { __context.graph->addFunctionAnnotations(function->getName(), function->getTags()); return AbstractPass::process(function); } CFAPass::CFAPass(PassManager* manager) : AbstractPass(manager) - , __context{new xreate::analysis::CFAGraph(manager->clasp)} + , __context{new CFAGraph(manager->clasp)} {} diff --git a/cpp/src/pass/cfapass.h b/cpp/src/pass/cfapass.h index b63e6a6..be27a1e 100644 --- a/cpp/src/pass/cfapass.h +++ b/cpp/src/pass/cfapass.h @@ -1,38 +1,39 @@ // Control Flow Graph determination pass #ifndef CFGPASS_H #define CFGPASS_H #include "xreatemanager.h" #include "clasplayer.h" #include "abstractpass.h" -namespace xreate{namespace analysis { - class CFAGraph; -}} - -namespace xreate { +namespace xreate{namespace cfa { + +class CFAGraph; + class CFAPass : public AbstractPass { public: void process(ManagedFnPtr function) override; void processFnCall(ManagedFnPtr function, PassContext context) override; void processFnCallUncertain(ManagedFnPtr function, PassContext context) override; void process(CodeScope* scope, PassContext context, const std::string& hintBlockDecl="") override; void process(const Expression& expression, PassContext context, const std::string& varDecl="") override; CFAPass(PassManager* manager); void finish() override; void run() override; private: struct { - xreate::analysis::CFAGraph* graph; + CFAGraph* graph; } __context; std::multimap __signatures; //CFA data for particular operators void initSignatures(); -}; } +}; + +}} //end of namespace xreate::cfa #endif // CFGPASS_H diff --git a/cpp/src/pass/compilepass.cpp b/cpp/src/pass/compilepass.cpp index e9e7d12..76425ba 100644 --- a/cpp/src/pass/compilepass.cpp +++ b/cpp/src/pass/compilepass.cpp @@ -1,799 +1,770 @@ #include "compilepass.h" #include "clasplayer.h" #include #include "llvmlayer.h" #include "query/containers.h" #include "query/context.h" #include "compilation/containers.h" #include "compilation/latecontextcompiler2.h" #include "ExternLayer.h" #include "pass/adhocpass.h" #include "compilation/targetinterpretation.h" #include "pass/versionspass.h" #include "compilation/scopedecorators.h" +#include "compilation/adhocfunctiondecorator.h" #include "compilation/pointerarithmetic.h" #include #include #include using namespace std; -using namespace xreate; -using namespace xreate::compilation; using namespace llvm; //TODO use Scope //SECTIONTAG types/convert implementation //TODO type conversion: //a) automatically expand types int -> bigger int; int -> floating //b) detect exact type of `num` based on max used numeral / function type //c) warning if need to truncate (allow/dissalow based on annotations) namespace xreate { llvm::Value* doAutomaticTypeConversion(llvm::Value* source, llvm::Type* tyTarget, llvm::IRBuilder<>& builder){ if (tyTarget->isIntegerTy() && source->getType()->isIntegerTy()) { llvm::IntegerType* tyTargetInt = llvm::dyn_cast(tyTarget); llvm::IntegerType* tySourceInt = llvm::dyn_cast(source->getType()); if (tyTargetInt->getBitWidth() < tySourceInt->getBitWidth()){ return builder.CreateCast(llvm::Instruction::Trunc, source, tyTarget); } if (tyTargetInt->getBitWidth() > tySourceInt->getBitWidth()){ return builder.CreateCast(llvm::Instruction::SExt, source, tyTarget); } } if (source->getType()->isIntegerTy() && tyTarget->isFloatingPointTy()){ return builder.CreateCast(llvm::Instruction::SIToFP, source, tyTarget); } return source; } std::string BasicFunctionDecorator::prepareName(){ AST* ast = FunctionUnit::pass->man->root; string name = ast->getFunctionVariants(FunctionUnit::function->__name).size() > 1? FunctionUnit::function->__name + std::to_string(FunctionUnit::function.id()) : FunctionUnit::function->__name; return name; } std::vector BasicFunctionDecorator::prepareArguments(){ LLVMLayer* llvm = FunctionUnit::pass->man->llvm; AST* ast = FunctionUnit::pass->man->root; CodeScope* entry = FunctionUnit::function->__entry; std::vector signature; std::transform(entry->__bindings.begin(), entry->__bindings.end(), std::inserter(signature, signature.end()), [llvm, ast, entry](const std::string &arg)->llvm::Type* { assert(entry->__identifiers.count(arg)); ScopedSymbol argid{entry->__identifiers.at(arg), VERSION_NONE}; return llvm->toLLVMType(ast->expandType(entry->__declarations.at(argid).type)); }); return signature; } llvm::Type* BasicFunctionDecorator::prepareResult(){ LLVMLayer* llvm = FunctionUnit::pass->man->llvm; AST* ast = FunctionUnit::pass->man->root; CodeScope* entry = FunctionUnit::function->__entry; return llvm->toLLVMType(ast->expandType(entry->__declarations.at(ScopedSymbol::RetSymbol).type)); } llvm::Function::arg_iterator BasicFunctionDecorator::prepareBindings(){ CodeScope* entry = FunctionUnit::function->__entry; AbstractCodeScopeUnit* entryCompilation = FunctionUnit::getScopeUnit(entry); llvm::Function::arg_iterator fargsI = FunctionUnit::raw->arg_begin(); for (std::string &arg : entry->__bindings) { ScopedSymbol argid{entry->__identifiers[arg], VERSION_NONE}; entryCompilation->bindArg(&*fargsI, argid); fargsI->setName(arg); ++fargsI; } return fargsI; } //SECTIONTAG late-context FunctionDecorator template class LateContextFunctionDecorator: public Parent{ public: LateContextFunctionDecorator(ManagedFnPtr f, CompilePass* p) : Parent(f, p), contextCompiler(this, p) {} protected: std::vector prepareArguments(){ std::vector&& arguments = Parent::prepareArguments(); size_t sizeLateContextDemand = contextCompiler.getFunctionDemandSize(); if (sizeLateContextDemand) { llvm::Type* ty32 = llvm::Type::getInt32Ty(llvm::getGlobalContext()); llvm::Type* tyDemand = llvm::ArrayType::get(ty32, sizeLateContextDemand); arguments.push_back(tyDemand); } return arguments; } llvm::Function::arg_iterator prepareBindings(){ llvm::Function::arg_iterator fargsI = Parent::prepareBindings(); size_t sizeLateContextDemand = contextCompiler.getFunctionDemandSize(); if (sizeLateContextDemand){ fargsI->setName("latecontext"); contextCompiler.rawContextArgument = &*fargsI; ++fargsI; } return fargsI; } public: - LateContextCompiler2 contextCompiler; - -}; - -//SECTIONTAG adhoc FunctionDecorator -template -class AdhocFunctionDecorator: public Parent{ -public: - AdhocFunctionDecorator(ManagedFnPtr f, CompilePass* p) - : Parent(f, p) {} - -protected: - llvm::Type* prepareResult(){ - PassManager* man = Parent::pass->man; - CodeScope* entry = Parent::function->__entry; - LLVMLayer* llvm = Parent::pass->man->llvm; - AST* ast = Parent::pass->man->root; - AdhocPass* adhocpass = reinterpret_cast(man->getPassById(PassId::AdhocPass)); - - if (! Parent::function->isPrefunction){ - return Parent::prepareResult(); - } - - adhocImplementation = adhocpass->findAssotiatedScheme(entry); - return llvm->toLLVMType(ast->expandType(adhocImplementation->getResultType())); - } - -public: - AdhocScheme* adhocImplementation=nullptr; + context::LateContextCompiler2 contextCompiler; }; //DEBT compiler rigidly depends on exact definition of DefaultFunctionUnit typedef LateContextFunctionDecorator< - AdhocFunctionDecorator< + adhoc::AdhocFunctionDecorator< BasicFunctionDecorator>> DefaultFunctionUnit; AbstractCodeScopeUnit::AbstractCodeScopeUnit(CodeScope* codeScope, FunctionUnit* f, CompilePass* compilePass) : pass(compilePass), function(f), scope(codeScope) {} llvm::Value* CallStatementRaw::operator() (std::vector&& args, const std::string& hintDecl) { llvm::Function* calleeInfo = dyn_cast(__callee); if (calleeInfo){ auto argsFormal = calleeInfo->args(); int pos=0; //SECTIONTAG types/convert function ret value for (auto argFormal = argsFormal.begin(); argFormal!=argsFormal.end(); ++argFormal, ++pos){ args[pos] = doAutomaticTypeConversion(args[pos], argFormal->getType(), llvm->builder); } } return llvm->builder.CreateCall(__calleeTy, __callee, args, hintDecl); } //DESABLEDFEATURE implement inlining class CallStatementInline: public CallStatement{ public: CallStatementInline(FunctionUnit* caller, FunctionUnit* callee, LLVMLayer* l) : __caller(caller), __callee(callee), llvm(l) {} llvm::Value* operator() (std::vector&& args, const std::string& hintDecl) { //TOTEST inlining // CodeScopeUnit* entryCompilation = outer->getScopeUnit(function->__entry); // for(int i=0, size = args.size(); ibindArg(args.at(i), string(entryCompilation->scope->__bindings.at(i))); // } // // // return entryCompilation->compile(); return nullptr; } private: FunctionUnit* __caller; FunctionUnit* __callee; LLVMLayer* llvm; bool isInline(){ // Symbol ret = Symbol{0, function->__entry}; // bool flagOnTheFly = SymbolAttachments::get(ret, false); //TODO consider inlining return false; } }; -} - BasicCodeScopeUnit::BasicCodeScopeUnit(CodeScope* codeScope, FunctionUnit* f, CompilePass* compilePass) : AbstractCodeScopeUnit(codeScope, f, compilePass) {} llvm::Value* BasicCodeScopeUnit::processSymbol(const Symbol& s, std::string hintRetVar){ Expression declaration = CodeScope::getDeclaration(s); CodeScope* scope = s.scope; AbstractCodeScopeUnit* self = AbstractCodeScopeUnit::function->getScopeUnit(scope); return self->process(declaration, hintRetVar); } //SECTIONTAG late-context find callee function //TOTEST static late context decisions //TOTEST dynamic late context decisions CallStatement* BasicCodeScopeUnit::findFunction(const std::string& calleeName){ LLVMLayer* llvm = pass->man->llvm; ClaspLayer* clasp = pass->man->clasp; DefaultFunctionUnit* function = dynamic_cast(this->function); - ContextQuery* queryContext = pass->queryContext; + context::ContextQuery* queryContext = pass->queryContext; const std::list& specializations = pass->man->root->getFunctionVariants(calleeName); //if no specializations registered - check external function if (specializations.size()==0){ llvm::Function* external = llvm->layerExtern->lookupFunction(calleeName); llvm::outs() << "Debug/External function: " << calleeName; external->getType()->print(llvm::outs(), true); llvm::outs() << "\n"; return new CallStatementRaw(external, llvm); } //no decisions required if (specializations.size()==1){ if (!specializations.front()->guardContext.isValid()) { return new CallStatementRaw( pass->getFunctionUnit(specializations.front())->compile(), llvm); } } //TODO move dictSpecialization over to a separate function in order to perform cache, etc. //prepare specializations dictionary std::map dictSpecializations; boost::optional variantDefault; boost::optional variant; for(const ManagedFnPtr& f: specializations){ const Expression& guard = f->guardContext; //default case: if (!guard.isValid()){ variantDefault = f; continue; } assert(dictSpecializations.emplace(guard, f).second && "Found several identical specializations"); } //check static context ScopePacked scopeCaller = clasp->pack(this->scope); const string atomSpecialization = "specialization"; const Expression topicSpecialization(Operator::CALL, {(Atom(string(atomSpecialization))), (Atom(string(calleeName))), (Atom(scopeCaller))}); - const Decisions& decisions = queryContext->getFinalDecisions(scopeCaller); + const context::Decisions& decisions = queryContext->getFinalDecisions(scopeCaller); if (decisions.count(topicSpecialization)){ variant = dictSpecializations.at(decisions.at(topicSpecialization)); } //TODO check only demand for this particular topic. size_t sizeDemand = function->contextCompiler.getFunctionDemandSize(); //decision made if static context found or no late context exists(and there is default variant) bool flagHasStaticDecision = variant || (variantDefault && !sizeDemand); //if no late context exists if (flagHasStaticDecision) { FunctionUnit* calleeUnit = pass->getFunctionUnit(variant? *variant: *variantDefault); //inlining possible based on static decision only // if (calleeUnit->isInline()) { // return new CallStatementInline(function, calleeUnit); // } return new CallStatementRaw(calleeUnit->compile(), llvm); } //require default variant if no static decision made assert(variantDefault); llvm::Function* functionVariantDefault = this->pass->getFunctionUnit(*variantDefault)->compile(); llvm::Value* resultFn = function->contextCompiler.findFunction(calleeName, functionVariantDefault, scopeCaller); llvm::PointerType *resultPTy = cast(resultFn->getType()); llvm::FunctionType *resultFTy = cast(resultPTy->getElementType()); return new CallStatementRaw(resultFn, resultFTy, llvm); } //DISABLEDFEATURE transformations // if (pass->transformations->isAcceptable(expr)){ // return pass->transformations->transform(expr, result, ctx); // } llvm::Value* BasicCodeScopeUnit::process(const Expression& expr, const std::string& hintVarDecl){ #define DEFAULT(x) (hintVarDecl.empty()? x: hintVarDecl) llvm::Value *left; llvm::Value *right; LLVMLayer& l = *pass->man->llvm; xreate::compilation::Advanced instructions = xreate::compilation::Advanced({this, function, pass}); switch (expr.op) { case Operator::ADD: case Operator::SUB: case Operator::MUL: case Operator::DIV: case Operator::EQU: case Operator::LSS: case Operator::GTR: case Operator::NE: case Operator::LSE: case Operator::GTE: assert(expr.__state == Expression::COMPOUND); assert(expr.operands.size() == 2); left = process(expr.operands[0]); right = process(expr.operands[1]); //SECTIONTAG types/convert binary operation right = doAutomaticTypeConversion(right, left->getType(), l.builder); break; default:; } switch (expr.op) { case Operator::ADD:{ - llvm::Value* resultAdd = PointerArithmetic::add(left, right, {this, function, pass}, DEFAULT("tmp_add")); + llvm::Value* resultAdd = pointerarithmetic::PointerArithmetic::add(left, right, {this, function, pass}, DEFAULT("tmp_add")); if (resultAdd) {return resultAdd;} return l.builder.CreateAdd(left, right, DEFAULT("tmp_add")); break; } case Operator::SUB: return l.builder.CreateSub(left, right, DEFAULT("tmp_sub")); break; case Operator::MUL: return l.builder.CreateMul(left, right, DEFAULT("tmp_mul")); break; case Operator::DIV: return l.builder.CreateSDiv(left, right, DEFAULT("tmp_div")); break; case Operator::EQU: if (left->getType()->isIntegerTy()) return l.builder.CreateICmpEQ(left, right, DEFAULT("tmp_equ")); if (left->getType()->isFloatingPointTy()) return l.builder.CreateFCmpOEQ(left, right, DEFAULT("tmp_equ")); break; case Operator::NE: return l.builder.CreateICmpNE(left, right, DEFAULT("tmp_ne")); break; case Operator::LSS: return l.builder.CreateICmpSLT(left, right, DEFAULT("tmp_lss")); break; case Operator::LSE: return l.builder.CreateICmpSLE(left, right, DEFAULT("tmp_lse")); break; case Operator::GTR: return l.builder.CreateICmpSGT(left, right, DEFAULT("tmp_gtr")); break; case Operator::GTE: return l.builder.CreateICmpSGE(left, right, DEFAULT("tmp_gte")); break; case Operator::NEG: left = process(expr.operands[0]); return l.builder.CreateNeg(left, DEFAULT("tmp_neg")); break; case Operator::CALL: { assert(expr.__state == Expression::COMPOUND); std::string nameCallee = expr.getValueString(); shared_ptr callee(findFunction(nameCallee)); //prepare arguments std::vector args; args.reserve(expr.operands.size()); std::transform(expr.operands.begin(), expr.operands.end(), std::inserter(args, args.end()), [this](const Expression &operand) { return process(operand); } ); ScopePacked outerScopeId = pass->man->clasp->pack(this->scope); //TASK a) refactor CALL/ADHOC/find function //SECTIONTAG late-context propagation arg size_t calleeDemandSize = pass->queryContext->getFunctionDemand(nameCallee).size(); if (calleeDemandSize){ DefaultFunctionUnit* function = dynamic_cast(this->function); llvm::Value* argLateContext = function->contextCompiler.compileContextArgument(nameCallee, outerScopeId); args.push_back(argLateContext); } return (*callee)(move(args), DEFAULT("res_"+nameCallee)); } case Operator::IF: { return instructions.compileIf(expr, DEFAULT("tmp_if")); } case Operator::SWITCH: { return instructions.compileSwitch(expr, DEFAULT("tmp_switch")); } case Operator::LOOP_CONTEXT: { assert(false); return nullptr; //return instructions.compileLoopContext(expr, DEFAULT("tmp_loop")); } case Operator::LOGIC_AND: { assert(expr.operands.size() == 1); return process (expr.operands[0]); } case Operator::LIST: { return instructions.compileListAsSolidArray(expr, DEFAULT("tmp_list")); }; case Operator::LIST_RANGE: { assert(false); //no compilation phase for a range list // return InstructionList(this).compileConstantArray(expr, l, hintRetVar); }; case Operator::LIST_NAMED: { typedef Expanded ExpandedType; ExpandedType tyRaw = l.ast->expandType(expr.type); const std::vector fields = (tyRaw.get().__operator == TypeOperator::CUSTOM)? l.layerExtern->getStructFields(l.layerExtern->lookupType(tyRaw.get().__valueCustom)) : tyRaw.get().fields; std::map indexFields; for(size_t i=0, size = fields.size(); i(l.toLLVMType(tyRaw)); llvm::Value* record = llvm::UndefValue::get(tyRecord); for (size_t i=0; igetElementType(fieldId); // result = llvm::UndefValue::get(tyNullField); // // } else { result = process(operand); // } assert (result); record = l.builder.CreateInsertValue(record, result, llvm::ArrayRef({fieldId})); } return record; }; case Operator::MAP: { assert(expr.blocks.size()); return instructions.compileMapSolidOutput(expr, DEFAULT("map")); }; case Operator::FOLD: { return instructions.compileFold(expr, DEFAULT("fold")); }; case Operator::FOLD_INF: { return instructions.compileFoldInf(expr, DEFAULT("fold")); }; case Operator::INDEX: { //TODO allow multiindex assert(expr.operands.size()==2); assert(expr.operands[0].__state == Expression::IDENT); const std::string& hintIdent= expr.operands[0].getValueString(); Symbol s = Attachments::get(expr.operands[0]); const ExpandedType& t2 = pass->man->root->expandType(CodeScope::getDeclaration(s).type); llvm::Value* aggr = processSymbol(s, hintIdent); switch (t2.get().__operator) { case TypeOperator::STRUCT: case TypeOperator::CUSTOM: { const Expression& idx = expr.operands.at(1); assert(idx.__state == Expression::STRING); std::string idxField = idx.getValueString(); return instructions.compileStructIndex(aggr, t2, idxField); }; case TypeOperator::ARRAY: { std::vector indexes; std::transform(++expr.operands.begin(), expr.operands.end(), std::inserter(indexes, indexes.end()), [this] (const Expression& op){ return process(op); } ); return instructions.compileArrayIndex(aggr, indexes, DEFAULT(string("el_") + hintIdent)); }; default: assert(false); } }; //SECTIONTAG adhoc actual compilation //TODO a) make sure that it's correct: function->adhocImplementation built for Entry scope and used in another scope case Operator::ADHOC: { DefaultFunctionUnit* function = dynamic_cast(this->function); assert(function->adhocImplementation && "Adhoc implementation not found"); - const Expression& comm = AdhocExpression(expr).getCommand(); + const Expression& comm = adhoc::AdhocExpression(expr).getCommand(); CodeScope* scope = function->adhocImplementation->getCommandImplementation(comm); AbstractCodeScopeUnit* unitScope = function->getScopeUnit(scope); //SECTIONTAG types/convert ADHOC ret convertation llvm::Type* resultTy = l.toLLVMType( pass->man->root->expandType(function->adhocImplementation->getResultType())); return doAutomaticTypeConversion(unitScope->compile(), resultTy, l.builder); }; case Operator::CALL_INTRINSIC:{ const std::string op = expr.getValueString(); if (op == "copy") { llvm::Value* result = process(expr.getOperands().at(0)); auto decoratorVersions = Decorators::getInterface(this); llvm::Value* storage = decoratorVersions->processIntrinsicInit(result->getType()); decoratorVersions->processIntrinsicCopy(result, storage); return l.builder.CreateLoad(storage, hintVarDecl); } assert(false && "undefined intrinsic"); } case Operator::NONE: assert(expr.__state != Expression::COMPOUND); switch (expr.__state) { case Expression::IDENT: { Symbol s = Attachments::get(expr); return processSymbol(s, expr.getValueString()); } case Expression::NUMBER: { llvm::Type* typConst; if (expr.type.isValid()){ typConst = l.toLLVMType(pass->man->root->expandType(expr.type)); } else { typConst = llvm::Type::getInt32Ty(llvm::getGlobalContext()); } int literal = expr.getValueDouble(); return llvm::ConstantInt::get(typConst, literal); } case Expression::STRING: { return instructions.compileConstantStringAsPChar(expr.getValueString(), DEFAULT("tmp_str")); }; case Expression::VARIANT: { const ExpandedType& typVariant = pass->man->root->expandType(expr.type); llvm::Type* typRaw = l.toLLVMType(typVariant); int value = expr.getValueDouble(); return llvm::ConstantInt::get(typRaw, value); } default: { break; } }; break; default: break; } assert(false); return 0; } llvm::Value* BasicCodeScopeUnit::compile(const std::string& hintBlockDecl){ if (!hintBlockDecl.empty()) { llvm::BasicBlock *block = llvm::BasicBlock::Create(llvm::getGlobalContext(), hintBlockDecl, function->raw); pass->man->llvm->builder.SetInsertPoint(block); } Symbol symbScope = Symbol{ScopedSymbol::RetSymbol, scope}; return processSymbol(symbScope); } AbstractCodeScopeUnit::~AbstractCodeScopeUnit() {} FunctionUnit::~FunctionUnit() {} llvm::Function* FunctionUnit::compile(){ if (raw != nullptr) return raw; LLVMLayer* llvm = pass->man->llvm; llvm::IRBuilder<>& builder = llvm->builder; string&& functionName = prepareName(); std::vector&& types = prepareArguments(); llvm::Type* expectedResultType = prepareResult(); llvm::FunctionType *ft = llvm::FunctionType::get(expectedResultType, types, false); raw = llvm::cast(llvm->module->getOrInsertFunction(functionName, ft)); prepareBindings(); const std::string&blockName = "entry"; llvm::BasicBlock* blockCurrent = builder.GetInsertBlock(); llvm::Value* result =getScopeUnit(function->__entry)->compile(blockName); assert(result); //SECTIONTAG types/convert function ret value builder.CreateRet(doAutomaticTypeConversion(result, expectedResultType, llvm->builder)); if (blockCurrent){ builder.SetInsertPoint(blockCurrent); } llvm->moveToGarbage(ft); return raw; } AbstractCodeScopeUnit* FunctionUnit::getScopeUnit(CodeScope* scope){ if (__scopes.count(scope)) { auto result = __scopes.at(scope).lock(); if (result){ return result.get(); } } std::shared_ptr unit(new DefaultScopeUnit(scope, this, pass)); if (scope->__parent != nullptr){ auto parentUnit = Decorators::getInterface(getScopeUnit(scope->__parent)); parentUnit->registerChildScope(unit); } else { __orphanedScopes.push_back(unit); } if (!__scopes.emplace(scope, unit).second){ __scopes[scope] = unit; } return unit.get(); } AbstractCodeScopeUnit* FunctionUnit::getScopeUnit(ManagedScpPtr scope){ return getScopeUnit(&*scope); } AbstractCodeScopeUnit* FunctionUnit::getEntry(){ return getScopeUnit(function->getEntryScope()); } FunctionUnit* CompilePass::getFunctionUnit(const ManagedFnPtr& function){ unsigned int id = function.id(); if (!functions.count(id)){ FunctionUnit* unit = new DefaultFunctionUnit(function, this); functions.emplace(id, unit); return unit; } return functions.at(id); } void CompilePass::run(){ managerTransformations = new TransformationsManager(); - targetInterpretation = new TargetInterpretation(this->man->root, this); - queryContext = reinterpret_cast (man->clasp->getQuery(QueryId::ContextQuery)); + targetInterpretation = new interpretation::TargetInterpretation(this->man->root, this); + queryContext = reinterpret_cast (man->clasp->getQuery(QueryId::ContextQuery)); //Find out main function; ClaspLayer::ModelFragment model = man->clasp->query(Config::get("function-entry")); assert(model && "Error: No entry function found"); assert(model->first != model->second && "Error: Ambiguous entry function"); string nameMain = std::get<0>(ClaspLayer::parse(model->first->second)); FunctionUnit* unitMain = getFunctionUnit(man->root->findFunction(nameMain)); entry = unitMain->compile(); } llvm::Function* CompilePass::getEntryFunction(){ assert(entry); return entry; } void CompilePass::prepareQueries(ClaspLayer* clasp){ clasp->registerQuery(new containers::Query(), QueryId::ContainersQuery); - clasp->registerQuery(new ContextQuery(), QueryId::ContextQuery); + clasp->registerQuery(new context::ContextQuery(), QueryId::ContextQuery); } + +} //end of namespace xreate diff --git a/cpp/src/pass/compilepass.h b/cpp/src/pass/compilepass.h index 24b666a..38209d0 100644 --- a/cpp/src/pass/compilepass.h +++ b/cpp/src/pass/compilepass.h @@ -1,168 +1,166 @@ #ifndef COMPILEPASS_H #define COMPILEPASS_H #include "abstractpass.h" #include "llvm/IR/Function.h" namespace xreate { - class AdhocScheme; - class ClaspLayer; - class ContextQuery; - class LLVMLayer; + class ClaspLayer; + class CompilePass; + class LLVMLayer; + + namespace adhoc{ + class AdhocScheme; + } + + namespace context{ + class ContextQuery; + class LateContextCompiler2; + } + + namespace interpretation{ + class TargetInterpretation; + } } -//namespace llvm { -// class Function; -// class Value; -// class Type; -//} - -namespace xreate { - -class CompilePass; - -namespace compilation { +namespace xreate { namespace compilation { class AbstractCodeScopeUnit; class FunctionUnit; - -class TargetInterpretation; class TransformationsManager; - struct Context{ AbstractCodeScopeUnit* scope; FunctionUnit* function; CompilePass* pass; }; class CallStatement { public: virtual llvm::Value* operator() (std::vector&& args, const std::string& hintDecl="") = 0; }; class CallStatementRaw: public CallStatement{ public: CallStatementRaw(llvm::Function* callee, LLVMLayer* l) : __callee(callee), __calleeTy(callee->getFunctionType()), llvm(l) {} CallStatementRaw(llvm::Value* callee, llvm::FunctionType* ty, LLVMLayer* l) : __callee(callee), __calleeTy(ty), llvm(l) {} llvm::Value* operator() (std::vector&& args, const std::string& hintDecl=""); private: llvm::Value* __callee; llvm::FunctionType* __calleeTy; LLVMLayer* llvm; }; class AbstractCodeScopeUnit{ public: CompilePass* const pass; FunctionUnit* const function; CodeScope* const scope; AbstractCodeScopeUnit(CodeScope* codeScope, FunctionUnit* f, CompilePass* compilePass); virtual ~AbstractCodeScopeUnit(); virtual llvm::Value* compile(const std::string& hintBlockDecl="")=0; virtual llvm::Value* processSymbol(const Symbol& s, std::string hintRetVar="")=0; virtual llvm::Value* process(const Expression& expr, const std::string& hintVarDecl="")=0; virtual void bindArg(llvm::Value* value, std::string&& alias)=0; virtual void bindArg(llvm::Value* value, const ScopedSymbol& s)=0; protected: virtual CallStatement* findFunction(const std::string& callee)=0; }; class BasicCodeScopeUnit: public AbstractCodeScopeUnit{ public: BasicCodeScopeUnit(CodeScope* codeScope, FunctionUnit* f, CompilePass* compilePass); llvm::Value* processSymbol(const Symbol& s, std::string hintRetVar=""); llvm::Value* process(const Expression& expr, const std::string& hintVarDecl=""); llvm::Value* compile(const std::string& hintBlockDecl=""); protected: CallStatement* findFunction(const std::string& callee); }; class IFunctionDecorator { protected: virtual std::string prepareName() = 0; virtual std::vector prepareArguments() = 0; virtual llvm::Type* prepareResult() = 0; virtual llvm::Function::arg_iterator prepareBindings() = 0; virtual ~IFunctionDecorator(){} }; class FunctionUnit: public IFunctionDecorator{ public: FunctionUnit(ManagedFnPtr f, CompilePass* p) : function(f), pass(p) {} ~FunctionUnit(); llvm::Function* compile(); AbstractCodeScopeUnit* getEntry(); AbstractCodeScopeUnit* getScopeUnit(CodeScope* scope); AbstractCodeScopeUnit* getScopeUnit(ManagedScpPtr scope); ManagedFnPtr function; llvm::Function* raw = nullptr; protected: CompilePass* pass=nullptr; private: std::map> __scopes; std::list> __orphanedScopes; }; class BasicFunctionDecorator: public FunctionUnit{ public: BasicFunctionDecorator(ManagedFnPtr f, CompilePass* p) : FunctionUnit(f, p) {} protected: std::string prepareName(); virtual std::vector prepareArguments(); virtual llvm::Type* prepareResult(); virtual llvm::Function::arg_iterator prepareBindings(); }; } // end of namespace `xreate::compilation` class CompilePass : public AbstractPass { - friend class LateContextCompiler; - friend class LateContextCompiler2; + friend class context::LateContextCompiler2; friend class compilation::BasicCodeScopeUnit; friend class compilation::FunctionUnit; public: compilation::TransformationsManager* managerTransformations; - compilation::TargetInterpretation* targetInterpretation; + interpretation::TargetInterpretation* targetInterpretation; CompilePass(PassManager* manager): AbstractPass(manager) {} compilation::FunctionUnit* getFunctionUnit(const ManagedFnPtr& function); void run() override; llvm::Function* getEntryFunction(); static void prepareQueries(ClaspLayer* clasp); private: //TODO free `functions` in destructor std::map functions; llvm::Function* entry = 0; - ContextQuery* queryContext; + context::ContextQuery* queryContext; }; } #endif // COMPILEPASS_H diff --git a/cpp/src/pass/dfapass.cpp b/cpp/src/pass/dfapass.cpp index bee36eb..e64eeff 100644 --- a/cpp/src/pass/dfapass.cpp +++ b/cpp/src/pass/dfapass.cpp @@ -1,262 +1,262 @@ #include "pass/dfapass.h" #include "analysis/dfagraph.h" #include "xreatemanager.h" #include "clasplayer.h" #include using namespace std; -using namespace xreate::analysis; +namespace xreate { namespace dfa { -namespace xreate { +class DfaExpressionProcessor { + std::vector operands; + std::vector blocks; - class DfaExpressionProcessor { - std::vector operands; - std::vector blocks; + const Expression expression; + SymbolNode result; + DFAPass * const pass; + const PassContext context; - const Expression expression; - xreate::analysis::SymbolNode result; - DFAPass * const pass; - const PassContext context; +public: + DfaExpressionProcessor(const Expression& expr, SymbolNode resInitial, DFAPass * const p, const PassContext c) + : expression(expr), result(resInitial), pass(p), context(c) { - public: - DfaExpressionProcessor(const Expression& expr, SymbolNode resInitial, DFAPass * const p, const PassContext c) - : expression(expr), result(resInitial), pass(p), context(c) { + operands.reserve(expression.getOperands().size()); + for (const Expression &op : expression.getOperands()) { + SymbolAnonymous symbOp(op.id); - operands.reserve(expression.getOperands().size()); - for (const Expression &op : expression.getOperands()) { - SymbolAnonymous symbOp(op.id); - - operands.push_back(DfaExpressionProcessor(op, symbOp, pass, context).process()); - } - - blocks.reserve(expression.blocks.size()); - for (CodeScope* scope : expression.blocks) { - blocks.push_back(pass->process(scope, context)); - } + operands.push_back(DfaExpressionProcessor(op, symbOp, pass, context).process()); } - SymbolNode - process() { - if (expression.__state == Expression::COMPOUND) { - processCompoundOp(); - - } else { - processElementaryOp(); - } + blocks.reserve(expression.blocks.size()); + for (CodeScope* scope : expression.blocks) { + blocks.push_back(pass->process(scope, context)); + } + } - applySignatureAnnotations(); - applyInPlaceAnnotations(); + SymbolNode + process() { + if (expression.__state == Expression::COMPOUND) { + processCompoundOp(); - return result; + } else { + processElementaryOp(); } - private: - void - processElementaryOp() { - switch (expression.__state) { - case Expression::IDENT: - { - SymbolPacked symbFrom = pass->processSymbol(Attachments::get(expression), context, expression.getValueString()); - - SymbolPacked* symbTo = boost::get(&result); - if (symbTo) { - pass->__context.graph->addConnection(*symbTo, SymbolNode(symbFrom), DFGConnection::STRONG); + applySignatureAnnotations(); + applyInPlaceAnnotations(); - } else { - result = SymbolNode(symbFrom); - } + return result; + } - break; +private: + void + processElementaryOp() { + switch (expression.__state) { + case Expression::IDENT: + { + SymbolPacked symbFrom = pass->processSymbol(Attachments::get(expression), context, expression.getValueString()); + + SymbolPacked* symbTo = boost::get(&result); + if (symbTo) { + pass->__context.graph->addConnection(*symbTo, SymbolNode(symbFrom), DFGConnection::STRONG); + + } else { + result = SymbolNode(symbFrom); } - default: break; + break; } - } - void - processCompoundOp() { - switch (expression.op) { - - //DEBT provide CALL processing - // case Operator::CALL: { - // const string &nameCalleeFunction = expression.getValueString(); - // - // //TODO implement processFnCall/Uncertain - // list variantsCalleeFunction = man->root->getFunctionVariants(nameCalleeFunction); - // if (variantsCalleeFunction.size()!=1) return; - // ManagedFnPtr function= variantsCalleeFunction.front(); - // - // // set calling relations: - // CodeScope *scopeRemote = function->getEntryScope(); - // std::vector::iterator nodeActual = cache.operands.begin(); - // for (const std::string &identFormal: scopeRemote->__bindings){ - // const ScopedSymbol symbolFormal{scopeRemote->__identifiers.at(identFormal), VERSION_NONE}; - // - // __context.graph->addConnection(clasp->pack(Symbol{symbolFormal, scopeRemote}, nameCalleeFunction + ":" + identFormal), *nodeActual, DFGConnection::WEAK); - // ++nodeActual; - // } - // - // //TODO add RET connection - // break; - // } - - //MAP processing: apply PROTOTYPE relation - case Operator::MAP: - { - SymbolNode nodeFrom = operands.front(); - - SymbolPacked* nodeTo = boost::get(&result); - assert(nodeTo); - - pass->__context.graph->addConnection(*nodeTo, nodeFrom, DFGConnection::PROTOTYPE); - break; - } + default: break; + } + } - default: break; + void + processCompoundOp() { + switch (expression.op) { + + //DEBT provide CALL processing + // case Operator::CALL: { + // const string &nameCalleeFunction = expression.getValueString(); + // + // //TODO implement processFnCall/Uncertain + // list variantsCalleeFunction = man->root->getFunctionVariants(nameCalleeFunction); + // if (variantsCalleeFunction.size()!=1) return; + // ManagedFnPtr function= variantsCalleeFunction.front(); + // + // // set calling relations: + // CodeScope *scopeRemote = function->getEntryScope(); + // std::vector::iterator nodeActual = cache.operands.begin(); + // for (const std::string &identFormal: scopeRemote->__bindings){ + // const ScopedSymbol symbolFormal{scopeRemote->__identifiers.at(identFormal), VERSION_NONE}; + // + // __context.graph->addConnection(clasp->pack(Symbol{symbolFormal, scopeRemote}, nameCalleeFunction + ":" + identFormal), *nodeActual, DFGConnection::WEAK); + // ++nodeActual; + // } + // + // //TODO add RET connection + // break; + // } + + //MAP processing: apply PROTOTYPE relation + case Operator::MAP: + { + SymbolNode nodeFrom = operands.front(); + + SymbolPacked* nodeTo = boost::get(&result); + assert(nodeTo); + + pass->__context.graph->addConnection(*nodeTo, nodeFrom, DFGConnection::PROTOTYPE); + break; } + + default: break; } + } - void - applySignatureAnnotations() { - if (pass->__signatures.count(expression.op)) { - const Expression &scheme = pass->__signatures.at(expression.op); + void + applySignatureAnnotations() { + if (pass->__signatures.count(expression.op)) { + const Expression &scheme = pass->__signatures.at(expression.op); - std::vector::iterator arg = operands.begin(); - std::vector::const_iterator tag = scheme.getOperands().begin(); + std::vector::iterator arg = operands.begin(); + std::vector::const_iterator tag = scheme.getOperands().begin(); - //Assign scheme RET annotation - Expression retTag = *scheme.getOperands().begin(); - if (retTag.__state != Expression::INVALID) { - pass->__context.graph->addAnnotation(result, move(retTag)); + //Assign scheme RET annotation + Expression retTag = *scheme.getOperands().begin(); + if (retTag.__state != Expression::INVALID) { + pass->__context.graph->addAnnotation(result, move(retTag)); + } + + ++tag; + while (tag != scheme.getOperands().end()) { + if (tag->__state != Expression::INVALID) { + pass->__context.graph->addAnnotation(*arg, Expression(*tag)); } + ++arg; ++tag; - while (tag != scheme.getOperands().end()) { - if (tag->__state != Expression::INVALID) { - pass->__context.graph->addAnnotation(*arg, Expression(*tag)); - } - - ++arg; - ++tag; - } + } - // TODO add possibility to have specific signature for a particular function - // if (expression.op == Operator::CALL || expression.op == Operator::INDEX){ - // string caption = expression.getValueString(); - // operands.push_back(process(Expression(move(caption)), context, "")); - // } + // TODO add possibility to have specific signature for a particular function + // if (expression.op == Operator::CALL || expression.op == Operator::INDEX){ + // string caption = expression.getValueString(); + // operands.push_back(process(Expression(move(caption)), context, "")); + // } - } } + } - void - applyInPlaceAnnotations() { - // write down in-place expression tags: - for (pair tag : expression.tags) { - pass->__context.graph->addAnnotation(result, Expression(tag.second)); - } + void + applyInPlaceAnnotations() { + // write down in-place expression tags: + for (pair tag : expression.tags) { + pass->__context.graph->addAnnotation(result, Expression(tag.second)); } - }; + } +}; - DFAPass::DFAPass(PassManager* manager) +DFAPass::DFAPass(PassManager* manager) : AbstractPass(manager) - , __context{new xreate::analysis::DFAGraph(manager->clasp)} + , __context{new DFAGraph(manager->clasp)} , clasp(manager->clasp) - {} +{} - SymbolPacked - DFAPass::process(CodeScope* scope, PassContext context, const std::string& hintBlockDecl) { - const SymbolPacked& symbRet = AbstractPass::process(scope, context, hintBlockDecl); - return symbRet; - } +SymbolPacked +DFAPass::process(CodeScope* scope, PassContext context, const std::string& hintBlockDecl) { + const SymbolPacked& symbRet = AbstractPass::process(scope, context, hintBlockDecl); + return symbRet; +} - SymbolPacked - DFAPass::processSymbol(const Symbol& symbol, PassContext context, const std::string& hintSymbol) { - const Expression& declaration = CodeScope::getDeclaration(symbol); - const SymbolPacked& symbPacked = clasp->pack(symbol, hintSymbol); - DfaExpressionProcessor(declaration, symbPacked, this, context).process(); +SymbolPacked +DFAPass::processSymbol(const Symbol& symbol, PassContext context, const std::string& hintSymbol) { + const Expression& declaration = CodeScope::getDeclaration(symbol); + const SymbolPacked& symbPacked = clasp->pack(symbol, hintSymbol); + DfaExpressionProcessor(declaration, symbPacked, this, context).process(); - return symbPacked; - } + return symbPacked; +} - void - DFAPass::run() { - init(); - return AbstractPass::run(); - } +void +DFAPass::run() { + init(); + return AbstractPass::run(); +} - void - DFAPass::init() { - for (const Expression& scheme : man->root->__dfadata) { - __signatures.emplace(scheme.op, scheme); - } +void +DFAPass::init() { + for (const Expression& scheme : man->root->__dfadata) { + __signatures.emplace(scheme.op, scheme); } +} - void - DFAPass::finish() { - clasp->setDFAData(move(__context.graph)); - } +void +DFAPass::finish() { + clasp->setDFAData(move(__context.graph)); +} + +} //end of namespace dfa template<> SymbolPacked defaultValue(){ assert(false); } } //xreate namespace //DEBT represent VersionaPass in declarative form using applyDependencies // applyDependencies(expression, context, cache, decl); //DEBT prepare static annotations and represent InterpretationPass in declarative form // applyStaticAnnotations(expression, context, cache, decl); //TODO Null ad hoc DFG implementation/None symbol //DISABLEDFEATURE None value // if (expression.isNone()){ // return SymbolTransient{{Atom(Config::get("clasp.nonevalue"))}}; // } // non initialized(SymbolInvalid) value //void //DFAPass::applyDependencies(const Expression& expression, PassContext context, ExpressionCache& cache, const std::string& decl){ // for (SymbolNode &op: cache.operands) { // __context.graph->addDependencyConnection(cache.result, op); // } // // for (SymbolNode &block: cache.blocks) { // __context.graph->addDependencyConnection(cache.result, block); // } // // switch(expression.__state) { // case Expression::IDENT: { // SymbolNode identSymbol = clasp->pack(Attachments::get(expression), context.function->getName() + ":" + expression.getValueString()); // __context.graph->addDependencyConnection(cache.result, identSymbol); // } // // default: break; // } //} //void //DFAPass::applyStaticAnnotations(const Expression& expression, PassContext context, ExpressionCache& cache, const std::string& decl){ // // switch(expression.__state) { // case Expression::NUMBER: // case Expression::STRING: // __context.graph->addAnnotation(cache.result, Expression(Atom("static"))); // break; // // default: break; // } //} diff --git a/cpp/src/pass/dfapass.h b/cpp/src/pass/dfapass.h index 0bc50a4..5572eaa 100644 --- a/cpp/src/pass/dfapass.h +++ b/cpp/src/pass/dfapass.h @@ -1,39 +1,41 @@ // Data Flow Graph determination pass #ifndef DFGPASS_H #define DFGPASS_H #include "abstractpass.h" #include "analysis/dfagraph.h" namespace xreate { + class ClaspLayer; +} -class ClaspLayer; +namespace xreate { namespace dfa { class DfaExpressionProcessor; class DFAPass: public AbstractPass { friend class DfaExpressionProcessor; public: DFAPass(PassManager* manager); SymbolPacked processSymbol(const Symbol& symbol, PassContext context, const std::string& hintSymbol="") override; SymbolPacked process(CodeScope* scope, PassContext context, const std::string& hintBlockDecl="") override; void init(); void run() override; void finish() override; private: struct { - xreate::analysis::DFAGraph* graph; + DFAGraph* graph; } __context; std::map __signatures; //DFA data for particular operators ClaspLayer* clasp; }; -}; //end of xreate namespace +}} //end of xreate::dfa namespace #endif diff --git a/cpp/src/pass/interpretationpass.cpp b/cpp/src/pass/interpretationpass.cpp index f079129..2387463 100644 --- a/cpp/src/pass/interpretationpass.cpp +++ b/cpp/src/pass/interpretationpass.cpp @@ -1,416 +1,414 @@ /* * File: interpretationpass.cpp * Author: pgess * * Created on July 5, 2016, 5:21 PM */ #include "pass/interpretationpass.h" //#include "compilation/transformations.h" #include #include "ast.h" //DEBT implement InterpretationPass purely in clasp //DEBT represent InterpretationPass as general type inference using namespace std; namespace xreate{ +template<> +interpretation::InterpretationResolution +defaultValue(){ + return interpretation::CMPL_ONLY; +} + +namespace interpretation{ enum InterpretationQuery{QUERY_INTR_ONLY, QUERY_CMPL_ONLY}; -template<> -InterpretationResolution -defaultValue(){ - return CMPL_ONLY; +namespace details { + template + bool checkConstraints(InterpretationResolution flag) { + return ( (flag==INTR_ONLY && FLAG_REQUIRED == QUERY_INTR_ONLY) + || (flag==CMPL_ONLY && FLAG_REQUIRED == QUERY_CMPL_ONLY)); + } + + InterpretationResolution + recognizeTags(const map& tags){ + auto i = tags.find("interpretation"); + if (i== tags.end()){ + return ANY; + } + + assert(i->second.op == Operator::CALL); + const string& cmd = i->second.operands.at(0).getValueString(); + + //TODO make consistent names of annotation and resolution + if (cmd == "force"){ + return INTR_ONLY; + + } else if (cmd == "suppress"){ + return CMPL_ONLY; + } + + return ANY; + } } InterpretationResolution unify(InterpretationResolution flag) { return flag; } template InterpretationResolution unify(FLAG_A flagA, FLAG_B flagB, FLAGS... flags) { if (flagA== ANY){ return unify(flagB, flags...); } if (flagB == ANY) { return unify(flagA, flags...); } assert(flagA == flagB); return flagA; } -namespace detail { - template - bool checkConstraints(InterpretationResolution flag) { - return ( (flag==INTR_ONLY && FLAG_REQUIRED == QUERY_INTR_ONLY) - || (flag==CMPL_ONLY && FLAG_REQUIRED == QUERY_CMPL_ONLY)); - } -} - template bool checkConstraints(std::vector&& flags) { assert(flags.size()); InterpretationResolution flag = flags.front(); - return detail::checkConstraints(flag); + return details::checkConstraints(flag); } template bool checkConstraints(std::vector&& flags) { assert(flags.size()); InterpretationResolution flag = flags.front(); flags.pop_back(); - if (detail::checkConstraints(flag)){ + if (details::checkConstraints(flag)){ return checkConstraints(move(flags)); } return false; } bool InterpretationData::isDefault() const{ return (resolution == ANY && op == NONE); } -namespace details { - InterpretationResolution - recognizeTags(const map& tags){ - auto i = tags.find("interpretation"); - if (i== tags.end()){ - return ANY; - } - - assert(i->second.op == Operator::CALL); - const string& cmd = i->second.operands.at(0).getValueString(); - - //TODO make consistent names of annotation and resolution - if (cmd == "force"){ - return INTR_ONLY; - - } else if (cmd == "suppress"){ - return CMPL_ONLY; - } - - return ANY; - } -} - - void recognizeTags(const Expression& e){ InterpretationData tag{details::recognizeTags(e.tags), NONE}; if (!tag.isDefault()) Attachments::put(e, tag); } InterpretationResolution recognizeTags(const ManagedFnPtr& f){ return details::recognizeTags(f->getTags()); } InterpretationPass::InterpretationPass(PassManager* manager) : AbstractPass(manager) { Attachments::init(); Attachments::init(); } void InterpretationPass::run(){ ManagedFnPtr f = man->root->begin(); auto& visitedSymbols = getSymbolCache(); while (f.isValid()) { const Symbol& symbolFunction{ScopedSymbol::RetSymbol, f->getEntryScope()}; if (!visitedSymbols.isCached(symbolFunction)){ visitedSymbols.setCachedValue(symbolFunction, process(f)); } ++f; } } InterpretationResolution InterpretationPass::process(const Expression& expression, PassContext context, const std::string& decl){ recognizeTags(expression); InterpretationResolution resolution = ANY; InterpretationOperator op = NONE; switch (expression.__state){ case Expression::VARIANT: case Expression::NUMBER: case Expression::STRING: { break; } case Expression::IDENT: { resolution = Parent::processSymbol(Attachments::get(expression), context); break; } case Expression::COMPOUND: break; default: { resolution = CMPL_ONLY; break;} } if (expression.__state == Expression::COMPOUND) switch(expression.op){ case Operator::EQU: case Operator::NE: { InterpretationResolution left = process(expression.operands[0], context); InterpretationResolution right = process(expression.operands[1], context); resolution = unify(left, right); break; } case Operator::LOGIC_AND: { assert(expression.operands.size() == 1); resolution = process (expression.operands[0], context); break; } case Operator::CALL: { //TODO cope with static/dynamic context //TODO BUG here: if several variants they all are processed as CMPL careless of signature list callees = man->root->getFunctionVariants(expression.getValueString()); if (callees.size()!=1){ resolution = CMPL_ONLY; break; } ManagedFnPtr callee = callees.front(); const Symbol& symbCalleeFunc{ScopedSymbol::RetSymbol, callee->getEntryScope()}; //recursion-aware processing: // - skip self recursion const Symbol& symbSelfFunc{ScopedSymbol::RetSymbol, context.function->getEntryScope()}; if (!(symbSelfFunc == symbCalleeFunc)){ InterpretationResolution resCallee = processFnCall(callee, context); assert(resCallee != FUNC_POSTPONED && "Indirect recursion detected: can't decide on interpretation resolution"); resolution = unify(resolution, resCallee); } //check arguments compatibility const FunctionInterpretationData& calleeSignature = FunctionInterpretationHelper::getSignature(callee); for (size_t op=0, size = expression.operands.size(); op < size; ++op){ const Expression &operand = expression.operands[op]; InterpretationResolution argActual = process(operand, context); InterpretationResolution argExpected = calleeSignature.signature[op]; //TODO use args unification result to properly process function call unify(argActual, argExpected); } if (FunctionInterpretationHelper::needPartialInterpretation(callee)){ op= CALL_INTERPRET_PARTIAL; } break; } case Operator::IF:{ InterpretationResolution flagCondition = process(expression.getOperands()[0], context); InterpretationResolution flagScope1 = Parent::process(expression.blocks.front(), context); InterpretationResolution flagScope2 = Parent::process(expression.blocks.back(), context); //special case: IF_INTERPRET_CONDITION if (checkConstraints({flagCondition})){ op= IF_INTERPRET_CONDITION; flagCondition = ANY; } resolution = unify(flagCondition, flagScope1, flagScope2); break; } case Operator::FOLD: { InterpretationResolution flagInput = process(expression.getOperands()[0], context); InterpretationResolution flagAccumInit = process(expression.getOperands()[1], context); CodeScope* scopeBody = expression.blocks.front(); const std::string& nameEl = expression.bindings[0]; Symbol symbEl{ScopedSymbol{scopeBody->__identifiers.at(nameEl), VERSION_NONE}, scopeBody}; getSymbolCache().setCachedValue(symbEl, InterpretationResolution(flagInput)); const std::string& nameAccum = expression.bindings[1]; Symbol symbAccum{ScopedSymbol{scopeBody->__identifiers.at(nameAccum), VERSION_NONE}, scopeBody}; getSymbolCache().setCachedValue(symbAccum, InterpretationResolution(flagAccumInit)); InterpretationResolution flagBody = Parent::process(expression.blocks.front(), context); //special case: FOLD_INTERPRET_INPUT if (checkConstraints({flagInput})){ op= FOLD_INTERPRET_INPUT; flagInput = ANY; } resolution = unify(flagInput, flagAccumInit, flagBody); break; } case Operator::INDEX: { resolution = unify( process(expression.operands[0], context), process(expression.operands[1], context) ); break; } case Operator::SWITCH: { InterpretationResolution flagCondition = process(expression.operands[0], context); bool hasDefaultCase = expression.operands[1].op == Operator::CASE_DEFAULT; //determine conditions resolution InterpretationResolution flagHeaders = flagCondition; for (size_t size = expression.operands.size(), i= hasDefaultCase? 2: 1; i({flagHeaders})){ op= SWITCH_INTERPRET_CONDITION; flagHeaders = ANY; } //determine body resolutions resolution = flagHeaders; for (size_t size = expression.operands.size(), i= 1; i(expression, {ANY, NONE}).resolution; resolution = unify(resolution, resolutionExpected); if (resolution != resolutionExpected && (op!=NONE || resolution == INTR_ONLY)){ Attachments::put(expression, {resolution, op}); } return resolution; } InterpretationResolution InterpretationPass::processFnCall(ManagedFnPtr function, PassContext context){ return process(function); } InterpretationResolution InterpretationPass::process(ManagedFnPtr function){ CodeScope* entry = function->getEntryScope(); std::vector arguments = entry->__bindings; const Symbol& symbSelfFunc{ScopedSymbol::RetSymbol, function->getEntryScope()}; auto& cache = getSymbolCache(); if (cache.isCached(symbSelfFunc)) return cache.getCachedValue(symbSelfFunc); const FunctionInterpretationData& fnSignature = FunctionInterpretationHelper::getSignature(function); InterpretationResolution fnResolutionExpected = details::recognizeTags(function->getTags()); //mark preliminary function resolution as expected if (fnResolutionExpected != ANY){ cache.setCachedValue(symbSelfFunc, move(fnResolutionExpected)); } else { // - in order to recognize indirect recursion mark this function resolution as POSTPONED cache.setCachedValue(symbSelfFunc, FUNC_POSTPONED); } //set resolution for function arguments as expected for (int argNo = 0, size = arguments.size(); argNo< size; ++argNo){ Symbol symbArg{ScopedSymbol{entry->__identifiers.at(arguments[argNo]), VERSION_NONE}, entry}; cache.setCachedValue(symbArg, InterpretationResolution(fnSignature.signature[argNo])); } PassContext context; context.function = function; context.scope = entry; InterpretationResolution resActual = process(CodeScope::getDeclaration(symbSelfFunc), context); resActual = unify(resActual, fnResolutionExpected); return cache.setCachedValue(symbSelfFunc, move(resActual)); } const FunctionInterpretationData FunctionInterpretationHelper::getSignature(ManagedFnPtr function){ if (Attachments::exists(function)){ return Attachments::get(function); } FunctionInterpretationData&& data = recognizeSignature(function); Attachments::put(function, data); return data; } FunctionInterpretationData FunctionInterpretationHelper::recognizeSignature(ManagedFnPtr function){ CodeScope* entry = function->__entry; FunctionInterpretationData result; result.signature.reserve(entry->__bindings.size()); bool flagPartialInterpretation = false; for(size_t no=0, size=entry->__bindings.size(); no < size; ++no){ const std::string& argName = entry->__bindings[no]; Symbol symbArg{ScopedSymbol{entry->__identifiers.at(argName), VERSION_NONE}, entry}; const Expression& arg = CodeScope::getDeclaration(symbArg); InterpretationResolution argResolution = details::recognizeTags(arg.tags); flagPartialInterpretation |= (argResolution == INTR_ONLY); result.signature.push_back(argResolution); } result.flagPartialInterpretation = flagPartialInterpretation; return result; } bool FunctionInterpretationHelper::needPartialInterpretation(ManagedFnPtr function){ const FunctionInterpretationData& data = getSignature(function); return data.flagPartialInterpretation; } -} +}} //end of namespace xreate::interpretation diff --git a/cpp/src/pass/interpretationpass.h b/cpp/src/pass/interpretationpass.h index a6434e6..e418055 100644 --- a/cpp/src/pass/interpretationpass.h +++ b/cpp/src/pass/interpretationpass.h @@ -1,80 +1,85 @@ /* * File: interpretationpass.h * Author: pgess * * Created on July 5, 2016, 5:21 PM */ #ifndef INTERPRETATIONPASS_H #define INTERPRETATIONPASS_H #include "abstractpass.h" #include -namespace xreate { - +#ifndef FRIENDS_INTERPRETATION_TESTS +#define FRIENDS_INTERPRETATION_TESTS +#endif + +namespace xreate{ namespace interpretation{ enum InterpretationResolution{ANY, INTR_ONLY, CMPL_ONLY, FUNC_POSTPONED}; enum InterpretationOperator{NONE, IF_INTERPRET_CONDITION, FOLD_INTERPRET_INPUT, SWITCH_INTERPRET_CONDITION, CALL_INTERPRET_PARTIAL}; - + struct InterpretationData{ InterpretationResolution resolution; InterpretationOperator op; bool isDefault() const; }; - template<> - InterpretationResolution - defaultValue(); - struct FunctionInterpretationData{ typedef std::vector Signature; Signature signature; bool flagPartialInterpretation; }; - template<> - struct AttachmentsDict - { - typedef FunctionInterpretationData Data; - static const unsigned int key = 5; - }; - class FunctionInterpretationHelper { public: static const FunctionInterpretationData getSignature(ManagedFnPtr function); static bool needPartialInterpretation(ManagedFnPtr function); private: static FunctionInterpretationData recognizeSignature(ManagedFnPtr function); }; - template<> - struct AttachmentsDict - { - typedef InterpretationData Data; - static const unsigned int key = 3; - }; - class InterpretationPass: public AbstractPass { typedef AbstractPass Parent; public: InterpretationResolution process(const Expression& expression, PassContext context, const std::string& varDecl="") override; InterpretationResolution process(ManagedFnPtr function); InterpretationResolution processFnCall(ManagedFnPtr function, PassContext context); InterpretationPass(PassManager* manager); void run(); }; namespace details { InterpretationResolution recognizeTags(const std::map& tags); } -} +} //end of namespace interpretation + +template<> +interpretation::InterpretationResolution +defaultValue(); + +template<> +struct AttachmentsDict +{ + typedef interpretation::FunctionInterpretationData Data; + static const unsigned int key = 5; +}; + +template<> +struct AttachmentsDict +{ + typedef interpretation::InterpretationData Data; + static const unsigned int key = 3; +}; + +} //end of namespace xreate #endif /* INTERPRETATIONPASS_H */ diff --git a/cpp/src/pass/versionspass.cpp b/cpp/src/pass/versionspass.cpp index 65c6853..734ee66 100644 --- a/cpp/src/pass/versionspass.cpp +++ b/cpp/src/pass/versionspass.cpp @@ -1,377 +1,366 @@ /* * versionspass.cpp * * Author: pgess * Created on January 4, 2017, 3:13 PM */ #include #include "pass/versionspass.h" namespace std{ std::size_t - hash::operator()(xreate::SymbolOrPlaceholder const& s) const + hash::operator()(xreate::versions::SymbolOrPlaceholder const& s) const {return std::hash()(s.symbol) + (s.flagEndOfLifePlaceholder? 9849 : 1);} bool - equal_to::operator()(const xreate::SymbolOrPlaceholder& __x, const xreate::SymbolOrPlaceholder& __y) const + equal_to::operator()(const xreate::versions::SymbolOrPlaceholder& __x, const xreate::versions::SymbolOrPlaceholder& __y) const { return __x.flagEndOfLifePlaceholder == __y.flagEndOfLifePlaceholder && __x.symbol == __y.symbol; } - - size_t - hash::operator()(xreate::Symbol const& s) const{ - return hash()(s.identifier) ^ ((long int) s.scope << 1); - } - - bool - equal_to::operator()(const xreate::Symbol& __x, const xreate::Symbol& __y) const{ - return __x == __y; - }; } using namespace std; -namespace xreate { +namespace xreate{ namespace versions{ template<> std::list defaultValue>(){ return std::list(); }; inline std::string printSymbol(const SymbolOrPlaceholder& s){ switch(s.flagEndOfLifePlaceholder){ case SYMBOL: return string("(") + std::to_string(s.symbol.identifier.id) + ", "+ std::to_string(s.symbol.identifier.version) + ")"; case PLACEHOLDER: return string("(") + std::to_string(s.symbol.identifier.id) + ", "+ std::to_string(s.symbol.identifier.version) + ")+"; } return ""; } void VersionsGraph::__debug_print(std::ostream& output) const{ for(auto entry: __inferiors){ output << printSymbol(entry.second) << " <-" << printSymbol(entry.first) << "\n"; } } void VersionsGraph::defineEndOfLife(const Symbol& symbol, const Symbol& symbolSuccessor){ if(__dictSuccessors.count(symbol)){ assert("No version branches allowed yet" && false); } const SymbolOrPlaceholder& placeholder = getEndOfLife(symbol); auto inferiorsDeferred = __inferiors.equal_range(placeholder); std::unordered_multimap inferiorsReassigned; for (const auto& inf: boost::make_iterator_range(inferiorsDeferred)){ inferiorsReassigned.emplace(SymbolOrPlaceholder{SYMBOL, symbolSuccessor}, inf.second); } __inferiors.erase(placeholder); __inferiors.insert(inferiorsReassigned.begin(), inferiorsReassigned.end()); __inferiors.emplace(SymbolOrPlaceholder{SYMBOL, symbolSuccessor}, SymbolOrPlaceholder{SYMBOL, symbol}); __dictSuccessors.emplace(symbol, symbolSuccessor); } SymbolOrPlaceholder VersionsGraph::getEndOfLife(const Symbol& s){ if (__dictSuccessors.count(s)){ return SymbolOrPlaceholder{SYMBOL, __dictSuccessors.at(s)}; } return SymbolOrPlaceholder{PLACEHOLDER, s}; } void VersionsGraph::applyNatualDependencies(const Symbol& symbol, const std::list& dependencies){ for (const Symbol& right: dependencies){ __inferiorsNatural.emplace(symbol, right); } } void VersionsGraph::applyDependentEndOfLife(const SymbolOrPlaceholder& symbol, const list& dependencies){ for (const Symbol& right: dependencies){ auto rightEOF = getEndOfLife(right); __inferiors.emplace(rightEOF, symbol); } } bool VersionsGraph::tryEliminateEofAliases(const std::list& aliases){ if (aliases.size()==1){ return true; } boost::optional symbolActualEoF; for(const SymbolOrPlaceholder alias: aliases){ switch(alias.flagEndOfLifePlaceholder){ case SYMBOL: if(symbolActualEoF){ return false; } symbolActualEoF = alias.symbol; break; case PLACEHOLDER: continue; } } if(!symbolActualEoF){ return false; } for(const SymbolOrPlaceholder alias: aliases){ switch(alias.flagEndOfLifePlaceholder){ case SYMBOL: continue; case PLACEHOLDER: defineEndOfLife(alias.symbol, symbolActualEoF.get()); break; } } return true; } std::list VersionsGraph::extractCycle(const Path& path, const SymbolOrPlaceholder& symbolBeginning){ unsigned int posBeginning = path.at(symbolBeginning); std::list result; auto i=path.begin(); while(true){ i = std::find_if(i, path.end(), [&posBeginning](const auto& el){return el.second >=posBeginning;}); if (i!= path.end()){ result.push_back(i->first); ++i; } else {break; } } return result; } - bool VersionsGraph::validateCycles(const SymbolOrPlaceholder& s, std::unordered_multimap& graph, std::unordered_set& symbolsVisited, Path& path) { if (symbolsVisited.count(s)) return true; symbolsVisited.insert(s); path.emplace(s, path.size()); if (graph.count(s)){ //iterate over imposed dependencies auto candidates = graph.equal_range(s); for (auto candidate = candidates.first; candidate != candidates.second; ++candidate){ if (path.count(candidate->second)) { std::list cycle = extractCycle(path, candidate->second); if (!tryEliminateEofAliases(cycle)) return false; continue; } if(!validateCycles(candidate->second, graph, symbolsVisited, path)) return false; } } //iterate over natural dependencies if (s.flagEndOfLifePlaceholder == SYMBOL) { auto candidates = __inferiorsNatural.equal_range(s.symbol); for (auto candidate = candidates.first; candidate != candidates.second; ++candidate){ if (path.count(SymbolOrPlaceholder{SYMBOL, candidate->second})){ return false; } if(!validateCycles(SymbolOrPlaceholder{SYMBOL,candidate->second}, graph, symbolsVisited, path)) return false; } } //check previous version if (s.flagEndOfLifePlaceholder == PLACEHOLDER){ const Symbol& candidate = s.symbol; if (path.count(SymbolOrPlaceholder{SYMBOL, candidate})){ std::list cycle = extractCycle(path, SymbolOrPlaceholder{SYMBOL, candidate}); if (!tryEliminateEofAliases(cycle)) return false; } if(!validateCycles(SymbolOrPlaceholder{SYMBOL,candidate}, graph, symbolsVisited, path)) return false; } path.erase(s); return true; } bool VersionsGraph::validateCycles(){ std::unordered_set symbolsVisited; Path path; std::unordered_multimap graph(__inferiors); std::unordered_multimap::const_iterator s; for (s = graph.begin(); s != graph.end(); ++s){ if(!validateCycles(s->first, graph, symbolsVisited, path)) return false; } return true; } bool VersionsGraph::validate(){ return validateCycles(); } std::list VersionsGraph::expandPlaceholder(const SymbolOrPlaceholder& symbol, const Symbol& symbolPrev) const{ std::list result; switch (symbol.flagEndOfLifePlaceholder){ case SYMBOL: //skip self-loops if (symbol.symbol == symbolPrev) return {}; return {symbol.symbol}; case PLACEHOLDER: for (const auto& entry: boost::make_iterator_range(__inferiors.equal_range(symbol))){ list&& childResult = expandPlaceholder(entry.second, symbolPrev); result.insert(result.end(), childResult.begin(), childResult.end()); } if (__dictSuccessors.count(symbol.symbol)){ Symbol knownSuccessor = __dictSuccessors.at(symbol.symbol); //skip alias loop if (knownSuccessor == symbolPrev) return {}; for (const auto& entry: boost::make_iterator_range(__inferiors.equal_range(SymbolOrPlaceholder{SYMBOL, knownSuccessor}))){ list&& childResult = expandPlaceholder(entry.second, knownSuccessor); result.insert(result.end(), childResult.begin(), childResult.end()); } } break; } return result; } AttachmentsContainerDefault>* VersionsGraph::representAsAttachments() const { AttachmentsContainerDefault>* container = new AttachmentsContainerDefault>(); std::map> containerData; for(const auto& entry: __inferiors){ if(entry.first.flagEndOfLifePlaceholder == PLACEHOLDER) continue; list& infs = containerData[entry.first.symbol]; list&& infsExpanded = expandPlaceholder(entry.second, entry.first.symbol); infs.insert(infs.begin(), infsExpanded.begin(), infsExpanded.end()); } for(const auto& entry: containerData){ container->put(entry.first, entry.second); } return container; } std::list VersionsPass::process(const Expression& expression, PassContext context, const std::string& hintSymbol){ if (expression.__state == Expression::COMPOUND){ std::list resultDependencies; for (const Expression &op: expression.getOperands()) { std::list deps = process(op, context); resultDependencies.insert(resultDependencies.end(), deps.begin(), deps.end()); } for (CodeScope* scope: expression.blocks) { std::list deps = Parent::process(scope, context); resultDependencies.insert(resultDependencies.end(), deps.begin(), deps.end()); } return resultDependencies; } if (expression.__state == Expression::IDENT){ const Symbol symb = Attachments::get(expression); return processSymbol(symb, context, expression.getValueString()); } return {}; } //TODO versions, check (declaration.isDefined()) before processing declaration list VersionsPass::processSymbol(const Symbol& symbol, PassContext context, const std::string& hintSymbol){ list result{symbol}; if (__symbolsVisited.exists(symbol)){ return result; } enum {MODE_ALIAS, MODE_COPY } mode = MODE_ALIAS; const Expression& declaration = CodeScope::getDeclaration(symbol); if (declaration.op == Operator::CALL_INTRINSIC){ if (declaration.getValueString() == "copy"){ mode = MODE_COPY; } } if (symbol.identifier.version != VERSION_NONE){ mode = MODE_COPY; if (symbol.identifier.version > 0){ Symbol versionPrev = Symbol{ScopedSymbol{symbol.identifier.id, symbol.identifier.version-1}, symbol.scope}; __graph.defineEndOfLife(versionPrev, symbol); } } PassContext context2 = context.updateScope(symbol.scope); std::list dependencies = process(declaration, context2, hintSymbol); switch (mode) { case MODE_COPY: __graph.applyDependentEndOfLife(SymbolOrPlaceholder{SYMBOL, symbol}, dependencies); break; case MODE_ALIAS: __graph.applyDependentEndOfLife(__graph.getEndOfLife(symbol), dependencies); break; } __graph.applyNatualDependencies(symbol, dependencies); __symbolsVisited.put(symbol, true); return list{symbol}; } VersionsGraph& VersionsPass::getResultGraph(){ return __graph; } void VersionsPass::finish(){ assert(__graph.validate() && "Can't validate versions graph"); Attachments::init(__graph.representAsAttachments()); } -} \ No newline at end of file +}} //end of namespace xreate::versions \ No newline at end of file diff --git a/cpp/src/pass/versionspass.h b/cpp/src/pass/versionspass.h index e13c62b..e60b2de 100644 --- a/cpp/src/pass/versionspass.h +++ b/cpp/src/pass/versionspass.h @@ -1,115 +1,107 @@ /* * File: versionspass.h * Author: v.melnychenko@xreate.org * * Created on January 4, 2017, 3:09 PM */ #ifndef VERSIONSPASS_H #define VERSIONSPASS_H #include "pass/abstractpass.h" #include #include -namespace xreate { - - enum PlaceholderFlag {SYMBOL, PLACEHOLDER}; - - struct SymbolOrPlaceholder { - PlaceholderFlag flagEndOfLifePlaceholder; - Symbol symbol; - }; - - -} namespace std { - - template<> - struct hash{ - std::size_t operator()(xreate::SymbolOrPlaceholder const& s) const; - }; +namespace xreate { namespace versions { + struct SymbolOrPlaceholder; +}} +namespace std { template<> - struct equal_to{ - bool operator()(const xreate::SymbolOrPlaceholder& __x, const xreate::SymbolOrPlaceholder& __y) const; + struct hash{ + std::size_t operator()(xreate::versions::SymbolOrPlaceholder const& s) const; }; template<> - struct hash{ - size_t operator()(xreate::Symbol const& s) const; + struct equal_to{ + bool operator()(const xreate::versions::SymbolOrPlaceholder& __x, const xreate::versions::SymbolOrPlaceholder& __y) const; }; +} - template<> - struct equal_to{ - bool operator()(const xreate::Symbol& __x, const xreate::Symbol& __y) const; - }; +namespace xreate { namespace versions { -} namespace xreate { +enum PlaceholderFlag {SYMBOL, PLACEHOLDER}; -struct VersionImposedDependency{}; - -template<> -struct AttachmentsDict -{ - typedef std::list Data; - static const unsigned int key = 8; +struct SymbolOrPlaceholder { + PlaceholderFlag flagEndOfLifePlaceholder; + Symbol symbol; }; + +struct VersionImposedDependency{}; class VersionsGraph{ public: //processing API: void applyNatualDependencies(const Symbol& symbol, const std::list& dependencies); void applyDependentEndOfLife(const SymbolOrPlaceholder& symbol, const std::list& dependencies); void defineEndOfLife(const Symbol& symbol, const Symbol& symbolSuccessor); SymbolOrPlaceholder getEndOfLife(const Symbol& s); bool validate(); //examination API: AttachmentsContainerDefault>* representAsAttachments() const; void __debug_print(std::ostream& output) const; private: typedef std::unordered_map Path; std::unordered_multimap __inferiorsNatural; std::unordered_multimap __inferiors; std::unordered_map __dictSuccessors; std::list expandPlaceholder(const SymbolOrPlaceholder& symbol, const Symbol& symbolPrev) const; std::list extractCycle(const Path& path, const SymbolOrPlaceholder& symbolBeginning); bool tryEliminateEofAliases(const std::list& aliases); bool validateCycles(); bool validateCycles(const SymbolOrPlaceholder& s, std::unordered_multimap& graph, std::unordered_set& symbolsVisited, Path& path); }; -template<> -std::list -defaultValue>(); - class VersionsPass: public AbstractPass> { typedef AbstractPass> Parent; public: VersionsPass(PassManager* manager): AbstractPass>(manager){} std::list process(const Expression& expression, PassContext context, const std::string& hintSymbol="") override; VersionsGraph& getResultGraph(); virtual void finish(); protected: std::list processSymbol(const Symbol& symbol, PassContext context, const std::string& hintSymbol="") override; private: VersionsGraph __graph; AttachmentsContainerDefault __symbolsVisited; }; -} //end of xreate +}} //end of xreate::versions +namespace xreate{ + template<> + std::list + defaultValue>(); + + template<> + struct AttachmentsDict + { + typedef std::list Data; + static const unsigned int key = 8; + }; +} #endif /* VERSIONSPASS_H */ diff --git a/cpp/src/query/context.cpp b/cpp/src/query/context.cpp index 76d7b05..3697073 100644 --- a/cpp/src/query/context.cpp +++ b/cpp/src/query/context.cpp @@ -1,207 +1,207 @@ /* * adhoc.cpp * * Created on: Dec 1, 2015 * Author: pgess */ #include #include #include using namespace std; -namespace xreate { +namespace xreate { namespace context { const Domain domainEmpty; const Decisions decisionsEmpty; const FunctionDemand functionDemandEmpty; ContextQuery::ContextQuery(){} const Domain& ContextQuery::getContext(const ScopePacked& scopeId) const{ if (!__modelContext.count(scopeId)){ return domainEmpty; } return __modelContext.at(scopeId); } const Domain& ContextQuery::getContext(CodeScope* const scope) const{ return getContext(clasp->pack(scope)); } //DEBT compatibility of forced context with context resolution for interpretation void ContextQuery::forceContext(const ScopePacked& scopeId, std::list context){ // TODO remove forced context of the same class/type only, possibly //remove any previous forced context for this scopeId //__modelForcedContext.erase(scopeId); //TASK restore forceContext //std::multimap __modelForcedContext; /* std::transform(context.begin(), context.end(), inserter(__modelForcedContext, __modelForcedContext.end()), [scopeId](const Expression& context){return make_pair(scopeId, context);}); */ } void ContextQuery::init(ClaspLayer* clasp){ const std::string& atomBinding = Config::get("clasp.bindings.scope"); this->clasp = clasp; ClaspLayer::ModelFragment query = clasp->query(atomBinding); //static context if (query){ map> dictContext; for (auto i = query->first; i!=query->second; ++i){ ScopePacked idScope; Expression context; std::string link; tie(idScope, context, link) = ClaspLayer::parse(i->second); if (link == "strong") { dictContext[idScope].push_back(context); } } for (map>::value_type& entry: dictContext){ __modelContext.insert(move(entry)); } } prepareFunctionDemandModel(); prepareDecisionModels(); } void ContextQuery::prepareFunctionDemandModel(){ const std::string& atomFunctionDemand = Config::get("clasp.bindings.function_demand"); ClaspLayer::ModelFragment query = clasp->query(atomFunctionDemand); if (query) for (auto i = query->first; i!=query->second; ++i){ string function; Expression topic; tie(function, topic) = ClaspLayer::parse(i->second); FunctionDemand& demand = __modelFunctionDemand[function]; demand.left.insert(make_pair(demand.left.size(), topic)); } } void ContextQuery::prepareDecisionModels(){ const std::string& atomDecision = Config::get("clasp.bindings.scope_decision"); const std::string& atomDependentDecision = Config::get("clasp.context.decisions.dependent"); std::multimap modelDomains; ClaspLayer::ModelFragment query = clasp->query(atomDecision); if (query){ for (auto i = query->first; i!=query->second; ++i){ ScopePacked scopeId; Expression topic; Expression decision; std::tie(scopeId, topic, decision) = ClaspLayer::parse(i->second); if (decision.getValueString() == atomDependentDecision) { assert(decision.operands.size() == 2); const Expression& decisionGuard = decision.operands[1]; const Expression& decisionValue = decision.operands[0]; __modelDependentDecisions[scopeId][topic].emplace(decisionGuard, decisionValue); modelDomains.emplace(topic, decisionValue); } else { Decisions& decisionsOfScope = __modelStaticDecisions[scopeId]; assert(decisionsOfScope.emplace(topic, decision).second && "Possibly more than one decision"); modelDomains.emplace(topic, decision); } } } //populate topic domains: auto adapter = [](const std::pair& p){ return p.second; }; auto iBegin = modelDomains.begin(); while (iBegin!=modelDomains.end()){ const Expression topic = iBegin->first; auto iEnd = modelDomains.upper_bound(topic); auto iBeginAdapted = boost::make_transform_iterator(iBegin,adapter); auto iEndAdapted = boost::make_transform_iterator(iEnd,adapter); Domain dom(iBeginAdapted, iEndAdapted); __modelTopicDomains.emplace(topic, move(dom)); iBegin = iEnd; } } const FunctionDemand& ContextQuery::getFunctionDemand(const std::string& name) const { if (__modelFunctionDemand.count(name)){ return __modelFunctionDemand.at(name); } return functionDemandEmpty; } const Decisions& ContextQuery::getFinalDecisions(const ScopePacked& scopeId) const{ if (__modelStaticDecisions.count(scopeId)){ return __modelStaticDecisions.at(scopeId); } return decisionsEmpty; } const Domain& ContextQuery::getTopicDomain(const Expression& topic) const{ if (__modelTopicDomains.count(topic)){ return __modelTopicDomains.at(topic); } return domainEmpty; } const DependentDecision& ContextQuery::getDependentDecision(ScopePacked scope, const Expression& topic) const{ auto itDecisionsAllTopics = __modelDependentDecisions.find(scope); if (itDecisionsAllTopics != __modelDependentDecisions.end()){ auto itDecisions = itDecisionsAllTopics->second.find(topic); if (itDecisions != itDecisionsAllTopics->second.end()){ return itDecisions->second; } } return decisionsEmpty; } // const std::string& atomLateBinding = Config::get("clasp.bindings.function_uncertain"); // query = clasp->query(atomLateBinding); // // std::map> dictFunctionDomain; // if (query){ // for (auto i = query->first; i!=query->second; ++i){ // string nameFunction; // Expression context; // tie(nameFunction, context) = ClaspLayer::parse(i->second); // dictFunctionDomain.at(nameFunction).push_back(context); // } // // for(auto& entry: dictFunctionDomain){ // __modelFunctionDomain.emplace(entry.first, move(entry.second)); // } // } -} /* namespace xreate */ +}} /* namespace xreate::context */ diff --git a/cpp/src/query/context.h b/cpp/src/query/context.h index 8dd6858..3fc0240 100644 --- a/cpp/src/query/context.h +++ b/cpp/src/query/context.h @@ -1,95 +1,95 @@ /* * adhoc.h * * Created on: Dec 1, 2015 * Author: pgess */ #ifndef SRC_QUERY_CONTEXT_H_ #define SRC_QUERY_CONTEXT_H_ #include "clasplayer.h" #include "ast.h" #include "serialization.h" #include #include #include #include #include #include -namespace xreate { +namespace xreate{ namespace context{ typedef ExpressionSerialization::Serializer Domain; typedef boost::bimap FunctionDemand; typedef std::map Decisions; typedef std::map DependentDecision; class ContextQuery: public IQuery { //AdhocQuery(); public: const Domain& getContext(const ScopePacked& scopeId) const; const Domain& getContext(CodeScope* const scope) const; void forceContext(const ScopePacked& scopeId, std::list context); const Domain& getTopicDomain(const Expression& topic) const; const DependentDecision& getDependentDecision(ScopePacked scope, const Expression& topic) const; const FunctionDemand& getFunctionDemand(const std::string& name) const; const Decisions& getFinalDecisions(const ScopePacked& scopeId) const; virtual void init(ClaspLayer* clasp); ContextQuery(); virtual ~ContextQuery(){}; private: ClaspLayer* clasp; std::map __modelContext; std::map __modelFunctionDemand; std::map __modelStaticDecisions; std::map __modelTopicDomains; std::map> __modelDependentDecisions; void prepareFunctionDemandModel(); void prepareDecisionModels(); }; -} /* namespace xreate */ +}} // namespace xreate::context */ /* template class ContextAttachments: private std::unordered_map { typedef std::unordered_map PARENT; public: ContextAttachments(ContextAttachments&& other) : PARENT(std::move(other)), domain(std::move(other.domain)) {} ContextAttachments(std::vector&& expressions, std::vector&& attachments) : domain(move(expressions)) { size_t size = domain.size(); for (size_t i=0; i FunctionSpecializations ; */ #endif /* SRC_QUERY_CONTEXT_H_ */ diff --git a/cpp/tests/adhoc.cpp b/cpp/tests/adhoc.cpp index 710fd4e..d088cd0 100644 --- a/cpp/tests/adhoc.cpp +++ b/cpp/tests/adhoc.cpp @@ -1,194 +1,195 @@ /* * adhoc-exceptions.cpp * * Created on: Nov 19, 2015 * Author: pgess */ class Adhoc_pass_Adhoc1_Test; #define FRIENDS_ADHOC \ friend class ::Adhoc_pass_Adhoc1_Test; #include "ast.h" #include "xreatemanager.h" #include "gtest/gtest.h" #include #include #include #include #include "pass/adhocpass.h" #include "pass/compilepass.h" #include "llvmlayer.h" using namespace xreate; +using namespace xreate::adhoc; using namespace std; TEST(Adhoc, ast_operatorAdhoc1){ XreateManager* man = XreateManager::prepare ( "test = function:: int {\n" " ad hoc exception(nonImplemented)\n" "}"); Expression subject = man->root->findFunction("test")->getEntryScope()->getBody(); ASSERT_EQ(Operator::ADHOC, subject.op); Expression exception = AdhocExpression(subject).getCommand(); ASSERT_EQ("exception", exception.getValueString()); } TEST(Adhoc, ast_schemeAdhoc1){ XreateManager* man = XreateManager::prepare ( "interface(adhoc){\n" " pre function expectNoErrors:: bool {\n" " case (Error) {false}\n" " case (Success) {true}\n" " }\n" " }"); assert(man->root->__interfacesData.count(ASTInterface::Adhoc)); Expression adhocData = man->root->__interfacesData.find(ASTInterface::Adhoc)->second; ASSERT_EQ(Operator::SWITCH, adhocData.operands[0].op); } TEST(Adhoc, pass_Adhoc1){ details::tier1::XreateManager* man = details::tier1::XreateManager::prepare ( "interface(adhoc){\n" " pre function expectNoErrors:: bool {\n" " case (Error) {false}\n" " case (Success) {true}\n" " }\n" "}\n" "main = function::int; entry {0} \n" ); man->analyse(); AdhocPass* pass = reinterpret_cast(man->getPassById(PassId::AdhocPass)); EXPECT_TRUE(pass->__schemes.size() > 0); AdhocScheme* scheme = pass->__schemes.begin()->second; EXPECT_EQ("expectNoErrors", scheme->getName()); } TEST(Adhoc, full_1){ XreateManager* man = XreateManager::prepare ( " import raw (\"core/control-context.lp\").\n" " interface(adhoc){\n" " pre function expectNoErrors:: bool {\n" " case (error) {false}\n" " case (success) {true}\n" " }\n" " }\n" " test1 = pre function {\n" " context:: expectNoErrors." " ad hoc success\n" " }" "main = function::bool;entry {\n" " test1()\n" " }"); bool (*main)() = (bool (*)()) man->run(); bool result = main(); ASSERT_EQ(true, result); } TEST(Adhoc, full_2){ XreateManager* man = XreateManager::prepare ( " import raw (\"core/control-context.lp\").\n" " interface(adhoc){\n" " pre function expectNoErrors:: bool {\n" " case (error) {false}\n" " case (success) {true}\n" " }\n" " pre function expectErrors:: bool {\n" " case (error) {true}\n" " case (success) {false}\n" " }\n" " }\n" " test1 = pre function {\n" " context:: expectNoErrors." " ad hoc success\n" " }\n" " test2 = pre function {\n" " context:: expectErrors." " ad hoc success\n" " }" "main = function::bool;entry {\n" " test1() != test2()\n" "}"); bool (*main)() = (bool (*)()) man->run(); bool result = main(); ASSERT_EQ(true, result); } //TODO adhoc type. FDecl sets wrong type in prefunc case(invalid type)) TEST(Adhoc, full_contextExpectNoErrrors){ XreateManager* man = XreateManager::prepare ( "import raw (\"core/control-context.lp\").\n" "interface(extern-c){\n" " xml2 = library:: pkgconfig(\"libxml-2.0\").\n" " \n" " include {\n" " xml2 = [\"stdlib.h\"]\n" " }.\n" "}" "interface(adhoc){\n" " pre function expectNoErrors:: bool {\n" " case (error) {false}\n" " case (success) {true}\n" " }\n" "}\n" "expectErrorCode = pre function(x::int){\n" " if (x==0)::undef {ad hoc success}\n" " else {ad hoc error}\n" "}\n" "main = function::bool; entry {\n" " context:: expectNoErrors." " expectErrorCode(system(\"ls -la\"))\n" "}" ); int (*main)() = (int (*)()) man->run(); ASSERT_EQ(1, main()); } //DEBT Implement compilation of switch adhoc TEST(Adhoc, ast_switchAdhoc1){ XreateManager* man = XreateManager::prepare ( "test1 = function:: bool {\n" " x = 0. \n" " switch ad hoc (x:: errors)\n" " case (error) {0}\n" " case (success) {1}\n" "\n" "}" ); Expression eSwitch = man->root->findFunction("test1")->getEntryScope()->getBody(); EXPECT_EQ(Operator::SWITCH_ADHOC, eSwitch.op); EXPECT_EQ(3, eSwitch.operands.size()); EXPECT_EQ(1, eSwitch.tags.size()); EXPECT_EQ("errors", eSwitch.tags.begin()->first); Expression eCondition = eSwitch.getOperands()[0]; EXPECT_EQ("x", eCondition.getValueString()); } \ No newline at end of file diff --git a/cpp/tests/ast.cpp b/cpp/tests/ast.cpp index 0720184..193b68a 100644 --- a/cpp/tests/ast.cpp +++ b/cpp/tests/ast.cpp @@ -1,68 +1,69 @@ /* * ast.cpp * * Created on: Jun 11, 2015 * Author: pgess */ #include "gtest/gtest.h" #include "xreatemanager.h" #include "main/Parser.h" using namespace std; +using namespace xreate; using namespace xreate::grammar::main; TEST(AST, Containers1){ - FILE* input = fopen("scripts/containers/Containers_Implementation_LinkedList1.xreate","r"); - Scanner scanner(input); + FILE* input = fopen("scripts/containers/Containers_Implementation_LinkedList1.xreate","r"); + Scanner scanner(input); Parser parser(&scanner); parser.Parse(); assert(!parser.errors->count && "Parser errors"); fclose(input); } TEST(AST, InterfacesDataCFA) { XreateManager* man = XreateManager::prepare ("interface(cfa){\n" " operator map :: annotation1.\n" "}"); auto answer = man->root->__interfacesData.equal_range(CFA); EXPECT_EQ(1, std::distance(answer.first, answer.second)); Expression&& scheme = move(answer.first->second); EXPECT_EQ(Operator::MAP, scheme.op); EXPECT_EQ("annotation1", scheme.getOperands().at(0).getValueString()); } TEST(AST, syntax_recognizeIdentifiers){ XreateManager* man = XreateManager::prepare(R"Code( test= function(a:: num):: num; entry { a = b:: int. b = 8:: int. a } )Code"); } TEST(AST, syntax_operatorIndex){ XreateManager* man = XreateManager::prepare(R"Code( test= function(a:: num):: num; entry { b = a[1]. b } )Code"); } TEST(AST, DISABLED_InterfacesDataDFA){ } TEST(AST, DISABLED_InterfacesDataExtern){ } //TODO xreate.atg: replace all Type<> as ExprAnnotations<> diff --git a/cpp/tests/cfa.cpp b/cpp/tests/cfa.cpp index 5d4f84a..37912d3 100644 --- a/cpp/tests/cfa.cpp +++ b/cpp/tests/cfa.cpp @@ -1,119 +1,120 @@ /* * testsCFG.cpp * * Created on: Jul 17, 2015 * Author: pgess */ #include "xreatemanager.h" #include "pass/dfapass.h" #include "pass/cfapass.h" #include "analysis/DominatorsTreeAnalysisProvider.h" #include "gtest/gtest.h" #include #include using namespace xreate; +using namespace xreate::cfa; using namespace std; TEST(CFA, testFunctionAnnotationsClasp){ string&& program = "f2 = function::int; annotationF2 {\n" " 0\n" "}\n" "\n" "f1 = function:: int; entry; annotationF1 {\n" " f2() + 10\n" "}"; details::tier1::XreateManager* man = details::tier1::XreateManager::prepare(move(program)); man->analyse(); ClaspLayer::ModelFragment answer = man->clasp->query("annotationF1"); int countNoneValue = 0; if (answer) countNoneValue = std::distance(answer->first, answer->second); EXPECT_EQ(1, countNoneValue); answer = man->clasp->query("annotationF2"); countNoneValue = 0; if (answer) countNoneValue = std::distance(answer->first, answer->second); EXPECT_EQ(1, countNoneValue); } TEST(CFA, testLoopContextExists){ details::tier1::XreateManager* man = details::tier1::XreateManager::prepare ( "interface(cfa){\n" " operator fold:: annotation1.\n" "}\n" "\n" "main = function:: int; entry {\n" " x = [1..10]:: [int].\n" " sum = loop fold (x->el:: int, 0->sum):: int {\n" " el + sum + f1()\n" " }. \n" " sum\n" "}" "case context:: annotation1 {" " f1 = function::int {\n" " x = 0:: int. " " x\n" " }" "}" ); man->analyse(); ClaspLayer::ModelFragment model = man->clasp->query("annotation1"); ScopePacked scopeIdActual = std::get<0>(ClaspLayer::parse(model->first->second)); CodeScope* scopeEntry = man->root->findFunction("main")->getEntryScope(); const Expression& exprSum = scopeEntry->getDeclaration(scopeEntry->getSymbol("sum")); CodeScope* scopeExpected = exprSum.blocks.front(); ScopePacked scopeIdExpected = man->clasp->pack(scopeExpected); ASSERT_EQ(scopeIdExpected, scopeIdActual); } TEST(CFA, CFGRoots){ std::string program = R"CODE( main = function::int{a()+ b()} a= function::int {c1() + c2()} b= function::int {c2()} c1=function::int{0} c2=function::int{0} )CODE"; boost::scoped_ptr manager (XreateManager::prepare(move(program))); manager->registerPass(new CFAPass(manager.get()) , PassId::CFGPass); manager->executePasses(); manager->clasp->run(); - DominatorsTreeAnalysisProvider domProvider; + dominators::DominatorsTreeAnalysisProvider domProvider; domProvider.run(manager->clasp); - DominatorsTreeAnalysisProvider::Dominators expectedFDom= { + dominators::DominatorsTreeAnalysisProvider::Dominators expectedFDom= { {0, {0, 9}} ,{1, {1, 4}} ,{2, {7, 8}} ,{3, {2, 3}} ,{4, {5, 6}} }; - DominatorsTreeAnalysisProvider::Dominators expectedPostDom= { + dominators::DominatorsTreeAnalysisProvider::Dominators expectedPostDom= { {0, {5, 6}} ,{1, {3, 4}} ,{2, {8, 9}} ,{3, {1, 2}} ,{4, {7, 10}} }; ASSERT_EQ(expectedFDom, domProvider.getForwardDominators()); ASSERT_EQ(expectedPostDom, domProvider.getPostDominators()); } diff --git a/cpp/tests/containers.cpp b/cpp/tests/containers.cpp index 75fbfc5..f49d209 100644 --- a/cpp/tests/containers.cpp +++ b/cpp/tests/containers.cpp @@ -1,109 +1,110 @@ /* * containers.cpp * * Created on: Jun 9, 2015 * Author: pgess */ #include "xreatemanager.h" #include "query/containers.h" #include "main/Parser.h" #include "gtest/gtest.h" using namespace std; using namespace xreate::grammar::main; using namespace xreate::containers; +using namespace xreate; TEST(Containers, ListAsArray){ XreateManager* man = XreateManager::prepare( R"Code( main = function(x:: int):: int;entry { a = [1, 2, 3]:: [int]. a[x] } )Code" ); void* mainPtr = man->run(); int (*main)(int) = (int (*)(int))mainPtr; ASSERT_EQ(2, main(1)); delete man; } TEST(Containers, ListAsArray2){ XreateManager* man = XreateManager::prepare( R"Code( // CONTAINERS interface(dfa) { operator map:: (op(seqaccess)) -> impl(solid). operator list_range:: ()->impl(on_the_fly). operator list:: ()->impl(solid). operator fold:: (op(seqaccess)). operator index:: (op(randaccess)). } import raw("core/containers.lp"). main = function:: int;entry { a= [1, 2, 3]:: [int]. b= loop map(a->el:: int):: [int]{ 2 * el }. sum = loop fold(b->el:: int, 0->acc):: int { acc + el }. sum } )Code" ); void* mainPtr = man->run(); int (*main)() = (int (*)())mainPtr; ASSERT_EQ(12, main()); delete man; } TEST(Containers, ContanierLinkedList1){ FILE* input = fopen("scripts/containers/Containers_Implementation_LinkedList1.xreate","r"); assert(input != nullptr); Scanner scanner(input); Parser parser(&scanner); parser.Parse(); AST* ast = parser.root->finalize(); CodeScope* body = ast->findFunction("test")->getEntryScope(); const Symbol symb_chilrenRaw{body->getSymbol("childrenRaw"), body}; containers::ImplementationLinkedList iLL(symb_chilrenRaw); ASSERT_EQ(true, static_cast(iLL)); ASSERT_EQ("next", iLL.fieldPointer); Implementation impl = Implementation::create(symb_chilrenRaw); ASSERT_NO_FATAL_FAILURE(impl.extract()); ImplementationRec recOnthefly = impl.extract(); ASSERT_EQ(symb_chilrenRaw, recOnthefly.source); } TEST(Containers, Implementation_LinkedListFull){ FILE* input = fopen("scripts/containers/Containers_Implementation_LinkedList1.xreate","r"); assert(input != nullptr); std::unique_ptr program(XreateManager::prepare(input)); void* mainPtr = program->run(); int (*main)() = (int (*)())(intptr_t)mainPtr; int answer = main(); ASSERT_EQ(17, answer); fclose(input); } diff --git a/cpp/tests/context.cpp b/cpp/tests/context.cpp index 92b19fc..98dc389 100644 --- a/cpp/tests/context.cpp +++ b/cpp/tests/context.cpp @@ -1,494 +1,495 @@ /* * frame-context.cpp * * Created on: Dec 3, 2015 * Author: pgess */ #include "xreatemanager.h" #include "query/context.h" #include "gtest/gtest.h" #include #include using namespace xreate; +using namespace xreate::context; TEST(Context, frame_Context1){ details::tier1::XreateManager* man = details::tier1::XreateManager::prepare( " import raw (\"core/control-context.lp\").\n" " compute = function::int {\n" " 0\n" " }\n" " computeFast = function:: int {\n" " context:: computation(fast).\n" " compute()\n" " }\n" " computePrecisely = function:: int {\n" " context:: computation(precise). \n" " compute()\n" " }\n" "test = function(cmnd:: int):: int; entry {\n" " context:: arithmetic(iee754). \n" " if (cmnd > 0)::int {computePrecisely()} else {computeFast()} \n" "}\n" ); ContextQuery* query = (ContextQuery*) man->clasp->registerQuery(new ContextQuery(), QueryId::ContextQuery); man->analyse(); CodeScope* scopeTestC = man->root->findFunction("compute")->getEntryScope(); const Domain& context = query->getContext(man->clasp->pack(scopeTestC)); int contextSize = context.size(); EXPECT_EQ(1, contextSize); //arithmetic(iee754) } TEST(Context, contextAsRequirementSuccessful1){ XreateManager* man = XreateManager::prepare( " import raw (\"core/control-context.lp\").\n" " case context::safe {\n" " funcSensitive = function::int {\n" " 0\n" " }}\n" " test = function:: int; entry {\n" " context:: safe; test.\n" " funcSensitive()\n" " }\n" ); int (*main)() = (int (*)()) man->run(); ASSERT_EQ(0, main()); } TEST(Context, contextAsRequirementFailed){ XreateManager* man = XreateManager::prepare( " import raw (\"core/control-context.lp\").\n" " case context::safe {\n" " funcSensitive = function::int {\n" " 0\n" " }}\n" " test = function:: int; entry {\n" " context:: non_safe; test.\n" " funcSensitive()\n" " }\n" ); ASSERT_DEATH(man->run(), "findFunction"); } TEST(Context, ContextPropagationNested){ XreateManager* man = XreateManager::prepare( " import raw (\"core/control-context.lp\").\n" " case context::safe {\n" " square = function(x:: int) ::int {\n" " x * x\n" " }}\n" " test = function:: int; entry {\n" " context:: safe; test.\n" " range = [1..10]:: [int]. \n" " loop fold(range->x::int, 0->acc):: int { \n" " acc + square(x) \n" " } \n" " }\n" ); int (*main)() = (int (*)()) man->run(); ASSERT_EQ(385, main()); } TEST(Context, ContextPropagationNestedInterfunction){ XreateManager* man = XreateManager::prepare( " import raw (\"core/control-context.lp\").\n" " case context::toMillimeters {\n" " convertConcrete = function(source:: num)::num {\n" " 10 * source \n" " }\n" " }\n" " case context::toInches {\n" " convertConcrete = function(source:: num)::num {\n" " 2 * source \n" " }\n" " }\n" "convert= function(source:: num):: num { \n" "convertConcrete(source) \n" "} \n" "test = function(source:: num):: num; entry {\n" " context:: toMillimeters.\n" " convert(1)\n" "}\n" ); int (*main)(int) = (int (*)(int)) man->run(); ASSERT_EQ(10, main(1)); } TEST(Context, full_ContextBasedFunctionSpecialization){ XreateManager* man = XreateManager::prepare( " import raw (\"core/control-context.lp\").\n" " case context::toMillimeters {\n" " convert = function(source:: num)::num {\n" " 10 * source \n" " }\n" " }\n" " case context::toInches {\n" " convert = function(source:: num)::num {\n" " 2 * source \n" " }\n" " }\n" "test = function(vrnt:: int)::int; entry {\n" " switch(vrnt):: int\n" " case (0) {\n" " context:: toMillimeters.\n" " convert(1)\n" " }\n" "\n" " case (1) {\n" " context:: toInches.\n" " convert(1)\n" " }\n" " case default {0}\n" " }" ); int (*main)(int) = (int (*)(int)) man->run(); ASSERT_EQ(10, main(0)); ASSERT_EQ(2, main(1)); } TEST(Context, full_RuleContext){ /* "rule context:: childs(Child)\n" " case artefact(Item)\n" " {\n" " artefact_depends(Item, Child)\n" " }"; */ XreateManager* man = XreateManager::prepare( " import raw (\"core/control-context.lp\").\n" " case context:: toMilli {\n" " convert = function(length::int)::int{\n" " 10 * length\n" " }\n" " }\n" "\n" " case context:: toCenti {\n" " convert = function(length::int)::int{\n" " length\n" " }\n" " }\n" "\n" " main=function::int; entry {\n" " context:: output(milli).\n" "\n" " rule context::toMilli\n" " case (output(milli)) {truth}\n" "\n" " convert(1)\n" " }" ); man->clasp->addRawScript("truth."); int (*entry)() = (int (*)()) man->run(); ASSERT_EQ(10, entry()); } TEST(Context, full_InheritedRuleContext){ XreateManager* man = XreateManager::prepare( " import raw (\"core/control-context.lp\"). \n" " case context:: toMilli {\n" " convert = function(length::int)::int{\n" " 10 * length\n" " }\n" " }\n" " case context:: toCenti {\n" " convert = function(length::int)::int{\n" " length\n" " }\n" " }\n" "\n" "main = function(comm:: num)::num; entry{\n" " rule context::X case (output(X)) {truth}\n" "\n" " switch (comm)::num \n" " case (0) {\n" " context:: output(toMilli).\n" " convert(1)\n" " }\n" " case default {\n" " context:: output(toCenti).\n" " convert(1)\n" " }\n" " }"); man->clasp->addRawScript("truth."); int (*entry)(int) = (int (*)(int)) man->run(); ASSERT_EQ(10, entry(0)); ASSERT_EQ(1, entry(1)); } TEST(Context, full_LateContext){ details::tier1::XreateManager* man = details::tier1::XreateManager::prepare( "import raw (\"core/control-context.lp\").\n" " convert = function(length:: num)::num{\n" " 0\n" " }\n" "case context:: milli {\n" " convert = function(length:: num)::num{\n" " 1000 * length\n" " }\n" "}\n" "\n" "case context:: centi {\n" " convert = function(length:: num)::num{\n" " 100 * length\n" " }\n" "}\n" "\n" "calculate = function(length:: num)::num {\n" " convert(length)\n" "}\n" "\n" "main = function(com:: num):: num; entry {\n" " switch (com):: num \n" " case (0) {\n" " context:: milli.\n" " calculate(1)\n" " }\n" "\n" " case default{\n" " context:: centi. \n" " calculate(1)\n" " }\n" "}"); man->analyse(); ContextQuery* queryContext = reinterpret_cast(man->clasp->getQuery(QueryId::ContextQuery)); Expression exprSwitch = man->root->findFunction("main")->__entry->getBody(); CodeScope* blockDefault = man->root->findFunction("main")->__entry->getBody().operands[1].blocks.front(); ScopePacked blockDefaultId = man->clasp->pack(blockDefault); const Domain& domDefault = queryContext->getContext(blockDefaultId); ASSERT_EQ(1, domDefault.count(Expression(Atom("centi")))); std::list variants = man->root->getFunctionVariants("convert"); for (ManagedFnPtr f: variants){ const Expression guard = f->guardContext; bool result = (guard.getValueString() == "centi" || guard.getValueString() == "milli" || !guard.isValid()); ASSERT_TRUE(result); } const FunctionDemand& demMain = queryContext->getFunctionDemand("main"); ASSERT_EQ(0, demMain.size()); const FunctionDemand& demCalculate = queryContext->getFunctionDemand("calculate"); ASSERT_EQ(1, demCalculate.size()); int (*entry)(int) = (int (*)(int)) man->run(); ASSERT_EQ(1000, entry(0)); ASSERT_EQ(100, entry(1)); } TEST(Context, loopContextExists){ XreateManager* man = XreateManager::prepare ( "import raw (\"core/control-context.lp\").\n" "interface(cfa){\n" " operator fold:: annotation1.\n" "}\n" "\n" "main = function:: int; entry {\n" " x = [1..10]:: [int].\n" " sum = loop fold (x->el:: int, 0->sum):: int {\n" " el + sum + f1()\n" " }. \n" " sum\n" "}" "case context:: annotation1 {" " f1 = function::int {\n" " x = 0:: int. " " x\n" " }" "}" ); man->run(); } TEST(Context, pathDependentContext){ std::string program = R"CODE( import raw("core/control-context.lp"). convert = function(length:: num) :: num { 0 } case context:: convert(milli, meters) { convert = function(length:: num) :: num { 1000 * length } } case context:: convert(centi, meters) { convert = function(length:: num) :: num { 100 * length } } case context:: convert(centi, kilo) { convert = function(length:: num) :: num { 100000 * length } } case context:: convert(milli, kilo) { convert = function(length:: num) :: num { 1000000 * length } } main = function(value::num, unitsInput::num, unitsOutput::num)::num; entry{ switch (unitsInput)::num case (0) { test_fromMilli(value, unitsOutput) } case (1) { test_fromCenti(value, unitsOutput) } case default {0} } test_fromCenti = function(value::num, output::num)::num{ context:: input(centi). switch(output):: num case (0) { toMeters(value) } case (1) { toKilo(value) } case default {0} } test_fromMilli = function(value::num, output::num)::num{ context:: input(milli). switch(output):: num case (0) { toMeters(value) } case (1) { toKilo(value) } case default {0} } toMeters = function(value::num)::num { rule context:: convert(X, meters) case (input(X)) {truth} doConvert(value) } toKilo = function(value::num)::num { rule context:: convert(X, kilo) case (input(X)) {truth} doConvert(value) } doConvert = function(value::num)::num{ convert(value) })CODE"; boost::scoped_ptr man(details::tier1::XreateManager::prepare(move(program))); man->clasp->addRawScript("truth."); man->analyse(); int (*test)(int, int, int) = (int (*)(int, int, int))man->run(); enum {INPUT_MILLI, INPUT_CENTI}; enum {OUTPUT_METERS, OUTPUT_KILO}; ASSERT_EQ(1000000, test(1, INPUT_MILLI, OUTPUT_KILO)); ASSERT_EQ(200, test(2, INPUT_CENTI, OUTPUT_METERS)); } //TODO recover context loop and enable the test TEST(Context, DISABLED_full_LoopContext){ XreateManager* man = XreateManager::prepare( " import raw (\"core/control-context.lp\")\n" " case context:: a {\n" " print = function:: string {\n" " \"a\"\n" " }}\n" "\n" " case context:: b {\n" " print = function:: string {\n" " \"b\"\n" " }}\n" "\n" " case context:: c {\n" " print = function:: string {\n" " \"c\"\n" " }}\n" "\n" " case context:: d {\n" " print = function:: string {\n" " \"d\"\n" " }}\n" "\n" " start = function(command::int)::string; entry {\n" " switch (command) :: string \n" " case (0) {\n" " context:: print(a); print(b); print(d).\n" "\n" " loop context (\"print\") {\n" " print()\n" " }\n" " }\n" "\n" " case default {\n" " context:: print(c).\n" " loop context (\"print\") {\n" " print()\n" " }\n" " }\n" " }"); char* (*main)(int) =(char* (*)(int)) man->run(); ASSERT_STREQ("c", main(1)); ASSERT_STREQ("a", main(0)); } \ No newline at end of file diff --git a/cpp/tests/effects-versions.cpp b/cpp/tests/effects-versions.cpp index 95e22c7..6f2687d 100644 --- a/cpp/tests/effects-versions.cpp +++ b/cpp/tests/effects-versions.cpp @@ -1,276 +1,277 @@ /* * Created on: Dec 16, 2016 * Author: pgess */ #include "pass/versionspass.h" #include "xreatemanager.h" #include "gtest/gtest.h" using namespace xreate; +using namespace xreate::versions; TEST(Effects, syntax_versions_1){ XreateManager* man = XreateManager::prepare(R"Code( test= function(a:: num):: num; entry { x= b[8]. b = 5:: num. x{1} = a:: num. x{1} + a } )Code"); } TEST(Effects, analysis_versions_1){ XreateManager* man = XreateManager::prepare( R"Code( test= function:: num; entry { x{0}= 3:: int. x{1} = x{0} + 1. x{1} } )Code"); VersionsPass* pass = new VersionsPass(man); pass->run(); VersionsGraph graph = pass->getResultGraph(); ASSERT_TRUE(graph.validate()); } TEST(Effects, analysis_versions_2){ XreateManager* man = XreateManager::prepare( R"Code( test= function(a:: num):: num; entry { x{0}= 3:: int. b = [1, 2, x{0}]. x{1} = b[2]. x{1} + a } )Code"); VersionsPass* pass = new VersionsPass(man); pass->run(); VersionsGraph graph = pass->getResultGraph(); ASSERT_TRUE(graph.validate()); } TEST(Effects, analysis_versions_2_1_fail){ XreateManager* man = XreateManager::prepare( R"Code( test= function(a:: num):: num; entry { x{0}= 5:: int. b = x{0}. x{1} = 2. b + x{1} } )Code"); VersionsPass* pass = new VersionsPass(man); pass->run(); VersionsGraph graph = pass->getResultGraph(); graph.__debug_print(std::cout); ASSERT_FALSE(graph.validate()); } TEST(Effects, analysis_versions_2_2){ XreateManager* man = XreateManager::prepare( R"Code( test= function(a:: num):: num; entry { x{0}= 5:: int. b = intrinsic copy(x{0}). x{1} = 2. b + x{1} } )Code"); VersionsPass* pass = new VersionsPass(man); pass->run(); VersionsGraph graph = pass->getResultGraph(); graph.__debug_print(std::cout); ASSERT_TRUE(graph.validate()); } TEST(Effects, analysis_versions_3){ XreateManager* man = XreateManager::prepare( R"Code( test= function:: num; entry { x{0}= 3:: int. a = x{0}:: int. b = a :: int. x{1} = b. x{1} } )Code"); VersionsPass* pass = new VersionsPass(man); pass->run(); VersionsGraph graph = pass->getResultGraph(); graph.__debug_print(std::cout); ASSERT_TRUE(graph.validate()); std::cout << "========================\n"; graph.__debug_print(std::cout); AttachmentsContainerDefault>* attachmentsDependency = graph.representAsAttachments(); CodeScope* scope = man->root->findFunction("test")->getEntryScope(); const std::list& dependenciesX1 = attachmentsDependency->get(Symbol{ScopedSymbol{1, 1}, scope}); ASSERT_EQ(3, dependenciesX1.size()); } TEST(Effects, compilation_versions_1){ details::tier1::XreateManager* man = details::tier1::XreateManager::prepare( R"Code( test= function:: num; entry { x{1} = b. b = a :: int. a = x{0}:: int. x{0}= 3:: int. x{1} } )Code"); man->analyse(); if (!man->isPassRegistered(PassId::VersionsPass)){ VersionsPass* pass = new VersionsPass(man); pass->run(); pass->finish(); } int (*body)() = (int (*)())man->run(); int answer = body(); ASSERT_EQ(3, answer); } TEST(Effects, compilation_versions_versionInit1){ details::tier1::XreateManager* man = details::tier1::XreateManager::prepare( R"Code( test= function:: num; entry { x{0} = 3. x{0} } )Code"); man->analyse(); if (!man->isPassRegistered(PassId::VersionsPass)){ VersionsPass* pass = new VersionsPass(man); pass->run(); pass->finish(); } int (*body)() = (int (*)())man->run(); int answer = body(); ASSERT_EQ(3, answer); } TEST(Effects, compilation_versions_versionNext1){ details::tier1::XreateManager* man = details::tier1::XreateManager::prepare( R"Code( test= function:: num; entry { x{0} = 5. x{1} = x{0} - 2. x{1} } )Code"); man->analyse(); if (!man->isPassRegistered(PassId::VersionsPass)){ VersionsPass* pass = new VersionsPass(man); pass->run(); pass->finish(); } int (*body)() = (int (*)())man->run(); int answer = body(); ASSERT_EQ(3, answer); } TEST(Effects, compilation_versions_IntrinsicCopy1){ details::tier1::XreateManager* man = details::tier1::XreateManager::prepare( R"Code( test= function:: num; entry { x{0} = 5. b = intrinsic copy (x{0}). x{1} = 2. b - x{1} } )Code"); man->analyse(); if (!man->isPassRegistered(PassId::VersionsPass)){ VersionsPass* pass = new VersionsPass(man); pass->run(); pass->finish(); } int (*body)() = (int (*)())man->run(); int answer = body(); ASSERT_EQ(3, answer); } TEST(Effects, compilation_versions_varexchange){ details::tier1::XreateManager* man = details::tier1::XreateManager::prepare( R"Code( test= function:: num; entry { a{0} = 3. b{0} = 5. tmp = intrinsic copy (a{0}). a{1} = b{0}. b{1} = tmp. b{1} } )Code"); man->analyse(); if (!man->isPassRegistered(PassId::VersionsPass)){ VersionsPass* pass = new VersionsPass(man); pass->run(); pass->finish(); } int (*body)() = (int (*)())man->run(); int answer = body(); ASSERT_EQ(3, answer); } /* TEST(Effects, analysis_versions_copy){ } TEST(Effects, syntax_references1){ } TEST(Effects, syntax_scope_versions1){ } TEST(Effects, DynamicVersions_analysis){ } */ diff --git a/cpp/tests/externc.cpp b/cpp/tests/externc.cpp index 2057d42..c9486e9 100644 --- a/cpp/tests/externc.cpp +++ b/cpp/tests/externc.cpp @@ -1,106 +1,107 @@ #include "gtest/gtest.h" #include "xreatemanager.h" #include "main/Scanner.h" #include "main/Parser.h" #include #include using namespace std; +using namespace xreate; TEST(InterfaceExternC, testAST) { std::string code = " \ interface(extern-c){ \ xml2 = library:: pkgconfig(\"libxml-2.0\"). \ \ include { \ xml2 = [\"libxml/tree.h\"] \ }. \ } \ "; xreate::grammar::main::Scanner scanner(reinterpret_cast (code.c_str()), code.size()); xreate::grammar::main::Parser parser(&scanner); parser.Parse(); ASSERT_EQ(1, parser.root->__externdata.size()); for (const ExternEntry& lib : parser.root->__externdata) { ASSERT_EQ("libxml-2.0", lib.package); ASSERT_EQ(1, lib.headers.size()); ASSERT_EQ("libxml/tree.h", lib.headers.at(0)); } } TEST(InterfaceExternC, testfetchPackageHeaders) { ExternEntry entry{"libxml-2.0", {}}; vector args = ExternLayer::fetchPackageFlags(entry); ASSERT_EQ(1, args.size()); ASSERT_EQ("-I/usr/include/libxml2", args.at(0)); } TEST(InterfaceExternC, testfetchPackageLibs) { ExternEntry entry{"libxml-2.0", {}}; vector args = ExternLayer::fetchPackageLibs(entry); ASSERT_EQ(1, args.size()); ASSERT_EQ("xml2", args.at(0)); } TEST(InterfaceExternC, testLoadLib) { std::string msgErr; if (!llvm::sys::DynamicLibrary::LoadLibraryPermanently("-lpcre -lxml2", &msgErr)) { cout << msgErr; ASSERT_EQ("", msgErr); } ASSERT_TRUE(true); } TEST(InterfaceExternC, testBSD1) { std::string code = " \n\ interface(extern-c){ \n\ libbsd = library:: pkgconfig(\"libbsd\"). \n\ \n\ include { \n\ libbsd = [\"bsd/stdlib.h\"] \n\ }. \n\ } \n" "main= function:: int; entry{arc4random_uniform(24) }"; std::unique_ptr program(XreateManager::prepare(move(code))); void* entryPtr = program->run(); int (*entry)() = (int (*)())(intptr_t) entryPtr; int answer = 24; answer = entry(); cout << answer; ASSERT_LT(answer, 24); } TEST(InterfaceExternC, testStructFields1) { FILE* input = fopen("scripts/containers/Containers_Implementation_LinkedList1.xreate", "r"); assert(input != nullptr); xreate::grammar::main::Scanner scanner(input); xreate::grammar::main::Parser parser(&scanner); parser.Parse(); AST* ast = parser.root->finalize(); CodeScope* body = ast->findFunction("test")->getEntryScope(); const TypeAnnotation& tTree = body->getDeclaration(body->getSymbol("tree")).type; const ExpandedType& t2Tree = ast->expandType(tTree); LLVMLayer llvm(ast); TypeUtils utils(&llvm); std::vectorfields = utils.getStructFields(t2Tree); auto field = std::find(fields.begin(), fields.end(), "children"); ASSERT_TRUE(field != fields.end()); } diff --git a/cpp/tests/interpretation.cpp b/cpp/tests/interpretation.cpp index abb3606..1e313d1 100644 --- a/cpp/tests/interpretation.cpp +++ b/cpp/tests/interpretation.cpp @@ -1,380 +1,384 @@ #include "attachments.h" using namespace xreate; #include "xreatemanager.h" #include "compilation/targetinterpretation.h" #include "gtest/gtest.h" #include "boost/scoped_ptr.hpp" -#define private public +//#define FRIENDS_INTERPRETATION_TESTS \ +// friend class ::Modules_AST2_Test; \ +// friend class ::Modules_Discovery1_Test; \ +// friend class ::Modules_Solve1_Test; + #include "pass/interpretationpass.h" using namespace xreate::grammar::main; -using namespace xreate::compilation; +using namespace xreate::interpretation; TEST(Interpretation, Analysis_StatementIF_1){ XreateManager* man = XreateManager::prepare( R"Code( main = function::bool { x = "a":: string. y = if (x=="b"):: bool; interpretation(force) { true } else { false }. y } )Code" ); InterpretationPass* pass = new InterpretationPass(man); pass->run(); CodeScope* scopeEntry = man->root->findFunction("main")->getEntryScope(); Symbol symbolY{scopeEntry->getSymbol("y"), scopeEntry}; InterpretationData& dataSymbolY = Attachments::get(symbolY); ASSERT_EQ(INTR_ONLY, dataSymbolY.resolution); } TEST(Interpretation, Compilation_StatementIF_1){ - details::tier1::XreateManager* man = details::tier1::XreateManager::prepare( + xreate::details::tier1::XreateManager* man = xreate::details::tier1::XreateManager::prepare( R"Code( main = function::int; entry { x = "a":: string. y = if (x=="b"):: string; interpretation(force) { 1 } else { 0 }. y } )Code" ); man->analyse(); InterpretationPass* pass; if (man->isPassRegistered(PassId::InterpretationPass)){ pass = (InterpretationPass*) man->getPassById(PassId::InterpretationPass); } else { pass = new InterpretationPass(man); pass->run(); } int (*main)() = (int (*)())man->run(); int result = main(); ASSERT_EQ(0, result); } TEST(Interpretation, Analysis_StatementIF_InterpretCondition_1){ XreateManager* man = XreateManager::prepare( R"Code( main = function(x:: int):: int { comm= "inc":: string; interpretation(force). y = if (comm == "inc")::int {x+1} else {x}. y } )Code" ); InterpretationPass* pass = new InterpretationPass(man); pass->run(); CodeScope* scopeEntry = man->root->findFunction("main")->getEntryScope(); Symbol symbolY{scopeEntry->getSymbol("y"), scopeEntry}; InterpretationData& dataSymbolY = Attachments::get(symbolY); ASSERT_EQ(CMPL_ONLY, dataSymbolY.resolution); ASSERT_EQ(IF_INTERPRET_CONDITION, dataSymbolY.op); } TEST(Interpretation, Compilation_StatementIF_InterpretCondition_1){ - details::tier1::XreateManager* man = details::tier1::XreateManager::prepare( + xreate::details::tier1::XreateManager* man = xreate::details::tier1::XreateManager::prepare( R"Code( main = function(x:: int):: int; entry { comm= "inc":: string; interpretation(force). y = if (comm == "inc")::int {x+1} else {x}. y } )Code" ); man->analyse(); InterpretationPass* pass; if (man->isPassRegistered(PassId::InterpretationPass)){ pass = (InterpretationPass*) man->getPassById(PassId::InterpretationPass); } else { pass = new InterpretationPass(man); pass->run(); } int (*main)(int) = (int (*)(int))man->run(); int result = main(1); ASSERT_EQ(2, result); } TEST(Interpretation, Compilation_StatementFOLD_INTERPRET_INPUT_1){ - details::tier1::XreateManager* man = details::tier1::XreateManager::prepare( + xreate::details::tier1::XreateManager* man = xreate::details::tier1::XreateManager::prepare( R"Code( main = function(x:: int):: int; entry { commands = ["inc", "double", "dec"]:: [string]; interpretation(force). loop fold(commands->comm::string, x->operand):: int{ switch(comm)::int case ("inc"){ operand + 1 } case ("dec"){ operand - 1 } case ("double"){ operand * 2 } } } )Code" ); man->analyse(); InterpretationPass* pass; if (man->isPassRegistered(PassId::InterpretationPass)){ pass = (InterpretationPass*) man->getPassById(PassId::InterpretationPass); } else { pass = new InterpretationPass(man); pass->run(); } const ManagedFnPtr& funcMain = man->root->findFunction("main"); InterpretationData& dataBody = Attachments::get(funcMain); ASSERT_EQ(FOLD_INTERPRET_INPUT, dataBody.op); int (*main)(int) = (int (*)(int))man->run(); int result = main(10); ASSERT_EQ(21, result); } TEST(Interpretation, StatementCall_RecursionNo_1){ - details::tier1::XreateManager* man = details::tier1::XreateManager::prepare( + xreate::details::tier1::XreateManager* man = xreate::details::tier1::XreateManager::prepare( R"Code( unwrap = function(data::undef, keys::undef):: undef; interpretation(force){ loop fold(keys->key::string, data->a):: undef { a[key] } } start = function::num; entry{ result = unwrap( { a = { b = { c = "core" } } }, ["a", "b", "c"])::undef. result == "core" } )Code" ); man->analyse(); InterpretationPass* pass; if (man->isPassRegistered(PassId::InterpretationPass)){ pass = (InterpretationPass*) man->getPassById(PassId::InterpretationPass); } else { pass = new InterpretationPass(man); pass->run(); } int (*main)() = (int (*)())man->run(); int result = main(); ASSERT_EQ(1, result); } TEST(Interpretation, StatementCall_RecursionDirect_1){ - details::tier1::XreateManager* man = details::tier1::XreateManager::prepare( + xreate::details::tier1::XreateManager* man = xreate::details::tier1::XreateManager::prepare( R"Code( unwrap = function(data:: X):: Y { if (data[0] == "a")::Y {0} else {unwrap(data[0])} } entry = function:: i8; entry { unwrap([[[["a"]]]]):: i8; interpretation(force) } )Code" ); man->analyse(); InterpretationPass* pass; if (man->isPassRegistered(PassId::InterpretationPass)){ pass = (InterpretationPass*) man->getPassById(PassId::InterpretationPass); } else { pass = new InterpretationPass(man); pass->run(); } InterpretationResolution resolutionActual = pass->process(man->root->findFunction("unwrap")); ASSERT_EQ(ANY, resolutionActual); int (*main)() = (int (*)())man->run(); int result = main(); ASSERT_EQ(0, result); } TEST(Interpretation, StatementCall_RecursionIndirect_1){ XreateManager* man = XreateManager::prepare( R"Code( funcA = function(data:: X):: Y { if (data == "a")::Y {0} else {funcB(data)} } funcB = function(data:: X):: Y { if (data == "b")::Y {1} else {funcA(data)} } entry = function:: i8; entry { funcA(""):: i8; interpretation(force) } )Code" ); InterpretationPass* pass = new InterpretationPass(man); ASSERT_DEATH(pass->run(), "Indirect recursion detected"); } TEST(Interpretation, PartialIntr_1){ XreateManager* man = XreateManager::prepare( R"Code( evaluate= function(argument:: num, code:: string; interpretation(force)):: num { switch(code)::int case ("inc") {argument + 1} case ("dec") {argument - 1} case ("double") {argument * 2} } main = function::int; entry { commands= ["inc", "double", "dec"]:: [string]; interpretation(force). loop fold(commands->comm::string, 10->operand):: int{ evaluate(operand, comm) } } )Code" ); InterpretationPass* pass = new InterpretationPass(man); pass->run(); ManagedFnPtr fnEvaluate = man->root->findFunction("evaluate"); InterpretationResolution resFnEvaluate= pass->process(fnEvaluate); ASSERT_EQ(CMPL_ONLY, resFnEvaluate); ASSERT_TRUE(FunctionInterpretationHelper::needPartialInterpretation(fnEvaluate)); const Expression& exprLoop = man->root->findFunction("main")->__entry->getBody(); Symbol symbCallEv{{0, VERSION_NONE}, exprLoop.blocks.front()}; InterpretationData dataCallEv = Attachments::get(symbCallEv); ASSERT_EQ(CMPL_ONLY, dataCallEv.resolution); ASSERT_EQ(CALL_INTERPRET_PARTIAL, dataCallEv.op); } TEST(Interpretation, Compilation_PartialIntr_2){ - details::tier1::XreateManager* man = details::tier1::XreateManager::prepare( + xreate::details::tier1::XreateManager* man = xreate::details::tier1::XreateManager::prepare( R"Code( evaluate= function(argument:: num, code:: string; interpretation(force)):: num { switch(code)::int case ("inc") {argument + 1} case ("dec") {argument - 1} case ("double") {argument * 2} case default {argument} } main = function::int; entry { commands= ["inc", "double", "dec"]:: [string]; interpretation(force). loop fold(commands->comm::string, 10->operand):: int{ evaluate(operand, comm) } } )Code" ); man->analyse(); if (!man->isPassRegistered(PassId::InterpretationPass)){ InterpretationPass* pass = new InterpretationPass(man); pass->run(); } int (*main)() = (int (*)())man->run(); int result = main(); ASSERT_EQ(21, result); } TEST(Interpretation, PartialIntr_3){ - details::tier1::XreateManager* man = details::tier1::XreateManager::prepare( + xreate::details::tier1::XreateManager* man = xreate::details::tier1::XreateManager::prepare( R"Code( Command= type variant (INC, DEC, DOUBLE). evaluate= function(argument:: num, code:: Command; interpretation(force)):: num { switch(code)::int case (INC) {argument + 1} case (DEC) {argument - 1} case (DOUBLE) {argument * 2} case default {argument} } main = function::int; entry { commands= [INC, DOUBLE, DEC]:: [Command]; interpretation(force). loop fold(commands->comm::Command, 10->operand):: int{ evaluate(operand, comm) } } )Code" ); man->analyse(); if (!man->isPassRegistered(PassId::InterpretationPass)){ InterpretationPass* pass = new InterpretationPass(man); pass->run(); } int (*main)() = (int (*)())man->run(); int result = main(); ASSERT_EQ(21, result); } TEST(InterpretationExamples, Regexp1){ FILE* input = fopen("scripts/dsl/regexp.xreate","r"); assert(input != nullptr); std::unique_ptr man(XreateManager::prepare(input)); int (*main)() = (int (*)())man->run(); int result = main(); ASSERT_EQ(4, result); } //TOTEST call indirect recursion(w/o tags) //TASk implement and test Loop Inf (fix acc types in coco grammar) diff --git a/cpp/tests/modules.cpp b/cpp/tests/modules.cpp index d8e76b1..ed0df5a 100644 --- a/cpp/tests/modules.cpp +++ b/cpp/tests/modules.cpp @@ -1,320 +1,321 @@ /* * modules.cpp * * Author: pgess * Created on June 18, 2017, 8:25 PM */ class Modules_AST2_Test; class Modules_Discovery1_Test; class Modules_Solve1_Test; #define FRIENDS_MODULES_TESTS \ friend class ::Modules_AST2_Test; \ friend class ::Modules_Discovery1_Test; \ friend class ::Modules_Solve1_Test; #include "modules.h" #include "misc/xreatemanager-decorators.h" #include "misc/xreatemanager-modules.h" #include "xreatemanager.h" #include "modules/Parser.h" #include "gtest/gtest.h" #include #include #include namespace fs = boost::filesystem; using namespace std; -using namespace xreate::grammar::modules; +using namespace xreate; +using namespace xreate::modules; TEST(Modules, AST1) { FILE* input = fopen("scripts/dsl/regexp.xreate","r"); assert(input != nullptr); Scanner scanner(input); Parser parser(&scanner); parser.Parse(); ASSERT_EQ(parser.errors->count, 0); } TEST(Modules, AST2){ string code = R"Code( module { name(test1). status(untested). require provides(logging). include controller("/tmp/test-controller.ls"). discover("/tmp/root/"). } )Code"; Scanner scanner(reinterpret_cast(code.c_str()), code.size()); Parser parser(&scanner); parser.Parse(); - xreate::ModuleRecord module = parser.module; + ModuleRecord module = parser.module; ASSERT_EQ(2, module.__properties.size()); ASSERT_EQ("name", module.__properties.front().getValueString()); ASSERT_EQ("status", module.__properties.back().getValueString()); ASSERT_EQ(1, module.__queries.size()); ASSERT_EQ("provides", module.__queries.front().getValueString()); ASSERT_EQ(1, module.__controllers.size()); ASSERT_EQ("/tmp/test-controller.ls", module.__controllers.front()); ASSERT_EQ(1, module.__discoveries.size()); ASSERT_EQ("/tmp/root/", module.__discoveries.front()); } TEST(Modules, Discovery1){ const std::string dirModulesRoot = "/tmp/testModulesDiscovery1_t54723/"; string codeA = R"Code(module { name(testA). status(needToTestMore). })Code"; string codeB = R"Code(module { name(testB). status(needToTestEvenMore). })Code"; string codeMain = string("module{discover \"") + dirModulesRoot + "\".}"; fs::create_directories(dirModulesRoot); fs::ofstream fileA(dirModulesRoot + "a.xreate"); fileA << codeA; fileA.close(); fs::ofstream fileB(dirModulesRoot + "b.xreate"); fileB << codeB; fileB.close(); Scanner scanner(reinterpret_cast(codeMain.c_str()), codeMain.size()); Parser parser(&scanner); parser.Parse(); - xreate::ModulesRegistry registry; - xreate::ModulesSolver solver(®istry); + ModulesRegistry registry; + ModulesSolver solver(®istry); solver.discoverModules(parser.module); fs::remove_all(dirModulesRoot); std::string output = solver.__program.str(); cout << output << endl; ASSERT_NE(string::npos, output.find("bind_module(0, name(testA)).")); ASSERT_NE(string::npos, output.find("bind_module(1, status(needToTestEvenMore)).")); } TEST(Modules, Requests1){ } TEST(Modules, Solve1){ const std::string dirModulesRoot = "/tmp/testModulesDiscovery1_t54724/"; string codeA = R"Code(module { name(testA). provide(superService). status(needToTestMore). })Code"; string codeB = R"Code(module { name(testB). provide(superService). status(needToTestEvenMore). })Code"; string codeMain = R"Code(module { discover("/tmp/testModulesDiscovery1_t54724/") include controller ("/tmp/testModulesDiscovery1_t54724/controller") require (superService) })Code"; string codeController = R"Code( status_score(0, needToTestEvenMore). status_score(1, needToTestMore). module_include_candidate(X, Y, Request):- module_require(X, Request); bind_module(Y, provide(Request)). module_include_winner(X, Request, MaxScore) :- MaxScore = #max{Score: module_include_candidate(X, Y, Request), bind_module(Y, status(Status)), status_score(Score, Status)}; module_require(X, Request). module_include(X, Y) :- module_include_winner(X, Request, MaxScore); bind_module(Y, provide(Request)); bind_module(Y, status(Status)); status_score(MaxScore, Status). )Code"; fs::create_directories(dirModulesRoot); fs::ofstream fileA(dirModulesRoot + "a.xreate"); fileA << codeA; fileA.close(); fs::ofstream fileB(dirModulesRoot + "b.xreate"); fileB << codeB; fileB.close(); fs::ofstream fileController(dirModulesRoot + "controller"); fileController << codeController; fileController.close(); Scanner scanner(reinterpret_cast(codeMain.c_str()), codeMain.size()); Parser parser(&scanner); parser.Parse(); - xreate::ModulesRegistry registry; - xreate::ModulesSolver solver(®istry); + ModulesRegistry registry; + ModulesSolver solver(®istry); solver.init("", parser.module); fs::remove_all(dirModulesRoot); cout << solver.__program.str() << endl; std::list modulesRequired = solver.run(parser.module); ASSERT_EQ(1, modulesRequired.size()); string moduleActualRequired = modulesRequired.front(); string moduleExpected = dirModulesRoot + "a.xreate"; ASSERT_EQ(moduleExpected, moduleActualRequired); } TEST(Modules, Compilation1){ - const std::string dirModulesRoot = "/tmp/testModulesDiscovery1_t54725/"; + const std::string dirModulesRoot = "/tmp/testModulesDiscovery1_t54726/"; string codeMain = R"Code( module { - discover("/tmp/testModulesDiscovery1_t54725/") - include controller("/tmp/testModulesDiscovery1_t54725/controller") + discover("/tmp/testModulesDiscovery1_t54726/") + include controller("/tmp/testModulesDiscovery1_t54726/controller") require (superService) } test = function:: int; entry { getYourNumber() } )Code"; string codeA = R"Code(module { name(testA). provide(superService). status(needToTestEvenMore). } getYourNumber= function:: int {0} )Code"; string codeB = R"Code(module { name(testB). provide(superService). status(needToTestMore). } getYourNumber= function:: int {1} )Code"; string codeController = R"Code( status_score(0, needToTestEvenMore). status_score(1, needToTestMore). module_include_candidate(X, Y, Request):- module_require(X, Request); bind_module(Y, provide(Request)). module_include_winner(X, Request, MaxScore) :- MaxScore = #max{Score: module_include_candidate(X, Y, Request), bind_module(Y, status(Status)), status_score(Score, Status)}; module_require(X, Request). module_include(X, Y) :- module_include_winner(X, Request, MaxScore); bind_module(Y, provide(Request)); bind_module(Y, status(Status)); status_score(MaxScore, Status). )Code"; fs::create_directories(dirModulesRoot); fs::ofstream fileA(dirModulesRoot + "a.xreate"); fileA << codeA; fileA.close(); fs::ofstream fileB(dirModulesRoot + "b.xreate"); fileB << codeB; fileB.close(); fs::ofstream fileController(dirModulesRoot + "controller"); fileController << codeController; fileController.close(); auto man = new XreateManagerImpl>(); man->prepareCode(std::move(codeMain)); fs::remove_all(dirModulesRoot); int (*funcMain)() = (int (*)()) man->run(); int result = funcMain(); ASSERT_EQ(1, result); } TEST(Modules, Compilation_AssignModulePath1){ const std::string dirModulesRoot = "/tmp/testModulesDiscovery1_t54725/"; string codeMain = R"Code( module { discover("/tmp/testModulesDiscovery1_t54725/") include controller("/tmp/testModulesDiscovery1_t54725/controller") require (superService) } test = function:: int; entry { getYourNumber() } )Code"; string codeA = R"Code(module { name(testA). provide(superService). status(needToTestEvenMore). } getYourNumber= function:: int {0} )Code"; string codeController = R"Code( module_include(X, "/tmp/testModulesDiscovery1_t54725/a.xreate") :- module_require(X, superService). )Code"; fs::create_directories(dirModulesRoot); fs::ofstream fileA(dirModulesRoot + "a.xreate"); fileA << codeA; fileA.close(); fs::ofstream fileController(dirModulesRoot + "controller"); fileController << codeController; fileController.close(); auto man = new XreateManagerImpl>(); man->prepareCode(std::move(codeMain)); fs::remove_all(dirModulesRoot); int (*funcMain)() = (int (*)()) man->run(); int result = funcMain(); ASSERT_EQ(0, result); } \ No newline at end of file diff --git a/cpp/tests/types.cpp b/cpp/tests/types.cpp index 30ea9a0..ababa6e 100644 --- a/cpp/tests/types.cpp +++ b/cpp/tests/types.cpp @@ -1,164 +1,165 @@ /* * types.cpp * * Created on: Jun 4, 2015 * Author: pgess */ #include "gtest/gtest.h" #include "xreatemanager.h" #include "llvmlayer.h" #include "main/Parser.h" using namespace std; +using namespace xreate; using namespace xreate::grammar::main; TEST(Types, DependantTypes1) { string&& code = "XmlNode = type alias {\n" " tag:: string,\n" " /* attrs:: [string],*/\n" " content:: string\n" "}.\n"; std::unique_ptr program(XreateManager::prepare(move(code))); ExpandedType typeXmlNode = program->root->findType("XmlNode"); ASSERT_EQ(TypeOperator::STRUCT, typeXmlNode->__operator); ASSERT_EQ(2, typeXmlNode->__operands.size()); ASSERT_EQ(TypePrimitive::String, typeXmlNode->__operands.at(0).__value); ASSERT_EQ(TypePrimitive::String, typeXmlNode->__operands.at(1).__value); } TEST(Types, DependantTypes2) { string&& code = "XmlNode = type alias {\n" " tag:: string,\n" " /* attrs:: [string],*/\n" " content:: string\n" "}.\n" "" "Template = type Template(Leaf) [Leaf, [Leaf[content]]]." "Concrete = type alias Template(XmlNode)."; std::unique_ptr program(XreateManager::prepare(move(code))); ExpandedType typeConcrete = program->root->findType("Concrete"); ASSERT_EQ(TypeOperator::TUPLE, typeConcrete->__operator); ASSERT_EQ(2, typeConcrete->__operands.size()); ASSERT_EQ(TypeOperator::STRUCT, typeConcrete->__operands.at(0).__operator); ASSERT_EQ(TypeOperator::ARRAY, typeConcrete->__operands.at(1).__operator); ASSERT_EQ(TypePrimitive::String, typeConcrete->__operands.at(1).__operands.at(0).__value); } TEST(Types, TreeType1) { string&& code = "XmlNode = type alias {\n" " tag:: string,\n" " /* attrs:: [string],*/\n" " content:: string\n" "}.\n" "" "Tree = type Tree(Leaf) [Leaf, [Tree(Leaf)]]." "Concrete = type alias Tree(XmlNode)."; std::unique_ptr program(XreateManager::prepare(move(code))); ExpandedType typeConcrete = program->root->findType("Concrete"); ASSERT_EQ(TypeOperator::TUPLE, typeConcrete->__operator); ASSERT_EQ(2, typeConcrete->__operands.size()); ASSERT_EQ(TypeOperator::STRUCT, typeConcrete->__operands.at(0).__operator); ASSERT_EQ(TypeOperator::ARRAY, typeConcrete->__operands.at(1).__operator); auto typeLink = typeConcrete->__operands.at(1).__operands.at(0); ASSERT_EQ(TypeOperator::LINK, typeLink.__operator); ASSERT_EQ(typeConcrete->conjuctionId,typeLink.conjuctionId); } TEST(Types, TreeType1LLvm){ string&& code = "XmlNode = type alias {\n" " tag:: string,\n" " /* attrs:: [string],*/\n" " content:: string\n" "}.\n" "" "Tree = type Tree(Leaf) [Leaf, [Tree(Leaf)]]." "Concrete = type alias Tree(XmlNode)."; std::unique_ptr program(XreateManager::prepare(move(code))); ExpandedType typeConcrete = program->root->findType("Concrete"); llvm::Type* raw = program->llvm->toLLVMType(typeConcrete); } TEST(Types, ArrayOfExternal1){ FILE* input = fopen("scripts/containers/Containers_Implementation_LinkedList1.xreate","r"); assert(input != nullptr); Scanner scanner(input); Parser parser(&scanner); parser.Parse(); AST* ast = parser.root->finalize(); CodeScope* body = ast->findFunction("test")->getEntryScope(); const TypeAnnotation& t = body->getDeclaration(body->getSymbol("childrenRaw")).type; const ExpandedType& t2 = ast->expandType(t); EXPECT_EQ(t2->__operator, TypeOperator::ARRAY); } TEST(Types, ExternType1){ FILE* input = fopen("scripts/containers/Containers_Implementation_LinkedList1.xreate","r"); assert(input != nullptr); Scanner scanner(input); Parser parser(&scanner); parser.Parse(); AST* ast = parser.root->finalize(); CodeScope* body = ast->findFunction("test")->getEntryScope(); const TypeAnnotation& t = body->getDeclaration(body->getSymbol("tree")).type; const ExpandedType& t2 = ast->expandType(t); EXPECT_EQ(t2->__operator, TypeOperator::CUSTOM); } TEST(Types, ast_VariantType1){ string&& code = " colors = type variant (RED, BLUE, GREEN).\n" " test = function:: colors; entry {GREEN}"; std::unique_ptr program(XreateManager::prepare(move(code))); ExpandedType typ = program->root->findType("colors"); EXPECT_EQ(TypeOperator::VARIANT, typ->__operator); Expression eRed = program->root->findFunction("test")->getEntryScope()->getBody(); EXPECT_EQ(Expression::VARIANT, eRed.__state); const ExpandedType& typ2 = program->root->expandType(eRed.type); EXPECT_EQ(TypeOperator::VARIANT, typ2->__operator); program->run(); } TEST(Types, full_VariantType_Switch1){ string&& code = " colors = type variant (RED, BLUE, GREEN). \n" " test = function:: colors {GREEN} \n" "main = function:: int; entry { \n" " switch(test()):: int \n" " case (GREEN) {0} \n" " case default {1} \n" "}"; XreateManager* man = XreateManager::prepare(move(code)); int (*main)() = (int (*)()) man->run(); EXPECT_EQ(0, main()); } //TOTEST string type diff --git a/grammar/gen-grammar b/grammar/gen-grammar index 237f5b5..f387d59 100755 --- a/grammar/gen-grammar +++ b/grammar/gen-grammar @@ -1,9 +1,9 @@ COCO_EXECUTABLE=${2:-cococpp} COCO_FRAMES_PATH=${3:-/usr/share/coco-cpp/} echo "Run coco generator: " case $1 in main) $COCO_EXECUTABLE ./xreate.ATG -frames $COCO_FRAMES_PATH -o main -namespace xreate::grammar::main;; - modules) $COCO_EXECUTABLE ./modules.ATG -frames $COCO_FRAMES_PATH -o modules -namespace xreate::grammar::modules;; + modules) $COCO_EXECUTABLE ./modules.ATG -frames $COCO_FRAMES_PATH -o modules -namespace xreate::modules;; esac diff --git a/grammar/xreate.ATG b/grammar/xreate.ATG index ac15f56..f57d3e4 100644 --- a/grammar/xreate.ATG +++ b/grammar/xreate.ATG @@ -1,607 +1,606 @@ //TODO add ListLiteral //TODO ExprTyped: assign default(none) type #include "ast.h" #include "ExternLayer.h" #include "pass/adhocpass.h" #include #include #define wprintf(format, ...) \ char __buffer[100]; \ wcstombs(__buffer, format, 100); \ fprintf(stderr, __buffer, __VA_ARGS__) -using namespace xreate; using namespace std; COMPILER Xreate - xreate::details::incomplete::AST* root = nullptr; // current program unit + details::incomplete::AST* root = nullptr; // current program unit void ensureInitalizedAST(){ - if (root == nullptr) root = new xreate::details::incomplete::AST(); + if (root == nullptr) root = new details::incomplete::AST(); } struct { - std::stack scopesOld; - xreate::CodeScope* scope = nullptr; + std::stack scopesOld; + CodeScope* scope = nullptr; } context; void pushContextScope(CodeScope* scope){ context.scopesOld.push(context.scope); context.scope = scope; } void popContextScope(){ context.scope = context.scopesOld.top(); context.scopesOld.pop(); } int nextToken() { scanner->ResetPeek(); return scanner->Peek()->kind; } bool checkParametersList() { return la->kind == _ident && nextToken() == _lparen; } bool checkInfix() { return la->kind == _ident && nextToken() == _ident; } bool checkIndex() { return la->kind == _ident && nextToken() == _lbrack; } bool checkFuncDecl() { if (la->kind != _ident) return false; int token2 = nextToken(); int token3 = scanner->Peek()->kind; return token2 == _assign && (token3 == _function || token3 == _pre); } bool checkAssignment() { if (la->kind != _ident) return false; scanner->ResetPeek(); int token2 = scanner->Peek()->kind; if (token2 == _lcurbrack) { scanner->Peek(); int token3 = scanner->Peek()->kind; if (token3 != _rcurbrack) return false; int token4 = scanner->Peek()->kind; return token4 == _assign; } return token2 == _assign; } void recognizeIdentifier(Expression& i){ if (!context.scope->recognizeIdentifier(i)){ if (!root->recognizeVariantIdentifier(i)){ root->postponeIdentifier(context.scope, i); } } } enum SwitchKind{SWITCH_NORMAL, SWITCH_META}; CHARACTERS letter = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz". any = ANY - '"'. digit = "0123456789". cr = '\r'. lf = '\n'. tab = '\t'. TOKENS ident = (letter | '_') {letter | digit | '_'}. number = (digit | '-' digit) {digit}. string = '"' { any } '"'. function = "function". pre = "pre". lparen = '('. rparen = ')'. lbrack = '['. rbrack = ']'. lcurbrack = '{'. rcurbrack = '}'. equal = "==". assign = '='. implic = '-' '>'. colon = ':'. context = "context". tagcolon = "::". lse = "<=". lss = "<". gte = ">=". gtr = ">". ne1 = "!=". ne2= "<>". COMMENTS FROM "/*" TO "*/" NESTED COMMENTS FROM "//" TO lf IGNORE cr + lf + tab PRODUCTIONS Xreate = (. Function* function; ensureInitalizedAST(); .) {( RuleDecl | InterfaceData | Imprt | ContextSection | IF(checkFuncDecl()) FDecl (. root->add(function); .) | TDecl | SkipModulesSection )} (. .) . Ident = ident (. name = t->val; .). VarIdent = ident (. e = Expression(Atom(t->val)); .) [ lcurbrack ( ident (. SemErr(coco_string_create("var version as ident is not implemented yet")); .) | number (. Attachments::put(e, Atom(t->val).get()); .) ) rcurbrack ] . FDecl = (. std::wstring fname; std::wstring argName; TypeAnnotation typIn; TypeAnnotation typOut; bool flagIsPrefunct = false; Expression binding; .) Ident assign [pre (. flagIsPrefunct = true; .)] function (. f = new Function(fname); f->isPrefunction = flagIsPrefunct; CodeScope* entry = f->getEntryScope(); .) ['(' Ident tagcolon ExprAnnotations (. f->addBinding(Atom(argName), move(binding)); .) {',' Ident tagcolon ExprAnnotations (. f->addBinding(Atom (argName), move(binding));.) } ')'] [ tagcolon ( IF(flagIsPrefunct) FnTag | Type ) {';' FnTag }] BDecl (. entry->getBody().bindType(move(typOut));.) . ContextSection<>= (. Expression context; Function* f; .) "case" "context" tagcolon MetaSimpExpr lcurbrack { FDecl (. f->guardContext = context; root->add(f); .) } rcurbrack. /** * TYPES * */ TypeTerm = (. std::wstring tid; .) ("string" (. typ = TypePrimitive::String;.) | "num" (. typ = TypePrimitive::Num;.) | "int" (. typ = TypePrimitive::Int;.) | "float" (. typ = TypePrimitive::Float;.) | "bool" (. typ = TypePrimitive::Bool; .) | "i8" (. typ = TypePrimitive::I8; .) | "i32" (. typ = TypePrimitive::I32; .) | "i64" (. typ = TypePrimitive::I64; .) ). Type = (. TypeAnnotation typ2; TypePrimitive typ3; std::wstring tid, field; .) ( TList | TStruct | TypeTerm (. typ = typ3; .) | IF (checkIndex()) Ident lbrack Ident (. typ = TypeAnnotation(TypeOperator::ACCESS, {}); typ.__valueCustom = Atom(tid).get(); typ.fields.push_back(Atom(field).get()); .) {',' Ident (. typ.fields.push_back(Atom(field).get()); .) } rbrack | Ident (. typ = TypeAnnotation(TypeOperator::CUSTOM, {}); typ.__valueCustom = Atom(tid).get(); .) ['(' Type (. typ.__operator = TypeOperator::CALL; typ.__operands.push_back(typ2); .) {',' Type (. typ.__operands.push_back(typ2); .) } ')'] ) . TList = (. TypeAnnotation ty; .) '[' Type (. typ = TypeAnnotation(TypeOperator::ARRAY, {ty}); .) {',' Type (. typ.__operator = TypeOperator::TUPLE; typ.__operands.push_back(ty); .) }']' . TStruct = (. TypeAnnotation t; std::wstring field; .) lcurbrack Ident tagcolon Type (. typ = TypeAnnotation(TypeOperator::STRUCT, {t}); typ.fields.push_back(Atom(field).get()); .) {',' Ident tagcolon Type} (. typ.__operands.push_back(t); typ.fields.push_back(Atom(field).get()); .) rcurbrack. TDecl = (. std::wstring ttag; TypeAnnotation t, t1; std::wstring tname, arg; std::vector> args; .) Ident assign "type" ( "alias" Type (. root->add(move(t), Atom(tname)); .) | "variant" lparen Ident (. t = TypeAnnotation(TypeOperator::VARIANT, {}); args.push_back(Atom(arg)); .) {',' Ident (. args.push_back(Atom(arg)); .) } rparen (. t.addFields(move(args)); root->add(move(t), Atom(tname)); .) | Ident ['(' Ident (. args.push_back(Atom(arg)); .) {',' Ident (. args.push_back(Atom(arg)); .) } ')'] Type (. t.addBindings(move(args)); root->add(move(t), Atom(tname)); .) ) '.' . ContextDecl = (. Expression tag; .) context tagcolon MetaSimpExpr (. scope->tags.push_back(tag); .) {';' MetaSimpExpr (. scope->tags.push_back(tag); .) }. VDecl = (. std::wstring vname; Expression var, value;.) VarIdent assign ExprTyped (. f->addDeclaration(move(var), move(value)); .) . //TODO forbid multiple body declaration (ExprTyped) BDecl = lcurbrack (. Expression body; pushContextScope(scope); .) {(IF(checkAssignment()) VDecl '.' | RuleContextDecl | ContextDecl'.' | ExprTyped (. scope->setBody(body); .) )} (. popContextScope(); .) rcurbrack . -IfDecl = (. Expression cond; ManagedScpPtr blockTrue = root->add(new xreate::CodeScope(context.scope)); ManagedScpPtr blockFalse = root->add(new xreate::CodeScope(context.scope)); .) +IfDecl = (. Expression cond; ManagedScpPtr blockTrue = root->add(new CodeScope(context.scope)); ManagedScpPtr blockFalse = root->add(new CodeScope(context.scope)); .) "if" '(' Expr ')' (. e = Expression(Operator::IF, {cond}); .) tagcolon ExprAnnotations BDecl<&*blockTrue> "else" BDecl<&*blockFalse> (. e.addBlock(blockTrue); e.addBlock(blockFalse); .) . LoopDecl = (. Expression eIn, eAcc, eFilters; std::wstring varEl, varAcc, contextClass; Expression tagsEl; - ManagedScpPtr block = root->add(new xreate::CodeScope(context.scope)); .) + ManagedScpPtr block = root->add(new CodeScope(context.scope)); .) "loop" ("map" '(' Expr implic Ident (. e = Expression(Operator::MAP, {eIn}); .) tagcolon ExprAnnotations ')' tagcolon ExprAnnotations BDecl<&*block> (. e.addBindings({Atom(varEl)}); block->addBinding(Atom(varEl), move(tagsEl)); e.addBlock(block); .) |"fold" ("inf" '(' Expr implic Ident ')' (. e = Expression(Operator::FOLD_INF, {eAcc}); e.addBindings({Atom(varAcc)}); .) tagcolon ExprAnnotations BDecl<&*block> (. block->addBinding(Atom(varAcc), Expression()); e.addBlock(block); .) | '(' Expr implic Ident tagcolon ExprAnnotations ['|' Expr ] ',' Expr implic Ident')' (. e = Expression(Operator::FOLD, {eIn, eAcc}); e.addBindings({Atom(varEl), Atom(varAcc)}); .) tagcolon ExprAnnotations BDecl<&*block> (. block->addBinding(Atom(varEl), move(tagsEl)); block->addBinding(Atom(varAcc), Expression()); e.addBlock(block); .) ) | "context" '(' string (. contextClass = t->val; .) ')' BDecl<&*block> (. e = Expression(Operator::LOOP_CONTEXT, {Expression(Atom(std::move(contextClass)))}); e.addBlock(block); .) ). SwitchDecl = (. TypeAnnotation typ; eSwitch = Expression(Operator::SWITCH, {}); Expression eCondition; Expression tag;.) ["switch" ( "ad" "hoc" lparen Expr tagcolon MetaSimpExpr rparen (. eSwitch.op = Operator::SWITCH_ADHOC; eSwitch.operands.push_back(eCondition); eSwitch.addTags({tag}); flagSwitchKind = SWITCH_META; .) | lparen Expr rparen tagcolon ExprAnnotations (. eSwitch.operands.push_back(eCondition);.) ) ] CaseDecl {CaseDecl} . -CaseDecl = (. ManagedScpPtr scope = root->add(new xreate::CodeScope(context.scope)); Expression condition; .) +CaseDecl = (. ManagedScpPtr scope = root->add(new CodeScope(context.scope)); Expression condition; .) "case" ( IF(flagSwitchKind == SWITCH_META) lparen MetaSimpExpr rparen BDecl<&*scope> (. Expression exprCase(Operator::CASE, {}); exprCase.addTags({condition}); exprCase.addBlock(scope); outer.addArg(move(exprCase));.) | "default" BDecl<&*scope> (. Expression exprCase(Operator::CASE_DEFAULT, {}); exprCase.addBlock(scope); outer.operands.insert(++outer.operands.begin(), exprCase); .) - | lparen CaseParams<&*scope> rparen (. ManagedScpPtr scopeBody = root->add(new xreate::CodeScope(&*scope)); Expression exprCase(Operator::CASE, {}); .) + | lparen CaseParams<&*scope> rparen (. ManagedScpPtr scopeBody = root->add(new CodeScope(&*scope)); Expression exprCase(Operator::CASE, {}); .) BDecl<&*scopeBody> (. exprCase.addBlock(scope); exprCase.addBlock(scopeBody); outer.addArg(move(exprCase)); .) ). CaseParams = (. Expression condition; Expression guard(Operator::LOGIC_AND, {}); pushContextScope(scope); .) ExprTyped (. guard.addArg(Expression(condition)); .) {',' ExprTyped (. guard.addArg(Expression(condition)); .) } (. scope->setBody(guard); popContextScope(); .) . IntrinsicDecl= (. std::wstring name; .) "intrinsic" Ident< name> (. outer = Expression(Operator::CALL_INTRINSIC, {}); outer.setValue(Atom(name)); .) lparen [CalleeParams] rparen . /*============================ INTERFACES ===============================*/ Imprt<> = "import" "raw" lparen string (. root->__rawImports.push_back(Atom(t->val).get()); .) rparen '.'. InterfaceData<> = "interface" '(' ( "dfa" ')' InterfaceDFA | "extern-c" ')' InterfaceExternC | "cfa" ')' InterfaceCFA | "adhoc" ')' InterfaceAdhoc ). InterfaceAdhoc<> = '{' { PrefunctionSchemeDecl } '}'. PrefunctionSchemeDecl<> = (. TypeAnnotation typReturn; std::wstring prefName; Expression exprCases; .) pre function Ident tagcolon Type lcurbrack SwitchDecl rcurbrack (. Expression prefData(Operator::CALL, {Atom(prefName), exprCases}); prefData.bindType(typReturn); root->addInterfaceData(Adhoc, move(prefData)); .). -InterfaceExternC<> = (.xreate::ExternData data; .) +InterfaceExternC<> = (. ExternData data; .) '{' {IncludeExternDecl | LibExternDecl } '}' (. root->addExternData(move(data)); .) . -LibExternDecl = (. std::wstring pkgname, libname; .) +LibExternDecl = (. std::wstring pkgname, libname; .) Ident assign "library" tagcolon "pkgconfig" '(' string (. pkgname = t->val; .) ')' '.' (. data.addLibrary(Atom(libname), Atom(pkgname)); .) . -IncludeExternDecl = (. Expression inc; .) +IncludeExternDecl = (. Expression inc; .) "include" StructLiteral '.' (. data.addIncludeDecl(move(inc)); .) . InterfaceDFA<> = '{' { InstructDecl } '}' . InstructDecl = (.Operator op; Expression tag; Expression scheme; std::vector& tags = scheme.operands; tags.push_back(Expression()); /* return value */ .) "operator" InstructAlias tagcolon '(' (.scheme.setOp(op); .) [ MetaSimpExpr (. tags.push_back(tag); .) { ',' MetaSimpExpr (. tags.push_back(tag); .) } ] ')' [ implic MetaSimpExpr (. tags[0] = tag; .) ] (. root->addDFAData(move(scheme)); .) '.'. InstructAlias = ( "map" (. op = Operator::MAP; .) | "list_range" (. op = Operator::LIST_RANGE; .) | "list" (. op = Operator::LIST; .) | "fold" (. op = Operator::FOLD; .) | "index" (. op = Operator::INDEX; .) ). InterfaceCFA<> = '{' { InstructCFADecl } '}' . InstructCFADecl<> = (.Operator op; Expression tag; Expression scheme; std::vector& tags = scheme.operands; .) "operator" InstructAlias tagcolon (. scheme.setOp(op); .) [ MetaSimpExpr (. tags.push_back(tag); .) { ',' MetaSimpExpr (. tags.push_back(tag); .) } ] '.' (. root->addInterfaceData(CFA, move(scheme)); .). /*============================ METAPROGRAMMING ===============================*/ // TagsDecl = (. Expression tag; TagModifier mod = TagModifier::NONE; .) // ':' { MetaSimpExpr (. /*f.addTag(std::move(tag), mod); */ .) // }. FnTag = (. Expression tag; TagModifier mod = TagModifier::NONE; .) MetaSimpExpr ['-' TagMod] (. f->addTag(std::move(tag), mod); .). TagMod = ( "assert" (. mod = TagModifier::ASSERT; .) | "require" (. mod = TagModifier::REQUIRE; .) ). RuleDecl<> = "rule" tagcolon (. RuleArguments args; RuleGuards guards; DomainAnnotation typ; std::wstring arg; .) '(' Ident tagcolon Domain (. args.add(arg, typ); .) {',' Ident tagcolon Domain (. args.add(arg, typ); .) } ')' ["case" RGuard {',' RGuard}] '{' RBody '}' . /* - TODO use RGuard for guards-*/ RuleContextDecl = (.Expression eHead, eGuards, eBody; .) "rule" "context" tagcolon MetaSimpExpr "case" lparen MetaSimpExpr rparen '{' MetaSimpExpr '}' (.scope->contextRules.push_back(Expression(Operator::CONTEXT_RULE, {eHead, eGuards, eBody})); .). Domain = ( "function" (. dom = DomainAnnotation::FUNCTION; .) | "variable" (. dom = DomainAnnotation::VARIABLE; .) ). RGuard= (. Expression e; .) MetaExpr (. guards.add(std::move(e)); .). MetaExpr= (.Operator op; Expression e2; .) MetaExpr2 [MetaOp MetaExpr2 (. e = Expression(op, {e, e2}); .) ]. MetaExpr2= ( '(' MetaExpr ')' | MetaSimpExpr ). MetaSimpExpr= (. std::wstring i1, infix; Expression e2; .) ( '-' MetaSimpExpr (. e = Expression(Operator::NEG, {e2}); .) | IF(checkParametersList()) Ident (. e = Expression(Operator::CALL, {Expression(Atom(i1))}); .) '(' [ MetaCalleeParams ] ')' | IF(checkInfix()) Ident Ident MetaSimpExpr (. e = Expression(Operator::CALL, {Expression(Atom(infix))}); e.addArg(Expression(Atom(i1))); e.addArg(std::move(e2)); .) | Ident (. e = Expression(Atom(i1)); .) ). MetaCalleeParams = (. Expression e2; .) MetaSimpExpr (. e.addArg(Expression(e2)); .) {',' MetaSimpExpr (. e.addArg(Expression(e2)); .) }. RBody = (. Expression e; std::wstring msg; .) "warning" MetaExpr ["message" string (. msg = t->val; .) ] (. root->add(new RuleWarning(RuleArguments(args), RuleGuards(guards), std::move(e), Atom(msg))); .) . MetaOp< Operator& op> = implic (. op = Operator::IMPL; .) . /*============================ Expressions ===============================*/ ExprAnnotations = (. TypeAnnotation typ; std::list tags; Expression tag; e.tags.clear();.) Type (. e.bindType(move(typ)); .) {';' MetaSimpExpr (. tags.push_back(tag); .) } (. e.addTags(tags); .) . ExprTyped = Expr [tagcolon ExprAnnotations]. Expr< Expression& e> (. Operator op; Expression e2; .) = ExprArithmAdd [ RelOp ExprArithmAdd (. e = Expression(op, {e, e2}); .) ]. ExprArithmAdd< Expression& e>= (. Operator op; Expression e2; .) ExprArithmMul< e> [ AddOp< op> ExprArithmAdd< e2> (. e = Expression(op, {e, e2});.) ]. ExprArithmMul< Expression& e> (. Operator op; Expression e2; .) = ExprPostfix< e> [ MulOp< op> ExprArithmMul< e2> (. e = Expression(op, {e, e2}); .) ]. ExprPostfix = Term [lbrack (. e = Expression(Operator::INDEX, {e}); .) CalleeParams rbrack ]. Term< Expression& e> (. std::wstring name; e = Expression(); .) = (IF (checkParametersList()) Ident< name> (. e = Expression(Operator::CALL, {Atom(name)}); .) '(' [CalleeParams] ')' | VarIdent (. recognizeIdentifier(e); .) | ListLiteral (. /* tuple */.) | StructLiteral (. /* struct */.) | LoopDecl | IfDecl | SwitchDecl | AdhocDecl | IntrinsicDecl | "true" (. e = Expression(Atom(1)); e.bindType(TypePrimitive::Bool); .) | "false" (. e = Expression(Atom(0)); e.bindType(TypePrimitive::Bool); .) | number (. e = Expression(Atom(t->val)); .) | string (. e = Expression(Atom(t->val)); .) | '-' Term (. e = Expression(Operator::NEG, {e}); .) | '(' ExprTyped ')' ). StructLiteral = (. std::wstring key; Expression val; std::list> keys; .) '{' Ident '=' Expr (. keys.push_back(Atom(key)); e = Expression(Operator::LIST_NAMED, {val}); .) {',' Ident '=' Expr (.e.addArg(Expression(val)); keys.push_back(Atom(key)); .) } '}' (. e.addBindings(keys.begin(), keys.end()); .) . ListLiteral = (. Expression eFrom, eTo; .) '[' [ Expr (. e.addArg(Expression(eFrom)); .) (".." Expr (. e.addArg(Expression(eTo)); e.setOp(Operator::LIST_RANGE); .) |{',' Expr (. e.addArg(Expression(eFrom)); .) } (. e.setOp(Operator::LIST); .) ) ] ']'. AdhocDecl = (. Expression command; .) -"ad" "hoc" MetaSimpExpr (. AdhocExpression exprAdhoc; exprAdhoc.setCommand(command); e = exprAdhoc; .). +"ad" "hoc" MetaSimpExpr (. adhoc::AdhocExpression exprAdhoc; exprAdhoc.setCommand(command); e = exprAdhoc; .). CalleeParams = (. Expression e2; .) ExprTyped (. e.addArg(Expression(e2)); .) {',' ExprTyped (. e.addArg(Expression(e2)); .) }. AddOp< Operator& op> = (. op = Operator::ADD; .) ( '+' | '-' (. op = Operator::SUB; .) ). MulOp< Operator& op> = (. op = Operator::MUL; .) ( '*' | '/' (. op = Operator::DIV; .) ). RelOp< Operator& op> = (. op = Operator::EQU; .) ( equal | (ne1 | ne2) (. op = Operator::NE; .) | lse (. op = Operator::LSE; .) | lss (. op = Operator::LSS; .) | gte (. op = Operator::GTE; .) | gtr (. op = Operator::GTR; .) ). SkipModulesSection = "module" '{' {ANY} '}'. END Xreate.