diff --git a/config/default.json b/config/default.json index 4f05447..b193258 100644 --- a/config/default.json +++ b/config/default.json @@ -1,74 +1,73 @@ { "containers": { "id": { "implementations": "impl_fulfill_cluster", "clusters": "var_cluster", "prototypes": "proto_cluster", "linkedlist": "linkedlist" }, "impl": { "solid": "solid", "onthefly": "on_the_fly" } }, "logging": { "id": "logging" }, "function-entry": "entry", "clasp": { "bindings" : { "variable": "bind", "function": "bind_func", "scope": "bind_scope", "function_demand" : "bind_function_demand", "scope_decision": "bind_scope_decision" }, "context" : { "decisions":{ "dependent": "resolution_dependency" } }, "nonevalue": "nonevalue", "ret": { "symbol": "retv", "tag": "ret" } }, "tests": { - "template": "virtualization", + "template": "latereasoning", "templates": { "current-fix":"*", - "default": "*-Adhoc.*:Containers.*:Compilation.full_IFStatementWithVariantType:Types.full_VariantType_Switch1:Context.full_LateContext:Context.pathDependentContext:Virtualization.test1", + "default": "*-Adhoc.*:Containers.*:Compilation.full_IFStatementWithVariantType:Types.full_VariantType_Switch1:Context.full_LateContext:Context.pathDependentContext:CFA.testLoopContextExists", "ast": "AST.*", - "adhocs": "Adhoc.*", "effects": "Effects.*", "basic": "Attachments.*", - "context": "Context.*", "compilation": "Compilation.*-Compilation.full_IFStatementWithVariantType", "communication": "Communication.*", "cfa": "CFA.*", "containers": "Containers.*", "dfa": "DFA.*", "diagnostic": "Diagnostic.*", "dsl": "Association.*:Interpretation.*", "exploitation": "Exploitation.*", "ExpressionSerializer": "ExpressionSerializer.*", "externc": "InterfaceExternC.*", "loops": "Loop.*", + "latereasoning": "LateReasoning.*", "modules": "Modules.*", "polymorphs": "Polymorphs.call1", "types": "Types.*", "virtualization": "Virtualization.test2", "vendorsAPI/clang": "ClangAPI.*", "vendorsAPI/xml2": "libxml2*" } } } diff --git a/cpp/src/CMakeLists.txt b/cpp/src/CMakeLists.txt index 22def64..c7e0c70 100644 --- a/cpp/src/CMakeLists.txt +++ b/cpp/src/CMakeLists.txt @@ -1,229 +1,227 @@ 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 + clasplayer.cpp query/polymorph.cpp analysis/dfagraph.cpp pass/dfapass.cpp compilation/targetinterpretation.cpp pass/interpretationpass.cpp ast.cpp xreatemanager.cpp analysis/typeinference.cpp aux/xreatemanager-decorators.cpp compilation/operators.cpp compilation/transformations.cpp compilation/transformersaturation.cpp pass/compilepass.cpp pass/versionspass.cpp attachments.cpp ExternLayer.cpp analysis/cfagraph.cpp - analysis/aux.cpp + analysis/utils.cpp compilation/containers.cpp compilation/advancedinstructions.cpp - clasplayer.cpp - query/context.cpp llvmlayer.cpp utils.cpp pass/abstractpass.cpp pass/cfapass.cpp - pass/adhocpass.cpp contextrule.cpp query/containers.cpp analysis/DominatorsTreeAnalysisProvider.cpp aux/serialization/expressionserializer.cpp modules.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 ${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/cfagraph.cpp b/cpp/src/analysis/cfagraph.cpp index f4b8292..adbf469 100644 --- a/cpp/src/analysis/cfagraph.cpp +++ b/cpp/src/analysis/cfagraph.cpp @@ -1,204 +1,204 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * File: CFAGraph.cpp * Author: pgess * * Created on June 27, 2016, 2:09 PM */ /** * \file cfagraph.h * \brief Control Flow Analysis(CFA) graph data * */ #include "analysis/cfagraph.h" -#include "analysis/aux.h" +#include "analysis/utils.h" 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->guard.isValid()){ list guardRaw = xreate::analysis::compile(f->guard); assert(guardRaw.size() == 1); output << formatSpecializations % (f->getName()) % (guardRaw.front()) << endl; } } //Dependencies boost::format formatDependencies("cfa_scope_depends(%1%, %2%)."); for(const auto relation: __dependencyRelations){ output << formatDependencies % relation.first % relation.second << endl; } std::multimap __dependencyRelations; } 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; } void CFAGraph::addDependency(const ScopePacked& scope, const ScopePacked& scopeDependency){ __dependencyRelations.emplace(scope, scopeDependency); } bool CFAGraph::isDependent(const ScopePacked& scope) const{ return __dependencyRelations.count(scope) > 0; } void CFAGraph::transmitDependencies(const ScopePacked& scopeTo, const ScopePacked& scopeFrom){ auto range = __dependencyRelations.equal_range(scopeFrom); std::list dependencies; for (auto pairI = range.first; pairI != range.second; ++pairI){ dependencies.push_back(pairI->second); } for(auto dep: dependencies){ __dependencyRelations.emplace(scopeTo, dep); } } diff --git a/cpp/src/analysis/dfagraph.cpp b/cpp/src/analysis/dfagraph.cpp index 8abf8e7..fc4fbd8 100644 --- a/cpp/src/analysis/dfagraph.cpp +++ b/cpp/src/analysis/dfagraph.cpp @@ -1,239 +1,239 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * File: DFAGraph.h * Author: pgess * */ /** * \file dfagraph.h * \brief Data Flow Analysis(DFA) graph data * */ #include "analysis/dfagraph.h" -#include "analysis/aux.h" +#include "analysis/utils.h" #include using namespace std; namespace xreate {namespace dfa { struct VisitorNodeHash : public boost::static_visitor { std::size_t operator()(const xreate::SymbolPacked& node) const noexcept { return 2* (node.identifier + 2 * node.scope + 3 * std::abs(node.version)) + 1; } std::size_t operator()(const xreate::dfa::SymbolAnonymous& node) const noexcept { return 2 * node.id; } }; }} std::size_t hash::operator()(xreate::dfa::SymbolNode const& s) const noexcept { return boost::apply_visitor(xreate::dfa::VisitorNodeHash(), s); } namespace xreate { namespace dfa { bool operator==(const SymbolAnonymous& s1, const SymbolAnonymous& s2){ return s1.id == s2.id && s1.flagIsUsed == s2.flagIsUsed; } //NOTE: Any changes should be reflected in ParseImplAtom class VisitorFormatSymbol: public boost::static_visitor { public: boost::format operator()(const SymbolPacked& node) const { boost::format formatSymbNamed("s(%1%,%2%,%3%)"); return formatSymbNamed % node.identifier % node.version % node.scope ; } boost::format operator()(const SymbolAnonymous& node) const { //boost::format formatSymbAnonymous("anon(%1%)"); boost::format formatSymbAnonymous("a%1%"); return formatSymbAnonymous % node.id; } }; void DFACallInstance::print(std::ostringstream& output) const{ boost::format formatArgs; boost::format formatInstance("dfa_callinstance(%1%, %2%)."); boost::format formatRet("dfa_callret(%1%, %2%)."); switch (type) { case WEAK: formatArgs = boost::format("weak(dfa_callargs(%1%, %2%, %3%))."); break; case STRONG: formatArgs = boost::format("weak(dfa_callargs(%1%, %2%, %3%)).\ndfa_callargs(%1%, %2%, %3%)."); break; } output << formatInstance % id % fnName << endl; for(std::pair rec: args) { SymbolNode argFormal(rec.first); output << formatArgs % id % boost::apply_visitor(VisitorFormatSymbol(), argFormal) % boost::apply_visitor(VisitorFormatSymbol(), rec.second) << endl; } output << formatRet % id % boost::apply_visitor(VisitorFormatSymbol(), retActual) << endl; } void DFAGraph::addDependency(const SymbolNode& node, const SymbolNode& subnode){ __dependencies.emplace(node, subnode); if (boost::get(&node)){ __usedSymbols.insert(node); } if (boost::get(&subnode)){ __usedSymbols.insert(node); } } void DFAGraph::printDependencies(std::ostringstream& output) const{ for(const SymbolNode& root: __roots){ printDependency(output, root, root); } } void DFAGraph::printDependency(std::ostringstream& output, const SymbolNode& nodeCurrent, const SymbolNode& nodeDependent) const { auto range = __dependencies.equal_range(nodeCurrent); for (auto it = range.first; it != range.second; ++it){ if (boost::get(&it->second)){ if (!__usedSymbols.count(it->second)){ printDependency(output, it->second, nodeDependent); continue; } } boost::format formatDependency("dfa_depends(%1%, %2%)."); output << formatDependency % boost::apply_visitor(VisitorFormatSymbol(), nodeDependent) % boost::apply_visitor(VisitorFormatSymbol(), it->second) << endl; printDependency(output, it->second, it->second); } } void DFAGraph::printInplaceAnnotations(SymbolNode node, const Expression& expression) { // write down in-place expression tags: boost::format formatBind("bind(%1%, %2%)."); if (expression.tags.size()) __usedSymbols.insert(node); for (const pair& tag : expression.tags){ for (const string& tagPart: xreate::analysis::compile(tag.second)) { __output << formatBind % boost::apply_visitor(VisitorFormatSymbol(), node) % tagPart << endl; } } } void DFAGraph::printAlias(const SymbolNode& symbFormal, const SymbolNode& symbActual){ __usedSymbols.insert(symbFormal); __usedSymbols.insert(symbActual); boost::format formatAlias("dfa_alias(%1%, %2%)."); __output << formatAlias % boost::apply_visitor(VisitorFormatSymbol(), symbFormal) % boost::apply_visitor(VisitorFormatSymbol(), symbActual) << endl; } void DFAGraph::printWeakAlias(const SymbolNode& symbFormal, const SymbolNode& symbActual){ __usedSymbols.insert(symbFormal); __usedSymbols.insert(symbActual); boost::format formatAlias("weak(dfa_alias(%1%, %2%))."); __output << formatAlias % boost::apply_visitor(VisitorFormatSymbol(), symbFormal) % boost::apply_visitor(VisitorFormatSymbol(), symbActual) << endl; } void DFAGraph::printFunctionRet(ManagedFnPtr function, const SymbolNode& symbolRet){ boost::format formatRet("dfa_fnret(%1%, %2%)."); __usedSymbols.insert(symbolRet); __output << formatRet % function->getName() % boost::apply_visitor(VisitorFormatSymbol(), symbolRet) << endl; __roots.insert(symbolRet); } void DFAGraph::addCallInstance(DFACallInstance&& instance){ __usedSymbols.insert(instance.retActual); for(const auto arg: instance.args){ __usedSymbols.insert(SymbolNode(arg.first)); __usedSymbols.insert(arg.second); } __callInstances.push_back(std::move(instance)); } void DFAGraph::print(std::ostringstream& output) const{ output << endl << "%\t\tStatic analysis: DFA" << endl; //Dependencies printDependencies(output); //Add generated report output << __output.str() << endl; //Call instances for(const DFACallInstance& instance: __callInstances){ instance.print(output); } output << endl; } void DFAGraph::printSymbols(ClaspLayer* clasp){ boost::format formatHint("shint(%1%, \"%2%\")."); for (const SymbolNode& node : __usedSymbols) { __output << "v(" << boost::apply_visitor(VisitorFormatSymbol(), node) << "). "; if (const SymbolPacked* symbol = boost::get(&node)){ __output << formatHint % boost::apply_visitor(VisitorFormatSymbol(), node) % clasp->getHintForPackedSymbol(*symbol); } __output << endl; } } }} //end of namespace xreate::dfa diff --git a/cpp/src/analysis/aux.cpp b/cpp/src/analysis/utils.cpp similarity index 99% rename from cpp/src/analysis/aux.cpp rename to cpp/src/analysis/utils.cpp index 27c3f6b..c089196 100644 --- a/cpp/src/analysis/aux.cpp +++ b/cpp/src/analysis/utils.cpp @@ -1,142 +1,142 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * aux.cpp * * Author: pgess */ /** * \file aux.h * \brief Data representation in ASP format ready for use by reasoner */ -#include "aux.h" +#include "utils.h" #include namespace xreate { namespace analysis { using namespace std; list multiplyLists(list> &&lists) { typedef list StringList; assert(lists.size()); StringList result(*lists.begin()); lists.pop_front(); boost::format concat("%s, %s"); for (StringList &list: lists) { StringList::const_iterator end = result.end(); for (StringList::iterator expr1I = result.begin(); expr1I != end; ++expr1I) { if (list.size() == 0) continue; StringList::const_iterator expr2I = list.begin(); for (int expr2No = 0, size = list.size() - 1; expr2No < size; ++expr2No, ++expr1I) result.push_back(str(concat %(*expr1I) %(*expr2I))); *expr1I = str(concat %(*expr1I) %(*expr2I)); } } return result; } std::list compile(const Expression &e){ list result; switch (e.op) { case Operator::CALL: { assert(e.__state == Expression::COMPOUND); if(!e.operands.size()){ result.push_back(e.getValueString()); break; } std::list> operands; std::transform(e.operands.begin(), e.operands.end(), std::inserter(operands, operands.begin()), [](const Expression &e) { return compile(e); }); list &&operands_ = multiplyLists(std::move(operands)); result.push_back(boost::str(boost::format("%1%(%2%)") % (e.getValueString()) % (boost::algorithm::join(operands_, ", ")))); break; } case Operator::NEG: { assert(e.operands.size() == 1); const Expression &op = e.operands.at(0); list &&rawOp = compile(op); assert(rawOp.size() == 1); result.push_back((boost::format("not %1%")%(rawOp.front())).str()); break; }; case Operator::INVALID: { switch (e.__state) { case Expression::IDENT: result.push_back(e.getValueString()); break; case Expression::NUMBER: result.push_back(to_string(e.getValueDouble())); break; default: assert(true); } break; } default: break; } //TODO Null ad hoc ClaspLayer implementation // if (e.isNone()){ // result.push_back(e.__valueS); // } assert(result.size()); return result; } std::list compileNeg(const Expression &e){ list result; switch (e.op) { case Operator::IMPL: { assert(e.__state == Expression::COMPOUND); assert(e.operands.size() == 2); list operands1 = compile(e.operands.at(0)); list operands2 = compile(e.operands.at(1)); boost::format formatNeg("%1%, not %2%"); for (const auto &op1: operands1) for (const auto &op2: operands2) { result.push_back(boost::str(formatNeg %(op1) % (op2))); } break; } case Operator::NEG: { assert(e.operands.size() == 1); const Expression &op = e.operands.at(0); list &&rawOp = compile(op); assert(rawOp.size() == 1); result.push_back(rawOp.front()); break; }; default: assert(true); } return result; } }} diff --git a/cpp/src/analysis/aux.h b/cpp/src/analysis/utils.h similarity index 100% rename from cpp/src/analysis/aux.h rename to cpp/src/analysis/utils.h diff --git a/cpp/src/ast.h b/cpp/src/ast.h index 57a4c2a..904bc31 100644 --- a/cpp/src/ast.h +++ b/cpp/src/ast.h @@ -1,733 +1,741 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * Author: pgess * File: ast.h */ #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 store line:col for all atoms/identifiers 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); Atom(std::string && name); 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, LIST, LIST_NAMED, ACCESS, LINK }; struct llvm_array_tag { }; struct struct_tag { }; const llvm_array_tag tag_array = llvm_array_tag(); const struct_tag tag_struct = struct_tag(); /** * \brief Represents type to support type system * * This class represents type in denormalized form, i.e. without arguments and aliases substitution * \sa AST::expandType() */ 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 { INVALID, UNDEF, ADD, SUB, MUL, DIV, EQU, NE, NEG, LSS, LSE, GTR, GTE, LIST, LIST_RANGE, LIST_NAMED, CALL, CALL_INTRINSIC, IMPL/* implication */, MAP, FOLD, FOLD_INF, LOOP_CONTEXT, INDEX, IF, SWITCH, SWITCH_ADHOC, SWITCH_VARIANT, CASE, CASE_DEFAULT, LOGIC_AND, ADHOC, CONTEXT_RULE, VARIANT, SEQUENCE }; class Function; class AST; class CodeScope; class MetaRuleAbstract; typedef ManagedPtr ManagedFnPtr; typedef ManagedPtr ManagedScpPtr; typedef ManagedPtr ManagedRulePtr; const ManagedScpPtr NO_SCOPE = ManagedScpPtr(UINT_MAX, 0); /** * \brief Represents every instruction in Xreate's syntax tree * \attention In case of any changes update xreate::ExpressionHints auxiliary helper as well * * Expression is generic building block of syntax tree able to hold node data * as well as child nodes as operands. Not only instructions use expression for representation in syntax tree * but annotation as well. * * Additionally, `types` as a special kind of annotations use Expression-like data structure TypeAnnotation * \sa xreate::AST, xreate::TypeAnnotation */ // 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; /** * \brief is it string, number, compound operation and so on */ enum { INVALID, COMPOUND, IDENT, NUMBER, STRING, BINDING } __state = INVALID; /** * \brief Valid for compound State. Holds type of compound operator */ Operator op; /** * \brief Unique id to identify expression within syntax tree */ unsigned int id; /** * \brief Exact meaning depends on particular instruction * \details As an example, named lists/structs hold field names in bindings */ std::vector bindings; std::map __indexBindings; /** * \brief Holds child instructions as arguments */ std::vector operands; /** * \brief Holds type of instruction's result */ TypeAnnotation type; /** * \brief Holds additional annotations */ mutable std::map tags; /** * \brief Child code blocks * \details For example, If statement holds TRUE-branch as first and FALSE-branch as second block here */ 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 }; enum class DomainAnnotation { FUNCTION, VARIABLE }; class RuleArguments : public std::vector> { public: void add(const Atom& name, DomainAnnotation typ); }; class RuleGuards : public std::vector { public: void add(Expression&& e); }; 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; namespace versions { typedef int VariableVersion; const VariableVersion VERSION_NONE = -2; const VariableVersion VERSION_INIT = 0; } template<> struct AttachmentsDict { typedef versions::VariableVersion Data; static const unsigned int key = 6; }; struct ScopedSymbol { VNameId id; versions::VariableVersion version; static const ScopedSymbol RetSymbol; }; struct Symbol { ScopedSymbol identifier; const CodeScope * scope; }; struct IdentifierSymbol{}; struct SymbolAlias{}; template<> struct AttachmentsDict { typedef Symbol Data; static const unsigned int key = 7; }; template<> struct AttachmentsDict { typedef Symbol Data; static const unsigned int key = 9; }; 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); /** * \brief Represents code block and single scope of visibility * * Holds single expression as a *body* and set of variable assignments(declarations) used in body's expression * \sa xreate::AST */ class CodeScope { friend class Function; friend class PassManager; public: CodeScope(CodeScope* parent = 0); ~CodeScope(); /** \brief Set expression as a body */ void setBody(const Expression& body); /** \brief Returns current code scope body */ const Expression& getBody() const; /** \brief Adds variable definition to be used in body as well as in other declarations */ Symbol addDefinition(Expression&& var, Expression&& body); /** \brief Returns symbols' definition */ static const Expression& getDefinition(const Symbol& symbol, bool flagAllowUndefined = false); const Expression& getDefinition(const ScopedSymbol& symbol, bool flagAllowUndefined = false) const; /** \brief Adds variable defined elsewhere */ void addBinding(Expression&& var, Expression&& argument); std::vector __bindings; std::map __identifiers; CodeScope* __parent; //TODO move __definitions to SymbolsAttachments data //NOTE: definition of return type has index 0 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); }; /** * \brief Represents single function in Xreate's syntax tree * * Holds an entry code scope and `guardContext` required for function to operate * \sa xreate::AST */ class Function { friend class Expression; friend class CodeScope; friend class AST; public: Function(const Atom& name); /** * \brief Adds function arguments */ void addBinding(Atom && name, Expression&& argument); /** * \brief Adds additional function annotations */ 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 guard; private: std::map __tags; }; class ExternData; struct ExternEntry { std::string package; std::vector headers; }; typedef Expanded ExpandedType; struct TypeInferred{}; template<> struct AttachmentsDict { typedef ExpandedType Data; static const unsigned int key = 11; }; 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); } }; +template<> +struct AttachmentsId{ + static unsigned int getId(const CodeScope* scope){ + const Symbol symbolScope{ScopedSymbol::RetSymbol, scope}; + return AttachmentsId::getId(symbolScope); + } +}; + template<> struct AttachmentsId{ static unsigned int getId(const unsigned int id){ return id; } }; class TypesResolver; namespace details { namespace inconsistent { /** * \brief Syntax tree under construction in inconsistent form * * Represents Syntax Tree under construction(**inconsistent state**). * \attention Clients should use rather xreate::AST unless client's code explicitly works with Syntax Tree during construction. * * Typically instance only created by xreate::XreateManager and filled in by Parser * \sa xreate::XreateManager::prepare(std::string&&) */ class AST { friend class xreate::TypesResolver; public: AST(); /** * \brief Adds new function to AST * \param f Function to register */ void add(Function* f); /** * \brief Adds new declarative rule to AST * \param r Declarative Rule */ void add(MetaRuleAbstract* r); /** \brief Registers new code block */ ManagedScpPtr add(CodeScope* scope); /** * \brief Add new type to AST * @param t Type definition * @param alias Typer name */ void add(TypeAnnotation t, Atom alias); /** \brief Current module's name */ std::string getModuleName(); /** * \brief Looks for function with given name * \param name Function name to find * \note Requires that only one function exists under given name * \return Found function */ ManagedPtr findFunction(const std::string& name); /** \brief Returns all function in AST */ std::list getAllFunctions() const; /** * \brief Returns all specializations of a function with a given name * \param fnName function to find * \return list of found function specializations */ std::list getFunctionSpecializations(const std::string& fnName) const; /** * \return First element in Functions/Scopes/Rules list depending on template parameter * \tparam Target either Function or CodeScope or MetaRuleAbstract */ template ManagedPtr begin(); /** * \brief Performs all necessary steps after AST is built * * Performs all finzalisation steps and move AST into consistent state represented by xreate::AST * \sa xreate::AST * \return AST in consistent state */ xreate::AST* finalize(); typedef std::multimap FUNCTIONS_REGISTRY; 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; protected: std::map __indexTypeAliases; public: /** * \brief Stores DFA scheme for later use by DFA Pass * * Treats expression as a DFA scheme and feeds to a DFA Pass later * \paramn Expression DFA Scheme * \sa xreate::DFAPass */ void addDFAData(Expression&& data); /** \brief Stores data for later use by xreate::ExternLayer */ void addExternData(ExternData&& data); /** * \brief Generalized function to store particular data for later use by particular pass * \param interface Particular Interface * \param data Particular data */ void addInterfaceData(const ASTInterface& interface, Expression&& data); /**\name Symbols Recognition */ ///@{ public: //TODO revisit enums/variants, move to codescope /** * \brief Tries to find out whether expression is Variant constructor */ void recognizeVariantConstructor(Expression& function); Atom recognizeVariantConstructor(Atom ident); private: std::map> __dictVariants; public: std::set> bucketUnrecognizedIdentifiers; public: /** * \brief Postpones unrecognized identifier for future second round of recognition * \param scope Code block identifier is encountered * \param id Identifier */ void postponeIdentifier(CodeScope* scope, const Expression& id); /** \brief Second round of identifiers recognition done right after AST is fully constructed */ void recognizePostponedIdentifiers(); ///@} }; template<> ManagedPtr AST::begin(); template<> ManagedPtr AST::begin(); template<> ManagedPtr AST::begin(); } } // namespace details::incomplete /** * \brief Xreate's Syntax Tree in consistent state * * Syntax Tree has two mutually exclusive possible states: * - inconsistent state while AST is under construction. Represented by xreate::details::inconsistent::AST * - consistent state when AST is built and finalize() is done. * * This class represents consistent state and should be used everywhere unless client's code explicitly works with AST under construction. * Consistent AST enables access to additional functions(currently related to type management). * \sa xreate::details::inconsistent::AST */ class AST : public details::inconsistent::AST { public: AST() : details::inconsistent::AST() {} /** * \brief Computes fully expanded form of type by substituting all arguments and aliases * \param t Type to expand * \return Expdanded or normal form of type * \sa TypeAnnotation */ ExpandedType expandType(const TypeAnnotation &t) const; /** * Searches type by given name * \param name Typename to search * \return Expanded or normal form of desired type * \note if type name is not found returns new undefined type with this name */ ExpandedType findType(const std::string& name); /** * Invokes Type Inference Analysis to find out expanded(normal) form expressions's type * \sa typeinference.h * \param expression * \return Type of expression */ ExpandedType getType(const Expression& expression); }; } #endif // AST_H diff --git a/cpp/src/attachments.h b/cpp/src/attachments.h index 2cbaf47..9072d2c 100644 --- a/cpp/src/attachments.h +++ b/cpp/src/attachments.h @@ -1,178 +1,181 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * Author: pgess * File: attachments.h * Date: 3/15/15 */ #ifndef _XREATE_ATTACHMENTS_H_ #define _XREATE_ATTACHMENTS_H_ #include #include #include #include namespace xreate { //Attachments dictionary template struct AttachmentsDict { // typedef void Data; - // static const unsigned int key (current unreserved - 12); - //reserved attachments: + // static const unsigned int key (next vacant id - 13); + +// Defined attachments: +//----------------------------------------------------- // 1 containers::Implementation // 3 interpretation::InterpretationData // 5 interpretation::FunctionInterpretationData // 6 VariableVersion // 7 IdentifierSymbol // 8 versions::VersionImposedDependency // 9 SymbolAlias // 10 CallGuard Expression // 11 TypeInferred +// 12 LateBinding }; template struct AttachmentsId{ //static unsigned int getId(const Object& object); }; template class IAttachmentsContainer{ protected: virtual bool __exists(const unsigned int object)=0; virtual Data& __get(const unsigned int object)=0; virtual void __put(const unsigned int object, Data data)=0; public: template bool exists(const Id& object){ unsigned int id = AttachmentsId::getId(object); return __exists(id); } template Data& get(const Id& object){ unsigned int id = AttachmentsId::getId(object); return __get(id); } template Data get(const Id& object, const Data& dataDefault){ unsigned int id = AttachmentsId::getId(object); if (! __exists(id)){ return dataDefault; } return __get(id); } template void put(const Id& object, Data data){ unsigned int id = AttachmentsId::getId(object); - __put(id, data); + __put(id, data); } virtual ~IAttachmentsContainer(){}; }; template class AttachmentsContainerDefault: public IAttachmentsContainer{ private: std::unordered_map __data; virtual bool __exists(const unsigned int id){ return __data.count(id); } virtual Data& __get(const unsigned int id){ return __data.at(id); } virtual void __put(const unsigned int id, Data data){ auto result = __data.emplace(id, data); assert(result.second); } public: std::unordered_map& getRawStorage() { return __data; } }; class Attachments{ private: static std::vector __storage; template using Data = typename AttachmentsDict::Data; public: template static bool exists(const Id& object) { assert(AttachmentsDict::key < __storage.size()); assert(__storage.at(AttachmentsDict::key)); IAttachmentsContainer>* self = reinterpret_cast>*>(__storage.at(AttachmentsDict::key)); return self->exists(object); } template static Data& get(const Id& object){ assert(AttachmentsDict::key < __storage.size()); assert(__storage.at(AttachmentsDict::key)); IAttachmentsContainer>* self = reinterpret_cast>*>(__storage.at(AttachmentsDict::key)); return self->get(object); } template static Data get(const Id& object, const Data& dataDefault){ assert(AttachmentsDict::key < __storage.size()); assert(__storage.at(AttachmentsDict::key)); IAttachmentsContainer>* self = reinterpret_cast>*>(__storage.at(AttachmentsDict::key)); return self->get(object, dataDefault); } template static void put(const Id& object, Data data){ assert(AttachmentsDict::key < __storage.size()); assert(__storage.at(AttachmentsDict::key)); IAttachmentsContainer>* self = reinterpret_cast>*>(__storage.at(AttachmentsDict::key)); self->put(object, data); } template static void init(){ unsigned int keyStorage = AttachmentsDict::key; if (keyStorage+1 > __storage.size()){ __storage.resize(keyStorage + 1, nullptr); } __storage[keyStorage] = new AttachmentsContainerDefault>(); } template static void init(IAttachmentsContainer>* container){ unsigned int keyStorage = AttachmentsDict::key; if (keyStorage+1 > __storage.size()){ __storage.resize(keyStorage + 1, nullptr); } __storage[keyStorage] = container; } }; } #endif //_XREATE_ATTACHMENTS_H_ diff --git a/cpp/src/aux/xreatemanager-decorators.cpp b/cpp/src/aux/xreatemanager-decorators.cpp index 5a8c79e..6f3872d 100644 --- a/cpp/src/aux/xreatemanager-decorators.cpp +++ b/cpp/src/aux/xreatemanager-decorators.cpp @@ -1,75 +1,73 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * xreatemanager-decorators.cpp * * Author: pgess * Created on July 16, 2017, 4:40 PM */ /** * \file xreatemanager-decorators.h * \brief \ref xreate::XreateManager decorators to provide various functionality */ #include "aux/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(){ cfa::CFAPass* passCFG = new cfa::CFAPass(this); //TODO is it really DFGPass needs CFGpass? registerPass(new dfa::DFAPass(this), PassId::DFGPass, passCFG); registerPass(passCFG, PassId::CFGPass); - 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 compilation::CompilePassCustomDecorators<>(this)); compiler->run(); llvm->print(); llvm->initJit(); return llvm->getFunctionPointer(compiler->getEntryFunction()); } } //namespace xreate diff --git a/cpp/src/clasplayer.cpp b/cpp/src/clasplayer.cpp index 9cd4de8..325b5ac 100644 --- a/cpp/src/clasplayer.cpp +++ b/cpp/src/clasplayer.cpp @@ -1,382 +1,459 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * Author: pgess * File: clasplayer.cpp */ /** * \file clasplayer.h * \brief Resoner. Wrapper over Clasp reasoner library */ #include "clasplayer.h" -#include "analysis/aux.h" +#include "analysis/utils.h" #include "utils.h" #include #include #include #include +#include using namespace std; //TODO escape identifiers started with upper case symbol namespace xreate { void -ClaspLayer::printWarnings(std::ostream& out) -{ +ClaspLayer::printWarnings(std::ostream& out) { const std::string warningTag = "warning"; - auto warningsRange = __model.equal_range(warningTag); + auto warningsModel = query(warningTag); - for (auto warning=warningsRange.first; warning!= warningsRange.second; ++warning) { + if(warningsModel.size()) + for (auto warning: warningsModel) { unsigned int warningId; Gringo::Symbol params; - std::tie(warningId, params) = parse(warning->second); + 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"); + const string& atomLateStatement = "late"; 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)); + string atomAlias = std::get<1>(parse(atom)).name().c_str(); + __model.addStaticAtom(atomAlias, atom); + + } else if(atomName == atomLateStatement){ + //late atom format: (Symbol, (tuple of keys), (tuple of values), late-annotation) + auto atomLate = parse, std::list, Gringo::Symbol>(atom); + const string& atomAlias = get<3>(atomLate).name().c_str(); + __model.addLateAtom(atomAlias, get<0>(atomLate), + get<3>(atomLate), get<1>(atomLate), + get<2>(atomLate)); } - __model.emplace(atomName, move(atom)); + __model.addStaticAtom(atomName, atom); } return true; } void ClaspLayer::registerReport(IAnalysisReport* report){ __reports.push_back(report); } void ClaspLayer::runReports(){ for(IAnalysisReport* report: __reports){ report->print(__partGeneral); delete report; } __reports.clear(); } 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; + if (!file){ + std::cout << "Can't process script file: " << fn << std::endl; + assert(false); + } while(!file.eof()){ string line; std::getline(file, line); out << line << endl; } } } void ClaspLayer::addRawScript(std::string&& script){ __partGeneral << script; } void ClaspLayer::run() { involveImports(); runReports(); 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::ClaspLayer(): __model(this), ast(nullptr){ } -ClaspLayer::ModelFragment -ClaspLayer::query(const std::string& atom) -{ - if (! __model.count(atom)){ - return boost::none; - } +ReasoningModel +ClaspLayer::queryCompiled(const std::string& atom) { + return __model; +} - return ModelFragment(__model.equal_range(atom)); +StaticModel +ClaspLayer::query(const std::string& atom){ + return __model.queryStatic(atom); } ScopePacked ClaspLayer::pack(const 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){ auto result = __indexSymbolNameHints.find(symbol); return (result == __indexSymbolNameHints.end())? "" : result->second; } 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); } +boost::optional +GuardedAnnotation::get(const std::list& keys) const{ + for (const auto& entry: guardedSymbols){ + const std::list& keysExpected = entry.first; + + auto keysIt = keys.begin(); + bool result = true; + for(const Expression& keyExpected: keysExpected){ + if(! (keyExpected == *keysIt)) {result = false; break; } + ++keysIt; + } + if(!result) continue; + return entry.second; + } + + return boost::none; +} + +std::list +ReasoningModel::findKeys(const std::list& keys) { + std::list result; + std::transform(keys.begin(), keys.end(), std::inserter(result, result.end()), [this](const SymbolPacked& key){ + return Attachments::get(this->clasp->unpack(key)); + }); + + return result; +} + +void ReasoningModel::addStaticAtom(const std::string& atomAlias, const Gringo::Symbol& atom){ + modelStatic.emplace(atomAlias, atom); +} + +void ReasoningModel::addLateAtom(const std::string& alias, const SymbolPacked& symbol, + const Gringo::Symbol& atom, const std::list& guardKeys, + const std::list& guardBindings){ + LateModel& model = modelGuarded[symbol]; + if(!model.bindings.count(alias)){ + model.bindings.emplace(alias, guardKeys); + } + + GuardedAnnotation& annotation = model.annotations[alias]; + annotation.guardedSymbols.push_back(make_pair(guardBindings, atom)); +} + +StaticModel +ReasoningModel::queryStatic(const std::string& alias) { + StaticModel result; + + if (! modelStatic.count(alias)){ + return result; + } + + auto currentDataRange = modelStatic.equal_range(alias); + std::copy(currentDataRange.first, currentDataRange.second, std::inserter(result, result.end())); + return result; +} + +StaticModel +ReasoningModel::queryLate(const std::string& alias, const SymbolPacked& symbol){ + StaticModel result; + if (!modelGuarded.count(symbol)) return StaticModel(); + + const LateModel& model = modelGuarded.at(symbol); + assert(model.bindings.count(alias)); + const list& bindings = model.bindings.at(alias); + list&& keys = findKeys(bindings); + + auto range = model.annotations.equal_range(alias); + for(auto it = range.first; it != range.second; ++it){ + auto annotation = it->second.get(keys); + if(annotation){ + result.emplace(make_pair(alias, *annotation)); + } + } + + return result; +} + Expression ParseImplAtom::get(const Gringo::Symbol& atom) { switch (atom.type()) { case Gringo::SymbolType::Num: return Expression(atom.num()); case Gringo::SymbolType::Str: return Expression(Atom(std::string(atom.string().c_str()))); case Gringo::SymbolType::Fun: { //FUNC Expression result(Operator::CALL,{Expression(Atom(std::string(atom.name().c_str())))}); for (const Gringo::Symbol& arg : atom.args()) { result.addArg(ParseImplAtom::get(arg)); } return result; } default: { assert(false); } } } int ParseImplAtom::get(const Gringo::Symbol& atom) { switch (atom.type()){ case Gringo::SymbolType::Num: return atom.num(); default: break; } assert(false && "Inappropriate symbol type"); } std::string ParseImplAtom::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"); } SymbolPacked ParseImplAtom::get(const Gringo::Symbol& atom) { auto result = ClaspLayer::parse(atom); return SymbolPacked(std::get<0>(result), std::get<1>(result), std::get<2>(result)); }; Gringo::Symbol ParseImplAtom::get(const Gringo::Symbol& atom) { return atom; } -std::list -ParseImplAtom>::get(const Gringo::Symbol& atom){ - assert (atom.type() == Gringo::SymbolType::Fun); - std::list result; - - for (const Gringo::Symbol& arg: atom.args()) { - result.push_back(ParseImplAtom::get(arg)); - } - - return result; -} - } //end of xreate namespace /** * \class xreate::ClaspLayer * \brief Reasoning and logic Solver. * * Wraps external brilliant fantastic tool [Clasp solver](https://potassco.org/clasp/) * * For building *logic program* for reasoning ClaspLayer takes input from: * - Raw scripts. Client could append arbitrary ASP script to _logic program_. \ref addRawScript() * - Includes. There is possibility to specify external files with ASP scripts * to append to _logic program_. \ref involveImports() (private member) * - Diagnostic rules. Rules that produce diagnostic messages during * compilation(warnings) or even able to halt compilation with errors. * addRuleWarning(), \ref registerWarning() * - DFA data. \ref setDFAData() * - CFA data. \ref setCFAData() * - Dominators Analysis. See xreate::dominators::DominatorsTreeAnalysisProvider. * Executed by \ref run() * - Context rules. See xreate::ContextRule and general [Context Explanation](/w/concepts/context) * * Data sources implement xreate::IAnalysisReport. Generally, input could be loosely divided into three categories: * - *Internally derived* data. CFA, DFA, Dominators analyses *automatically* feed reasoner by * useful insights about data, structure and algorithms of a program * - *User provided* data. CFA, DFA, Diagnostic/Context rules feed reasoner by * annotations Developer specifically provides manually * - *External* data. Raw scripts and includes feed reasoner with third-party data * related to a different aspects of a program possibly produced by external analyzers * * Once ClaspLayer got input from all providers and logic program is fully constructed * it runs external Clasp solver and receives back desired solutions. * * Output of Clasp reasoner is recognized and accessed via *queries*. * IQuery represents an interface between reasoner's output and rest of Xreate. * Each query inherits xreate::IQuery interface. Currently there are queries as follows: * - xreate::containers::Query to catch solutions regarding Containers implementation. See [Containers Explanation](/w/concepts/containers) * - xreate::context::ContextQuery to catch solution regarding Context. See [Context Explanation](/w/concepts/context) * * \sa See xreate::dfa::DFAPass, xreate::cfa::CFAPass, xreate::IQuery, xreate::IAnalysisReport, xreate::dominators::DominatorsTreeAnalysisProvider */ \ No newline at end of file diff --git a/cpp/src/clasplayer.h b/cpp/src/clasplayer.h index 1ad660e..ec4c0b9 100644 --- a/cpp/src/clasplayer.h +++ b/cpp/src/clasplayer.h @@ -1,231 +1,275 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * Author: pgess * File: clasplayer.h */ #ifndef CLASPLAYER_H #define CLASPLAYER_H #include "ast.h" #include "contextrule.h" #include #include #include #include #include #include #include #include #include namespace xreate { typedef unsigned int ScopePacked; const ScopePacked SCOPE_ABSTRACT_GLOBAL = std::numeric_limits::max(); struct SymbolPacked { SymbolPacked(){} SymbolPacked(ScopedSymbol i, ScopePacked s): identifier(i.id), version(i.version), scope(s){} SymbolPacked(VNameId symbolId, versions::VariableVersion symbolVersion, ScopePacked symbolScope) : identifier(symbolId), version(symbolVersion), scope(symbolScope){} VNameId identifier; versions::VariableVersion version; ScopePacked scope; }; bool operator==(const SymbolPacked& s1, const SymbolPacked& s2); bool operator<(const SymbolPacked& s1, const SymbolPacked& s2); enum class DFGConnection { STRONG, WEAK, PROTOTYPE }; /** \brief Designated to mark analysis results that can be composed as *logic program* */ class IAnalysisReport { public: /** \brief Composes *logic program* based on analysis data into ASP format and appends to a stream*/ virtual void print(std::ostringstream& output) const = 0; virtual ~IAnalysisReport(){}; }; /** \brief Logic program query interface */ class IQuery { public: virtual void init(ClaspLayer* clasp) = 0; virtual ~IQuery() {} }; enum class QueryId { ContainersQuery, - ContextQuery, - PtrvalidQuery, PolymorphQuery }; namespace dfa{ class DFAGraph; } namespace cfa { class CFAGraph; } +typedef std::multimap StaticModel; +typedef StaticModel::const_iterator StaticModelIterator; + +struct GuardedAnnotation{ + std::list, Gringo::Symbol>> guardedSymbols; + boost::optional get(const std::list& keys) const; +}; + +struct LateModel{ + std::map annotations; + std::map> bindings; +}; + +//DEBT implement querying as a view/joining iterators without actual data copying +//DEBT how to implement late model RESET(invalidate all child models) +class ReasoningModel{ +public: + ReasoningModel(ClaspLayer* claspLayer): clasp(claspLayer) {} + void addLateAtom(const std::string& alias, const SymbolPacked& symbol, + const Gringo::Symbol& atom, const std::list& guardKeys, + const std::list& guardBindings); + void addStaticAtom(const std::string& atomAlias, const Gringo::Symbol& atom); + StaticModel queryStatic(const std::string& atom); + StaticModel queryLate(const std::string& alias, const SymbolPacked& symbol); + +private: + ClaspLayer* clasp; + StaticModel modelStatic; + std::map modelGuarded; + std::list findKeys(const std::list& keys); +}; + +struct LateBinding; + +template<> +struct AttachmentsDict{ + typedef Expression Data; + static const unsigned int key = 12; +}; + class ClaspLayer { - friend class ContextRule; +friend class ContextRule; /**\name Data Providers Management */ ///@{ public: void registerReport(IAnalysisReport* report); void runReports(); /** \brief Appends arbitrary string to *logic program* */ void addRawScript(std::string&& script); private: std::list __reports; /** Includes external text files to a *logic program* */ void involveImports(); ///@} /**\name Queries Management */ ///@{ public: /** \brief Adds query. See xreate::IQuery */ IQuery* registerQuery(IQuery* query, const QueryId& id); /** \brief Returns particular query. See xreate::IQuery */ 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); + StaticModel query(const std::string& atom); + ReasoningModel queryCompiled(const std::string& atom); size_t getScopesCount() const; SymbolPacked pack(const Symbol& symbol, std::string hintSymbolName = ""); ScopePacked pack(const CodeScope * const scope); Symbol unpack(const SymbolPacked& symbol); std::string getHintForPackedSymbol(const SymbolPacked& symbol); ///@} private: std::map __queries; - std::multimap __model; + ReasoningModel __model; std::map __indexSymbolNameHints; std::unordered_map __indexScopes; std::vector __registryScopes; /**\name Diagnostic */ ///@{ //TODO diagnostic move over to separate provider/query public: /** \brief Adds diagnostic rule */ void addRuleWarning(const RuleWarning &rule); /** \brief Registers diagnostic messages */ unsigned int registerWarning(std::string &&message); private: std::map __warnings; void printWarnings(std::ostream& out); ///@} ///@{ public: ClaspLayer(); /** \brief Executes reasoning */ void run(); ///@} AST *ast; 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 int get(const Gringo::Symbol& atom); }; template<> struct ParseImplAtom { static std::string get(const Gringo::Symbol& atom); }; template<> struct ParseImplAtom { static SymbolPacked get(const Gringo::Symbol& atom); }; template<> struct ParseImplAtom { static Gringo::Symbol get(const Gringo::Symbol& atom); }; -template<> -struct ParseImplAtom>{ - static std::list get(const Gringo::Symbol& atom); +template +struct ParseImplAtom>{ + static std::list + get(const Gringo::Symbol& atom){ + assert (atom.type() == Gringo::SymbolType::Fun); + std::list result; + + for (const Gringo::Symbol& arg: atom.args()) { + result.push_back(ParseImplAtom::get(arg)); + } + + return result; + } }; template<> struct ParseImplAtom { static Expression get(const Gringo::Symbol& atom); }; 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; } } //end of xreate namespace #endif diff --git a/cpp/src/compilation/adhocfunctiondecorator.h b/cpp/src/compilation/adhocfunctiondecorator.h deleted file mode 100644 index a26dce8..0000000 --- a/cpp/src/compilation/adhocfunctiondecorator.h +++ /dev/null @@ -1,49 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - * - * File: adhocfunctiondecorator.h - * Author: pgess - * - * Created on July 29, 2017, 12:26 PM - */ - -#ifndef ADHOCFUNCTIONDECORATOR_H -#define ADHOCFUNCTIONDECORATOR_H - -#include "ast.h" -#include "llvmlayer.h" - -using namespace xreate::compilation; - -namespace xreate{ namespace adhoc{ -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; - adhoc::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; -}; - -}} //end of namespace xreate::adhoc - -#endif /* ADHOCFUNCTIONDECORATOR_H */ - diff --git a/cpp/src/compilation/advancedinstructions.cpp b/cpp/src/compilation/advancedinstructions.cpp index 59bbdd4..fb3406b 100644 --- a/cpp/src/compilation/advancedinstructions.cpp +++ b/cpp/src/compilation/advancedinstructions.cpp @@ -1,460 +1,459 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * File: InstructionsAdvanced.cpp * Author: pgess * * Created on June 26, 2016, 6:00 PM */ /** * \file advanced.h * \brief Compilation of statements that require more than one LLVM instruction */ #include "compilation/advancedinstructions.h" #include "compilation/containers.h" #include "compilation/transformersaturation.h" -#include "query/context.h" #include "query/containers.h" #include "llvmlayer.h" #include "ast.h" using namespace std; using namespace llvm; using namespace xreate; using namespace xreate::containers; using namespace xreate::compilation; #define NAME(x) (hintRetVar.empty()? x : hintRetVar) #define UNUSED(x) (void)(x) #define EXPAND_CONTEXT \ LLVMLayer* llvm = context.pass->man->llvm; \ compilation::ICodeScopeUnit* scope = context.scope; \ compilation::IFunctionUnit* function = context.function; AdvancedInstructions::AdvancedInstructions(compilation::Context ctx) : context(ctx), tyNum(static_cast (ctx.pass->man->llvm->toLLVMType(ExpandedType(TypeAnnotation(TypePrimitive::Num))))) { } llvm::Value* AdvancedInstructions::compileMapSolidOutput(const Expression &expr, const std::string hintRetVar) { EXPAND_CONTEXT UNUSED(scope); //initialization Symbol symbolIn = Attachments::get(expr.getOperands()[0]); ImplementationRec implIn = containers::Query::queryImplementation(symbolIn).extract(); // impl of input list size_t size = implIn.size; CodeScope* scopeLoop = expr.blocks.front(); std::string varEl = scopeLoop->__bindings[0]; Iterator* it = Iterator::create(context, symbolIn); llvm::Value *rangeFrom = it->begin(); llvm::Value *rangeTo = it->end(); //definitions ArrayType* tyNumArray = (ArrayType*) (llvm->toLLVMType(ExpandedType(TypeAnnotation(tag_array, TypePrimitive::Num, size)))); llvm::IRBuilder<> &builder = llvm->builder; llvm::BasicBlock *blockLoop = llvm::BasicBlock::Create(llvm::getGlobalContext(), "loop", function->raw); llvm::BasicBlock *blockBeforeLoop = builder.GetInsertBlock(); llvm::BasicBlock *blockAfterLoop = llvm::BasicBlock::Create(llvm::getGlobalContext(), "postloop", function->raw); Value* dataOut = llvm->builder.CreateAlloca(tyNumArray, ConstantInt::get(tyNum, size), NAME("map")); // * initial check Value* condBefore = builder.CreateICmpSLE(rangeFrom, rangeTo); builder.CreateCondBr(condBefore, blockLoop, blockAfterLoop); // create PHI: builder.SetInsertPoint(blockLoop); llvm::PHINode *stateLoop = builder.CreatePHI(tyNum, 2, "mapIt"); stateLoop->addIncoming(rangeFrom, blockBeforeLoop); // loop body: Value* elIn = it->get(stateLoop, varEl); compilation::ICodeScopeUnit* scopeLoopUnit = function->getScopeUnit(scopeLoop); scopeLoopUnit->bindArg(elIn, move(varEl)); Value* elOut = scopeLoopUnit->compile(); Value *pElOut = builder.CreateGEP(dataOut, ArrayRef(std::vector{ConstantInt::get(tyNum, 0), stateLoop})); builder.CreateStore(elOut, pElOut); //next iteration preparing Value *stateLoopNext = builder.CreateAdd(stateLoop, llvm::ConstantInt::get(tyNum, 1)); stateLoop->addIncoming(stateLoopNext, builder.GetInsertBlock()); //next iteration checks: Value* condAfter = builder.CreateICmpSLE(stateLoopNext, rangeTo); builder.CreateCondBr(condAfter, blockLoop, blockAfterLoop); //finalization: builder.SetInsertPoint(blockAfterLoop); return dataOut; } Value* AdvancedInstructions::compileArrayIndex(llvm::Value* aggregate, std::vector indexes, std::string hintRetVar) { EXPAND_CONTEXT UNUSED(function); UNUSED(scope); indexes.insert(indexes.begin(), llvm::ConstantInt::get(tyNum, 0)); llvm::Value *pEl = llvm->builder.CreateGEP(aggregate, llvm::ArrayRef(indexes)); return llvm->builder.CreateLoad(pEl, NAME("el")); } Value* AdvancedInstructions::compileStructIndex(llvm::Value* aggregate, const ExpandedType& t, const std::string& idx) { EXPAND_CONTEXT UNUSED(scope); UNUSED(function); TypeUtils types(llvm); std::vector&& fields = types.getStructFields(t); for (unsigned i = 0, size = fields.size(); i < size; ++i) { if (fields.at(i) == idx) { //dereference pointer if (types.isPointer(t)) { llvm::Value* addr = llvm->builder.CreateConstGEP2_32(nullptr, aggregate, 0, i); return llvm->builder.CreateLoad(addr); } return llvm->builder.CreateExtractValue(aggregate, llvm::ArrayRef{i}); } } assert(false && "not found required struct field"); return nullptr; } llvm::Value* AdvancedInstructions::compileFold(const Expression& fold, const std::string& hintRetVar) { EXPAND_CONTEXT assert(fold.op == Operator::FOLD); //initialization: Symbol varInSymbol = Attachments::get(fold.getOperands()[0]); Implementation info = Query::queryImplementation(varInSymbol); Iterator* it = Iterator::create(context, varInSymbol); llvm::Value* rangeBegin = it->begin(); llvm::Value* rangeEnd = it->end(); llvm::Value* accumInit = scope->process(fold.getOperands()[1]); std::string varIn = fold.getOperands()[0].getValueString(); std::string varAccum = fold.bindings[1]; std::string varEl = fold.bindings[0]; llvm::BasicBlock *blockBeforeLoop = llvm->builder.GetInsertBlock(); std::unique_ptr transformerSaturation(new TransformerSaturation(blockBeforeLoop, context.pass->managerTransformations)); llvm::BasicBlock *blockLoop = llvm::BasicBlock::Create(llvm::getGlobalContext(), "fold", function->raw); llvm::BasicBlock *blockLoopBody = llvm::BasicBlock::Create(llvm::getGlobalContext(), "fold_body", function->raw); llvm::BasicBlock *blockAfterLoop = llvm::BasicBlock::Create(llvm::getGlobalContext(), "fold_after", function->raw); llvm::BasicBlock *blockNext = llvm::BasicBlock::Create(llvm::getGlobalContext(), "fold_next", function->raw); llvm->builder.CreateBr(blockLoop); // * create phi llvm->builder.SetInsertPoint(blockLoop); llvm::PHINode *accum = llvm->builder.CreatePHI(accumInit->getType(), 2, varAccum); accum->addIncoming(accumInit, blockBeforeLoop); llvm::PHINode *itLoop = llvm->builder.CreatePHI(rangeBegin->getType(), 2, "foldIt"); itLoop->addIncoming(rangeBegin, blockBeforeLoop); // * loop checks Value* condRange = llvm->builder.CreateICmpNE(itLoop, rangeEnd); llvm->builder.CreateCondBr(condRange, blockLoopBody, blockAfterLoop); // * loop body llvm->builder.SetInsertPoint(blockLoopBody); CodeScope* scopeLoop = fold.blocks.front(); compilation::ICodeScopeUnit* loopUnit = function->getScopeUnit(scopeLoop); Value* elIn = it->get(itLoop); loopUnit->bindArg(accum, move(varAccum)); loopUnit->bindArg(elIn, move(varEl)); Value* accumNext = loopUnit->compile(); // * Loop saturation checks bool flagSaturationTriggered = transformerSaturation->insertSaturationChecks(blockNext, blockAfterLoop, context); llvm::BasicBlock* blockSaturation = llvm->builder.GetInsertBlock(); if (!flagSaturationTriggered){ llvm->builder.CreateBr(blockNext); } // * computing next iteration state llvm->builder.SetInsertPoint(blockNext); Value *itLoopNext = it->advance(itLoop); accum->addIncoming(accumNext, llvm->builder.GetInsertBlock()); itLoop->addIncoming(itLoopNext, llvm->builder.GetInsertBlock()); llvm->builder.CreateBr(blockLoop); // * finalization: llvm->builder.SetInsertPoint(blockAfterLoop); if (!flagSaturationTriggered){ return accum; } llvm::PHINode* result = llvm->builder.CreatePHI(accumInit->getType(), 2); result->addIncoming(accum, blockLoop); result->addIncoming(accumNext, blockSaturation); return result; } llvm::Value* AdvancedInstructions::compileFoldInf(const Expression& fold, const std::string& hintRetVar) { EXPAND_CONTEXT assert(fold.op == Operator::FOLD_INF); std::string accumName = fold.bindings[0]; llvm::Value* accumInit = scope->process(fold.getOperands()[0]); llvm::BasicBlock *blockBeforeLoop = llvm->builder.GetInsertBlock(); llvm::BasicBlock *blockLoop = llvm::BasicBlock::Create(llvm::getGlobalContext(), "foldinf", function->raw); llvm::BasicBlock *blockNext = llvm::BasicBlock::Create(llvm::getGlobalContext(), "foldinf_next", function->raw); llvm::BasicBlock *blockAfterLoop = llvm::BasicBlock::Create(llvm::getGlobalContext(), "foldinf_post", function->raw); std::unique_ptr transformerSaturation(new TransformerSaturation(blockBeforeLoop, context.pass->managerTransformations)); llvm->builder.CreateBr(blockLoop); // * create phi llvm->builder.SetInsertPoint(blockLoop); llvm::PHINode *accum = llvm->builder.CreatePHI(accumInit->getType(), 2, accumName); accum->addIncoming(accumInit, blockBeforeLoop); // * loop body CodeScope* scopeLoop = fold.blocks.front(); compilation::ICodeScopeUnit* unitLoop = function->getScopeUnit(scopeLoop); unitLoop->bindArg(accum, move(accumName)); Value* accumNext = unitLoop->compile(); // * Loop saturation checks bool flagSaturationTriggered = transformerSaturation->insertSaturationChecks(blockNext, blockAfterLoop, context); assert(flagSaturationTriggered); // * computing next iteration state llvm->builder.SetInsertPoint(blockNext); accum->addIncoming(accumNext, llvm->builder.GetInsertBlock()); llvm->builder.CreateBr(blockLoop); // finalization: llvm->builder.SetInsertPoint(blockAfterLoop); return accumNext; } llvm::Value* AdvancedInstructions::compileIf(const Expression& exprIf, const std::string& hintRetVar) { EXPAND_CONTEXT const Expression& condExpr = exprIf.getOperands()[0]; llvm::IRBuilder<>& builder = llvm->builder; assert(builder.GetInsertBlock() == scope->currentBlockRaw); //initialization: llvm::BasicBlock *blockEpilog = llvm::BasicBlock::Create(llvm::getGlobalContext(), "ifAfter", function->raw); llvm::BasicBlock *blockTrue = llvm::BasicBlock::Create(llvm::getGlobalContext(), "ifTrue", function->raw); llvm::BasicBlock *blockFalse = llvm::BasicBlock::Create(llvm::getGlobalContext(), "ifFalse", function->raw); llvm::Value* cond = scope->process(condExpr); builder.SetInsertPoint(blockTrue); CodeScope* scopeTrue = exprIf.blocks.front(); llvm::Value* resultTrue = function->getScopeUnit(scopeTrue)->compile(); llvm::BasicBlock * blockTrueEnd = builder.GetInsertBlock(); builder.CreateBr(blockEpilog); builder.SetInsertPoint(blockFalse); CodeScope* scopeFalse = exprIf.blocks.back(); llvm::Value* resultFalse = function->getScopeUnit(scopeFalse)->compile(); llvm::BasicBlock * blockFalseEnd = builder.GetInsertBlock(); builder.CreateBr(blockEpilog); builder.SetInsertPoint(scope->currentBlockRaw); llvm->builder.CreateCondBr(cond, blockTrue, blockFalse); builder.SetInsertPoint(blockEpilog); llvm::PHINode *ret = builder.CreatePHI(resultTrue->getType(), 2, NAME("if")); ret->addIncoming(resultTrue, blockTrueEnd); ret->addIncoming(resultFalse, blockFalseEnd); return ret; } //TODO Switch: default variant no needed when all possible conditions are considered llvm::Value* AdvancedInstructions::compileSwitch(const Expression& exprSwitch, const std::string& hintRetVar) { EXPAND_CONTEXT UNUSED(function); AST* root = context.pass->man->root; llvm::IRBuilder<>& builder = llvm->builder; assert(exprSwitch.operands.size() >= 2); assert(exprSwitch.operands[1].op == Operator::CASE_DEFAULT && "No default case in Switch Statement"); int countCases = exprSwitch.operands.size() - 1; llvm::BasicBlock* blockProlog = builder.GetInsertBlock(); llvm::BasicBlock *blockEpilog = llvm::BasicBlock::Create(llvm::getGlobalContext(), "switchAfter", function->raw); builder.SetInsertPoint(blockEpilog); llvm::Type* exprSwitchType = llvm->toLLVMType(root->getType(exprSwitch)); llvm::PHINode *ret = builder.CreatePHI(exprSwitchType, countCases, NAME("switch")); builder.SetInsertPoint(blockProlog); llvm::Value * conditionSwitch = scope->process(exprSwitch.operands[0]); llvm::BasicBlock *blockDefault = llvm::BasicBlock::Create(llvm::getGlobalContext(), "caseDefault", function->raw); llvm::SwitchInst * instructionSwitch = builder.CreateSwitch(conditionSwitch, blockDefault, countCases); for (int size = exprSwitch.operands.size(), i = 2; i < size; ++i) { llvm::BasicBlock *blockCase = llvm::BasicBlock::Create(llvm::getGlobalContext(), "case" + std::to_string(i), function->raw); llvm::Value* condCase = function->getScopeUnit(exprSwitch.operands[i].blocks.front())->compile(); builder.SetInsertPoint(blockCase); llvm::Value* resultCase = function->getScopeUnit(exprSwitch.operands[i].blocks.back())->compile(); builder.CreateBr(blockEpilog); ret->addIncoming(resultCase, builder.GetInsertBlock()); builder.SetInsertPoint(blockProlog); instructionSwitch->addCase(dyn_cast(condCase), blockCase); } //compile default block: builder.SetInsertPoint(blockDefault); CodeScope* scopeDefault = exprSwitch.operands[1].blocks.front(); llvm::Value* resultDefault = function->getScopeUnit(scopeDefault)->compile(); builder.CreateBr(blockEpilog); ret->addIncoming(resultDefault, builder.GetInsertBlock()); builder.SetInsertPoint(blockEpilog); return ret; } llvm::Value* AdvancedInstructions::compileSwitchVariant(const Expression& exprSwitch, const std::string& hintRetVar) { EXPAND_CONTEXT UNUSED(function); AST* root = context.pass->man->root; llvm::IRBuilder<>& builder = llvm->builder; llvm::Type* typI8= llvm::Type::getInt8Ty(llvm::getGlobalContext()); const ExpandedType& typVariant = root->getType(exprSwitch.operands.at(0)); llvm::Type* typVariantRaw = llvm->toLLVMType(typVariant); assert(typVariant->__operands.size() == exprSwitch.operands.size() - 1 && "Ill-formed Switch Variant"); int casesCount = exprSwitch.operands.size(); llvm::BasicBlock* blockProlog = builder.GetInsertBlock(); llvm::BasicBlock *blockEpilog = llvm::BasicBlock::Create(llvm::getGlobalContext(), "switchAfter", function->raw); builder.SetInsertPoint(blockEpilog); llvm::Type* resultType = llvm->toLLVMType(root->getType(exprSwitch)); llvm::PHINode *ret = builder.CreatePHI(resultType, casesCount, NAME("switch")); builder.SetInsertPoint(blockProlog); llvm::Value * conditionSwitchRaw = scope->process(exprSwitch.operands.at(0)); llvm::Value* idRaw = builder.CreateExtractValue(conditionSwitchRaw, llvm::ArrayRef({0})); //Dereference preparation const bool flagDoDerefence = llvm::cast(typVariantRaw)->getStructNumElements() > 1; llvm::Value* addrAsStorage = nullptr; if (flagDoDerefence){ llvm::Type* typStorageRaw = llvm::cast(typVariantRaw)->getElementType(1); llvm::Value* storageRaw = builder.CreateExtractValue(conditionSwitchRaw, llvm::ArrayRef({1})); addrAsStorage = llvm->builder.CreateAlloca(typStorageRaw); llvm->builder.CreateStore(storageRaw, addrAsStorage); } llvm::SwitchInst * instructionSwitch = builder.CreateSwitch(idRaw, nullptr, casesCount); llvm::BasicBlock* blockDefaultUndefined; std::list::const_iterator scopeCaseIt = exprSwitch.blocks.begin(); for (int instancesSize = exprSwitch.operands.size()-1, instId = 0; instId < instancesSize; ++instId) { llvm::BasicBlock *blockCase = llvm::BasicBlock::Create(llvm::getGlobalContext(), "case" + std::to_string(instId), function->raw); builder.SetInsertPoint(blockCase); ICodeScopeUnit* unitCase = function->getScopeUnit(*scopeCaseIt); //Actual variant Derefence if (flagDoDerefence) { assert(exprSwitch.bindings.size() && "Switch condition alias not found"); string identCondition = exprSwitch.bindings.front(); const ExpandedType& instType = ExpandedType(typVariant->__operands.at(instId)); llvm::Type* instTypeRaw = llvm->toLLVMType(instType); llvm::Value* addrAsInst = llvm->builder.CreateBitOrPointerCast(addrAsStorage, instTypeRaw->getPointerTo()); llvm::Value* instRaw = llvm->builder.CreateLoad(instTypeRaw, addrAsInst); const Symbol& identSymb = unitCase->bindArg(instRaw, move(identCondition)); Attachments::put(identSymb, instType); } llvm::Value* resultCase = function->getScopeUnit(*scopeCaseIt)->compile(); builder.CreateBr(blockEpilog); ret->addIncoming(resultCase, blockDefaultUndefined = builder.GetInsertBlock()); builder.SetInsertPoint(blockProlog); instructionSwitch->addCase(dyn_cast(llvm::ConstantInt::get(typI8, exprSwitch.operands.at(instId+1).getValueDouble())), blockCase); ++scopeCaseIt; } instructionSwitch->setDefaultDest(blockDefaultUndefined); builder.SetInsertPoint(blockEpilog); return ret; } //TODO recognize cases to make const arrays/stored in global mem/stack alloced. llvm::Value* AdvancedInstructions::compileListAsSolidArray(const Expression &expr, const std::string& hintRetVar) { EXPAND_CONTEXT UNUSED(scope); UNUSED(function); AST* root = context.pass->man->root; const size_t& length = expr.getOperands().size(); const Expression& expression = expr; llvm::Value* zero = ConstantInt::get(tyNum, 0); llvm::Value* one = ConstantInt::get(tyNum, 1); ExpandedType typAggrExpanded = root->getType(expression); assert(typAggrExpanded->__operator == TypeOperator::LIST); llvm::Type* typEl = llvm->toLLVMType(ExpandedType(typAggrExpanded->__operands[0])); ArrayType* typAggr = (ArrayType*) llvm::ArrayType::get(typEl, length); llvm::Value* list = llvm->builder.CreateAlloca(typAggr, ConstantInt::get(Type::getInt32Ty(llvm::getGlobalContext()), length, false), hintRetVar); const std::vector& operands = expression.getOperands(); llvm::Value* addrOperand = llvm->builder.CreateGEP(typAggr, list, ArrayRef(std::vector{zero, zero})); llvm->builder.CreateStore(scope->process(operands.front()), addrOperand) ; for (auto i=++operands.begin(); i!=operands.end(); ++i){ addrOperand = llvm->builder.CreateGEP(typEl, addrOperand, ArrayRef(std::vector{one})); llvm->builder.CreateStore(scope->process(*i), addrOperand) ; } return list; // Value* listDest = l.builder.CreateAlloca(typList, ConstantInt::get(typI32, __size), *hintRetVar); // l.buil1der.CreateMemCpy(listDest, listSource, __size, 16); } llvm::Value* AdvancedInstructions::compileConstantStringAsPChar(const string& data, const std::string& hintRetVar) { EXPAND_CONTEXT UNUSED(function); UNUSED(scope); Type* typPchar = PointerType::getUnqual(Type::getInt8Ty(llvm::getGlobalContext())); //ArrayType* typStr = (ArrayType*) (llvm->toLLVMType(ExpandedType(TypeAnnotation(tag_array, TypePrimitive::I8, size+1)))); /* std::vector chars; chars.reserve(size+1); for (size_t i=0; i< size; ++i){ chars[i] = ConstantInt::get(typI8, (unsigned char) data[i]); } chars[size] = ConstantInt::get(typI8, 0); */ Value* rawData = ConstantDataArray::getString(llvm::getGlobalContext(), data); Value* rawPtrData = llvm->builder.CreateAlloca(rawData->getType(), ConstantInt::get(Type::getInt32Ty(llvm::getGlobalContext()), 1, false)); llvm->builder.CreateStore(rawData, rawPtrData); return llvm->builder.CreateCast(llvm::Instruction::BitCast, rawPtrData, typPchar, hintRetVar); } llvm::Value* AdvancedInstructions::compileSequence(const Expression &expr){ EXPAND_CONTEXT UNUSED(scope); UNUSED(llvm); llvm::Value* result; for(CodeScope* scope: expr.blocks){ result = function->getScopeUnit(scope)->compile(); } return result; } diff --git a/cpp/src/compilation/containers.h b/cpp/src/compilation/containers.h index 6fa52d9..bd8a4fc 100644 --- a/cpp/src/compilation/containers.h +++ b/cpp/src/compilation/containers.h @@ -1,98 +1,96 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * File: containers.h * Author: pgess */ #ifndef CODEINSTRUCTIONS_H #define CODEINSTRUCTIONS_H #include "ast.h" #include "llvmlayer.h" #include "pass/compilepass.h" #include "compilation/advancedinstructions.h" - -#include "query/context.h" #include "query/containers.h" namespace xreate { namespace containers { using namespace llvm; /** \brief Factory to create relevant iterator based on solution * provided by xreate::containers::Query * \sa xreate::containers::Query */ class Iterator{ public : virtual llvm::Value* begin() =0; virtual llvm::Value* end() = 0; virtual llvm::Value* get(llvm::Value* index,const std::string& hintRetVar="") = 0; virtual llvm::Value* advance(llvm::Value* index, const std::string& hintRetVar="")=0; virtual ~Iterator(){}; static Iterator* create(xreate::compilation::Context context, const xreate::Symbol& var); }; template class IteratorForward; /** \brief Possible container implementation. Represents computation on the fly * \sa xreate::containers::Iterator, \sa xreate::containers::Query */ template<> class IteratorForward : public Iterator { private: LLVMLayer* llvm; const xreate::Symbol current; const Symbol source; const ImplementationLinkedList linkedlist; const CodeScope* const sourceScope; //TODO initialize and mark as const (three fields) compilation::ICodeScopeUnit* sourceUnit; compilation::IFunctionUnit* function; //TODO is used somewhere? const Expression& sourceDecl; compilation::Context context; llvm::Type* sourceRawType =nullptr; public: IteratorForward(const compilation::Context& ctx, const xreate::Symbol& s, const ImplementationRec& implementation) : llvm(ctx.pass->man->llvm), current(s), source(implementation.source), linkedlist(source), sourceScope(source.scope), sourceUnit(ctx.function->getScopeUnit(source.scope)), sourceDecl(CodeScope::getDefinition(source)), context(ctx) {} llvm::Value* begin() override; llvm::Value* end() override; llvm::Value* get(llvm::Value* index,const std::string& hintRetVar="") override; llvm::Value* advance(llvm::Value* index, const std::string& hintRetVar="") override; }; /** \brief Possible container implementation. Represents contiguous in memory(array) implementation * \sa xreate::containers::Iterator, \sa xreate::containers::Query */ template<> class IteratorForward: public Iterator{ size_t __length; llvm::Value* __container; LLVMLayer* llvm; public: IteratorForward(const compilation::Context& ctx, const xreate::Symbol& symbolContainer, const ImplementationRec& implementation); llvm::Value* begin() override; llvm::Value* end() override; llvm::Value* get(llvm::Value* index,const std::string& hintRetVar="") override; llvm::Value* advance(llvm::Value* index, const std::string& hintRetVar="") override; }; }} #endif //CODEINSTRUCTIONS_H diff --git a/cpp/src/compilation/targetinterpretation.cpp b/cpp/src/compilation/targetinterpretation.cpp index ae9237f..ccd5f02 100644 --- a/cpp/src/compilation/targetinterpretation.cpp +++ b/cpp/src/compilation/targetinterpretation.cpp @@ -1,644 +1,645 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * File: targetinterpretation.cpp * Author: pgess * * Created on June 29, 2016, 6:45 PM */ /** * \file targetinterpretation.h * \brief Interpretation support. See more [details on Interpretation](/w/concepts/dsl/) */ #include "compilation/targetinterpretation.h" #include "pass/interpretationpass.h" #include "analysis/typeinference.h" #include "llvmlayer.h" #include "compilation/scopedecorators.h" #include #include #include #include using namespace std; using namespace xreate::compilation; namespace xreate{ namespace interpretation{ - const Expression EXPRESSION_FALSE = Expression(Atom(0)); - const Expression EXPRESSION_TRUE = Expression(Atom(1)); + +const Expression EXPRESSION_FALSE = Expression(Atom(0)); +const Expression EXPRESSION_TRUE = Expression(Atom(1)); Expression representAsAnnotation(const Gringo::Symbol& atom){ switch (atom.type()) { case Gringo::SymbolType::Num: { Expression result(Operator::VARIANT, {Expression(atom.num())}); result.setValueDouble(0); return result; } case Gringo::SymbolType::Str: { Expression result(Operator::VARIANT, {Expression(Atom(std::string(atom.string().c_str())))}); result.setValueDouble(1); return result; } case Gringo::SymbolType::Fun: { Expression fnDescription(Operator::LIST_NAMED, {}); std::list> bindings{Atom("name"), Atom("arguments")}; fnDescription.addBindings(bindings.begin(), bindings.end()); fnDescription.addArg(Expression(Atom(std::string(atom.name().c_str())))); Expression args(Operator::LIST, {}); for (const Gringo::Symbol& arg : atom.args()) { args.addArg(representAsAnnotation(arg)); } fnDescription.addArg(std::move(args)); Expression result(Operator::VARIANT, {fnDescription}); result.setValueDouble(2); return result; } default: { assert(false); } } } 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((const CodeScope*) 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; } CodeScope* InterpretationScope::processOperatorSwitchVariant(const Expression& expression){ const Expression& condition = process(expression.operands.at(0)); assert(condition.op == Operator::VARIANT); const string& identCondition = expression.bindings.front(); Expression opExpected(Atom(condition.getValueDouble())); auto itFoundValue = std::find(++expression.operands.begin(), expression.operands.end(), opExpected); assert(itFoundValue != expression.operands.end()); int indexBlock = itFoundValue - expression.operands.begin() -1; auto blockFound = expression.blocks.begin(); std::advance(blockFound, indexBlock); InterpretationScope* scopeI12n = function->getScope(*blockFound); if(condition.operands.size()){ const Expression& value=condition.operands.at(0); scopeI12n->overrideBindings({ {value, identCondition}}); } return *blockFound; } 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 SWITCH_VARIANT: { CodeScope* scopeResult = processOperatorSwitchVariant(expression); const Expression& condition = expression.operands.at(0); const Expression& valueCondition = process(condition); const string identCondition = expression.bindings.front(); auto scopeCompilation = Decorators::getInterface(context.function->getScopeUnit(scopeResult)); if(valueCondition.operands.size()){ //override value Symbol symbCondition{ScopedSymbol{scopeResult->__identifiers.at(identCondition), versions::VERSION_NONE}, scopeResult}; scopeCompilation->overrideDeclarations( {{symbCondition, Expression(valueCondition.operands.at(0))}} ); //set correct type for binding: TypeAnnotation typeVariant = typeinference::getType(condition, *function->man->ast); int conditionIndex = valueCondition.getValueDouble(); ScopedSymbol symbolInternal = scopeResult->getSymbol(identCondition); scopeResult->__declarations[symbolInternal].bindType(typeVariant.__operands.at(conditionIndex)); } 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), versions::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; ioverrideBindings({ {exprElement, nameEl}}); unitBody->overrideDeclarations({ {symbEl, exprElement}}); //resets unitBody unitBody->bindArg(rawAccum, string(idAccum)); rawAccum=unitBody->compile(); } return rawAccum; } /* case FOLD_INF_INTERPRET_INOUT{ } */ //TODO refactor as InterpretationCallStatement class case CALL_INTERPRET_PARTIAL: { const std::string &calleeName = expression.getValueString(); ICodeScopeUnit* 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) { #ifndef NDEBUG if (expression.tags.count("bpoint")){ std::raise(SIGINT); } #endif PassManager* man = (static_cast (function->man))->pass->man; switch (expression.__state){ case Expression::INVALID: assert(false); 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::CALL_INTRINSIC: { std::string nameFunction = expression.getValueString(); if(nameFunction=="query"){ assert(expression.operands.size() == 1); assert(expression.operands.front().__state == Expression::STRING); std::string namePredicate = expression.operands.front().getValueString(); - ClaspLayer::ModelFragment model = (static_cast(function->man))->pass->man->clasp->query(namePredicate); + StaticModel model = (static_cast(function->man))->pass->man->clasp->query(namePredicate); Expression result(Operator::LIST, {}); - if(model) - for (const auto& row: boost::make_iterator_range(model.get())) { + if(model.size()) + for (const auto& row: model) { result.addArg(representAsAnnotation(std::get<1>(row))); } return result; } else if(nameFunction=="query_scope"){ ScopePacked scopeId = man->clasp->pack(scope); Expression result(Operator::VARIANT, {Expression(scopeId)}); result.setValueDouble(0); return result; } else { assert(false && "Unknown intrinsic"); } } 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::SWITCH_VARIANT: { CodeScope* scopeResult = processOperatorSwitchVariant(expression); return function->getScope(scopeResult)->processScope(); } case Operator::VARIANT: { if(!expression.operands.size()) return expression; - + Expression variantData = process(expression.operands[0]); Expression result{Operator::VARIANT, {variantData}}; result.setValueDouble(expression.getValueDouble()); return result; } case Operator::INDEX: { Expression exprData = process(expression.operands[0]); for (size_t keyId=1; keyIdgetScope(expression.blocks.front()); Expression accum = exprInit; for(size_t size=exprInput.getOperands().size(), i=0; ioverrideBindings({ {exprInput.getOperands()[i], argEl}, {accum, argAccum} }); accum = body->processScope(); } return accum; } case Operator::LIST: case Operator::LIST_NAMED: case Operator::LIST_RANGE: { Expression result(expression.op,{}); result.operands.resize(expression.operands.size()); result.bindings=expression.bindings; result.__indexBindings=expression.__indexBindings; int keyId=0; for(const Expression& opCurrent : expression.operands) { result.operands[keyId++]=process(opCurrent); } return result; } // case Operator::MAP: { // break; // } default: break; } return expression; } InterpretationFunction* TargetInterpretation::getFunction(IFunctionUnit* 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); list> bindings; for(size_t i=0, size=args.size(); iscope->__bindings.at(i))); } body->overrideBindings(bindings); return body->processScope(); } // Partial function interpretation typedef BasicFunctionUnit 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, versions::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; ICodeScopeUnit* 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)), versions::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); list> bindingsPartial; list> declsPartial; for(size_t no=0, sigNo=0, size=entry->__bindings.size(); no__bindings[no]}); VNameId argId=entry->__identifiers.at(entry->__bindings[no]); Symbol argSymbol{ScopedSymbol {argId, versions::VERSION_NONE}, entry}; declsPartial.push_back({argSymbol, signatureInstance.bindings[sigNo]}); ++sigNo; } } entryIntrp->overrideBindings(bindingsPartial); entryUnit->overrideDeclarations(declsPartial); } 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; } }} /** \class xreate::interpretation::InterpretationFunction * * Holds list of xreate::interpretation::InterpretationScope 's focused on interpretation of individual code scopes * * There is particulat subclass PIFunction intended to represent partially interpreted functions *\sa TargetInterpretation, [Interpretation Concept](/w/concepts/dfa) */ /** \class xreate::interpretation::TargetInterpretation * * Executed during compilation and intented to preprocess eligible parts of code. * Established on [Targets Infrastructure](\ref compilation::Target) * * Holds list of InterpretationFunction / PIFunction to represent interpretation process for individual functions * * In order to be activated during compilation process there is * InterpretationScopeDecorator implementation of ICodeScopeUnit * \sa InterpretationPass, compilation::Target, [Interpretation Concept](/w/concepts/dfa) * */ \ No newline at end of file diff --git a/cpp/src/contextrule.cpp b/cpp/src/contextrule.cpp index 489af60..7bdcb9e 100644 --- a/cpp/src/contextrule.cpp +++ b/cpp/src/contextrule.cpp @@ -1,61 +1,61 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * contextrule.cpp * * Created on: Jan 2, 2016 * Author: pgess */ /** * \file contextrule.h * \brief Context rules support. See more on [context rules](/w/concepts/context#context-rules) */ #include "contextrule.h" #include "clasplayer.h" -#include "analysis/aux.h" +#include "analysis/utils.h" #include using namespace xreate; using namespace std; ContextRule::ContextRule(const Expression& rule) { assert(rule.op == Operator::CONTEXT_RULE); assert(rule.operands.size() == 3); head = rule.operands.at(0); guards = rule.operands.at(1); body = rule.operands.at(2); } std::string ContextRule::compile(const ScopePacked& scopeId) const{ const string prolog = " %context rule visibility implemenetation\n" "context_rule_visibility(X, Y) :- X=Y, scope(X), scope(Y).\n" "context_rule_visibility(X, Y) :- cfa_parent(X, scope(Y)), scope(X), scope(Y).\n"; listrepHead_ = xreate::analysis::compile(head); assert(repHead_.size() == 1); listrepGuards_ = xreate::analysis::compile(guards); assert(repGuards_.size() == 1); listrepBody_ = xreate::analysis::compile(body); assert(repBody_.size() == 1); const std::string& atomBindingScope = Config::get("clasp.bindings.scope"); boost::format formatContextVisibility("context_rule_visibility(ScopeX, %1%)"); boost::format formatScopeBind(atomBindingScope + "(ScopeX, %1%, Linkage)"); const string& repHead = str(formatScopeBind % repHead_.front()); const string& repGuards = str(formatScopeBind % repGuards_.front()); const string& repVisibility = str(formatContextVisibility % scopeId); boost::format formatRule("%1%:- %2%, %3%, %4%."); return prolog + str(formatRule % repHead % repGuards % repBody_.front() % repVisibility); } diff --git a/cpp/src/modules.cpp b/cpp/src/modules.cpp index c7bf5aa..f610c9c 100644 --- a/cpp/src/modules.cpp +++ b/cpp/src/modules.cpp @@ -1,183 +1,183 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * modules.cpp * * Author: pgess * Created on July 22, 2017, 5:13 PM */ /** * \file modules.h * \brief Modules support */ #include "modules.h" #include "modules/Parser.h" -#include "analysis/aux.h" +#include "analysis/utils.h" #include #include #include #include #include namespace fs = boost::filesystem; 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"); 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::modules diff --git a/cpp/src/pass/adhocpass.cpp b/cpp/src/pass/adhocpass.cpp deleted file mode 100644 index af8aea0..0000000 --- a/cpp/src/pass/adhocpass.cpp +++ /dev/null @@ -1,99 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - * - * adhocpass.cpp - * - * Created on: Nov 28, 2015 - * Author: pgess - */ - -#include "pass/adhocpass.h" -#include "query/context.h" - -//TODO use ADT/templated types rather than adhocs. remove adhocs. -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 context::Domain& domain = queryContext->getContext(scopeId); - AdhocScheme* scheme = nullptr; - - for (const Expression& context: domain){ - if (!(context.__state == Expression::COMPOUND && context.op == Operator::CALL)) 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::COMPOUND && comm.op == Operator::CALL && comm.operands.size() == 0); - - 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 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 deleted file mode 100644 index 6cada0d..0000000 --- a/cpp/src/pass/adhocpass.h +++ /dev/null @@ -1,62 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - * - * adhocpass.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 { 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; - context::ContextQuery* queryContext; -}; - -}} //end of namespace xreate::adhoc - -#endif /* SRC_INSTRUCTIONS_ADHOC_H_ */ diff --git a/cpp/src/pass/compilepass.cpp b/cpp/src/pass/compilepass.cpp index b66b7d5..19ef1aa 100644 --- a/cpp/src/pass/compilepass.cpp +++ b/cpp/src/pass/compilepass.cpp @@ -1,740 +1,718 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * Author: pgess * * compilepass.cpp */ /** * \file compilepass.h * \brief Compilation pass */ #include "compilepass.h" #include "clasplayer.h" #include #include "llvmlayer.h" #include "query/containers.h" -#include "query/context.h" #include "compilation/containers.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/operators.h" #include "analysis/typeinference.h" #include #include #include using namespace std; using namespace llvm; namespace xreate { namespace compilation{ std::string BasicFunctionUnit::prepareName(){ AST* ast = IFunctionUnit::pass->man->root; string name = ast->getFunctionSpecializations(IFunctionUnit::function->__name).size() > 1 ? IFunctionUnit::function->__name + std::to_string(IFunctionUnit::function.id()) : IFunctionUnit::function->__name; return name; } std::vector BasicFunctionUnit::prepareArguments() { LLVMLayer* llvm = IFunctionUnit::pass->man->llvm; AST* ast = IFunctionUnit::pass->man->root; CodeScope* entry = IFunctionUnit::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), versions::VERSION_NONE}; return llvm->toLLVMType(ast->expandType(entry->__declarations.at(argid).type)); }); return signature; } llvm::Type* BasicFunctionUnit::prepareResult() { LLVMLayer* llvm = IFunctionUnit::pass->man->llvm; AST* ast = IFunctionUnit::pass->man->root; CodeScope* entry = IFunctionUnit::function->__entry; return llvm->toLLVMType(ast->expandType(entry->__declarations.at(ScopedSymbol::RetSymbol).type)); } llvm::Function::arg_iterator BasicFunctionUnit::prepareBindings() { CodeScope* entry = IFunctionUnit::function->__entry; ICodeScopeUnit* entryCompilation = IFunctionUnit::getScopeUnit(entry); llvm::Function::arg_iterator fargsI = IFunctionUnit::raw->arg_begin(); for (std::string &arg : entry->__bindings) { ScopedSymbol argid{entry->__identifiers[arg], versions::VERSION_NONE}; entryCompilation->bindArg(&*fargsI, argid); fargsI->setName(arg); ++fargsI; } return fargsI; } //DEBT compiler rigidly depends on exact definition of DefaultFunctionUnit -typedef adhoc::AdhocFunctionDecorator< - BasicFunctionUnit> DefaultFunctionUnit; +typedef BasicFunctionUnit DefaultFunctionUnit; ICodeScopeUnit::ICodeScopeUnit(const CodeScope* const codeScope, IFunctionUnit* f, CompilePass* compilePass) : pass(compilePass), function(f), scope(codeScope), currentBlockRaw(nullptr) { } 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] = typeinference::doAutomaticTypeConversion(args[pos], argFormal->getType(), llvm->builder); } } //Do not name function call that returns Void. std::string nameStatement = hintDecl; if (calleeInfo->getReturnType()->isVoidTy()){ nameStatement.clear(); } return llvm->builder.CreateCall(__calleeTy, __callee, args, nameStatement); } //DESABLEDFEATURE implement inlining class CallStatementInline : public ICallStatement { public: CallStatementInline(IFunctionUnit* caller, IFunctionUnit* 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: IFunctionUnit* __caller; IFunctionUnit* __callee; LLVMLayer* llvm; bool isInline() { // Symbol ret = Symbol{0, function->__entry}; // bool flagOnTheFly = SymbolAttachments::get(ret, false); //TODO consider inlining return false; } }; BasicCodeScopeUnit::BasicCodeScopeUnit(const CodeScope* const codeScope, IFunctionUnit* f, CompilePass* compilePass) : ICodeScopeUnit(codeScope, f, compilePass) { } llvm::Value* BasicCodeScopeUnit::processSymbol(const Symbol& s, std::string hintRetVar) { Expression declaration = CodeScope::getDefinition(s); const CodeScope* scope = s.scope; ICodeScopeUnit* scopeExternal = ICodeScopeUnit::function->getScopeUnit(scope); llvm::Value* resultRaw; if (scopeExternal == this){ resultRaw = process(declaration, hintRetVar); currentBlockRaw = pass->man->llvm->builder.GetInsertBlock(); } else { assert(scopeExternal->currentBlockRaw); llvm::BasicBlock* blockOwn = pass->man->llvm->builder.GetInsertBlock(); pass->man->llvm->builder.SetInsertPoint(scopeExternal->currentBlockRaw); resultRaw = scopeExternal->processSymbol(s, hintRetVar); pass->man->llvm->builder.SetInsertPoint(blockOwn); } return resultRaw; } ICallStatement* BasicCodeScopeUnit::findFunction(const Expression& opCall) { const std::string& calleeName = opCall.getValueString(); LLVMLayer* llvm = pass->man->llvm; const std::list& specializations = pass->man->root->getFunctionSpecializations(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); } //There should be only one specialization without any valid guards at this point return new CallStatementRaw(pass->getFunctionUnit( pass->man->root->findFunction(calleeName))->compile(), 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::AdvancedInstructions instructions = xreate::compilation::AdvancedInstructions({this, function, pass}); switch (expr.op) { 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 = typeinference::doAutomaticTypeConversion(right, left->getType(), l.builder); break; default:; } switch (expr.op) { case Operator::ADD: { left = process(expr.operands[0]); Context context{this, function, pass}; llvm::Value* resultSU = StructUpdate::add(expr.operands[0], left, expr.operands[1], context, DEFAULT("tmp_add")); if (resultSU) return resultSU; right = process(expr.operands[1]); llvm::Value* resultAddPA = pointerarithmetic::PointerArithmetic::add(left, right, context, DEFAULT("tmp_add")); if (resultAddPA) { return resultAddPA; } 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); shared_ptr callee(findFunction(expr)); const std::string& nameCallee = expr.getValueString(); //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); } ); 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 tyStructLiteral = l.ast->getType(expr); const std::vector fieldsFormal = (tyStructLiteral.get().__operator == TypeOperator::CUSTOM) ? l.layerExtern->getStructFields(l.layerExtern->lookupType(tyStructLiteral.get().__valueCustom)) : tyStructLiteral.get().fields; std::map indexFields; for (size_t i = 0, size = fieldsFormal.size(); i < size; ++i) { indexFields.emplace(fieldsFormal[i], i); } llvm::StructType* tyLiteralRaw = llvm::cast(l.toLLVMType(tyStructLiteral)); llvm::Value* record = llvm::UndefValue::get(tyLiteralRaw); for (size_t i = 0; i < expr.operands.size(); ++i) { const Expression& operand = expr.operands.at(i); unsigned int fieldId = indexFields.at(expr.bindings.at(i)); llvm::Value* 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: { //TASK allow multiindex compilation 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->getType(expr.operands[0]); llvm::Value* aggr = processSymbol(s, hintIdent); switch (t2.get().__operator) { case TypeOperator::LIST_NAMED: case TypeOperator::CUSTOM: { std::string idxField; const Expression& idx = expr.operands.at(1); switch (idx.__state) { //named struct field case Expression::STRING: idxField = idx.getValueString(); break; //anonymous struct field case Expression::NUMBER: idxField = to_string((int) idx.getValueDouble()); break; default: assert(false && "Wrong index for a struct"); } return instructions.compileStructIndex(aggr, t2, idxField); }; case TypeOperator::LIST: { 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 = adhoc::AdhocExpression(expr).getCommand(); - - CodeScope* scope = function->adhocImplementation->getCommandImplementation(comm); - ICodeScopeUnit* unitScope = function->getScopeUnit(scope); - - //SECTIONTAG types/convert ADHOC ret convertation - llvm::Type* resultTy = l.toLLVMType(pass->man->root->expandType(function->adhocImplementation->getResultType())); - return typeinference::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::VARIANT: { const ExpandedType& typVariant = pass->man->root->getType(expr); llvm::Type* typVariantRaw = l.toLLVMType(typVariant); llvm::Type* typIdRaw = llvm::cast(typVariantRaw)->getElementType(0); uint64_t id = expr.getValueDouble(); llvm::Value* variantRaw = llvm::UndefValue::get(typVariantRaw); variantRaw = l.builder.CreateInsertValue(variantRaw, llvm::ConstantInt::get(typIdRaw, id), llvm::ArrayRef({0})); const bool flagDoReference = expr.operands.size(); if (flagDoReference){ const ExpandedType& subtyp = ExpandedType(typVariant->__operands.at(id)); llvm::Type* subtypRaw = l.toLLVMType(subtyp); Attachments::put(expr.operands.at(0), subtyp); llvm::Value* subtypValue = process(expr.operands.at(0)); llvm::Type* typStorageRaw = llvm::cast(typVariantRaw)->getElementType(1); llvm::Value* addrAsStorage = l.builder.CreateAlloca(typStorageRaw); llvm::Value* addrAsSubtyp = l.builder.CreateBitOrPointerCast(addrAsStorage, subtypRaw->getPointerTo()); l.builder.CreateStore(subtypValue, addrAsSubtyp); llvm::Value* storageRaw = l.builder.CreateLoad(typStorageRaw, addrAsStorage); variantRaw = l.builder.CreateInsertValue(variantRaw, storageRaw, llvm::ArrayRef({1})); } return variantRaw; } case Operator::SWITCH_VARIANT: { return instructions.compileSwitchVariant(expr, DEFAULT("tmpswitch")); } case Operator::SEQUENCE: { return instructions.compileSequence(expr); } case Operator::UNDEF: { llvm::Type* typExprUndef = l.toLLVMType(typeinference::getType(expr, *pass->man->root)); return llvm::UndefValue::get(typExprUndef); } case Operator::INVALID: 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 = l.toLLVMType(typeinference::getType(expr, *pass->man->root)); int literal = expr.getValueDouble(); return llvm::ConstantInt::get(typConst, literal); } case Expression::STRING: { return instructions.compileConstantStringAsPChar(expr.getValueString(), DEFAULT("tmp_str")); }; default: { break; } }; break; default: break; } assert(false && "Can't compile expression"); 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); } currentBlockRaw = pass->man->llvm->builder.GetInsertBlock(); Symbol symbScope = Symbol{ScopedSymbol::RetSymbol, scope}; return processSymbol(symbScope); } ICodeScopeUnit::~ICodeScopeUnit() { } IFunctionUnit::~IFunctionUnit() { } llvm::Function* IFunctionUnit::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(typeinference::doAutomaticTypeConversion(result, expectedResultType, llvm->builder)); if (blockCurrent) { builder.SetInsertPoint(blockCurrent); } llvm->moveToGarbage(ft); return raw; } ICodeScopeUnit* IFunctionUnit::getScopeUnit(const CodeScope * const scope) { if (__scopes.count(scope)) { auto result = __scopes.at(scope).lock(); if (result) { return result.get(); } } std::shared_ptr unit(pass->buildCodeScopeUnit(scope, this)); 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(); } ICodeScopeUnit* IFunctionUnit::getScopeUnit(ManagedScpPtr scope) { return getScopeUnit(&*scope); } ICodeScopeUnit* IFunctionUnit::getEntry() { return getScopeUnit(function->getEntryScope()); } template<> compilation::IFunctionUnit* CompilePassCustomDecorators::buildFunctionUnit(const ManagedFnPtr& function){ return new DefaultFunctionUnit(function, this); } template<> compilation::ICodeScopeUnit* CompilePassCustomDecorators::buildCodeScopeUnit(const CodeScope* const scope, IFunctionUnit* function){ return new DefaultCodeScopeUnit(scope, function, this); } -} // emf of compilation +} // end of compilation -IFunctionUnit* +compilation::IFunctionUnit* CompilePass::getFunctionUnit(const ManagedFnPtr& function) { unsigned int id = function.id(); if (!functions.count(id)) { - IFunctionUnit* unit = buildFunctionUnit(function); + compilation::IFunctionUnit* unit = buildFunctionUnit(function); functions.emplace(id, unit); return unit; } return functions.at(id); } void CompilePass::run() { - managerTransformations = new TransformationsManager(); + managerTransformations = new xreate::compilation::TransformationsManager(); 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"); + StaticModel model = man->clasp->query(Config::get("function-entry")); + assert(model.size() && "Error: No entry function found"); + assert(model.size() == 1 && "Error: Ambiguous entry function"); - string nameMain = std::get<0>(ClaspLayer::parse(model->first->second)); - IFunctionUnit* unitMain = getFunctionUnit(man->root->findFunction(nameMain)); + string nameMain = std::get<0>(ClaspLayer::parse(model.begin()->second)); + compilation::IFunctionUnit* 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 context::ContextQuery(), QueryId::ContextQuery); Attachments::init(); clasp->registerQuery(new polymorph::PolymorphQuery(), QueryId::PolymorphQuery); } } //end of namespace xreate /** * \class xreate::CompilePass * \brief Encapsulates all compilation activities * * xreate::CompilePass iterates over xreate::AST tree and produces executable code fed by data(via xreate::Attachments) gathered by previous passes as well as data via queries(xreate::IQuery) from xreate:ClaspLayer reasoner. * Compilation's done using xreate::LLVMLayer(wrapper over LLVM toolchain) and based on following aspects: * - Containers support. See \ref compilation/containers.h * - Late Conext compilation. See xreate::context::LateContextCompiler2 * - Interpretation support. See xreate::interpretation::TargetInterpretation * - Loop saturation support. See xreate::compilation::TransformerSaturation * - External Code access. See xreate::ExternLayer(wrapper over Clang library) * * \section adaptability_sect Adaptability * xreate::CompilePass's architecture provides adaptability by employing: * - %Function Decorators to alter function-level compilation. See xreate::compilation::IFunctionUnit * - Code Block Decorators to alter code block level compilation. See xreate::compilation::ICodeScopeUnit * Default functionality defined by \ref xreate::compilation::DefaultCodeScopeUnit * - Targets to allow more versitile extensions. * Currently only xreate::interpretation::TargetInterpretation use Targets infrastructure. See xreate::compilation::Target * - %Altering Function invocation. xreate::compilation::ICallStatement * * Client able to construct compiler with desired decorators using xreate::compilation::CompilePassCustomDecorators. * As a handy alias, `CompilePassCustomDecorators` constructs default compiler * */ diff --git a/cpp/src/pass/compilepass.h b/cpp/src/pass/compilepass.h index 148012b..a21db70 100644 --- a/cpp/src/pass/compilepass.h +++ b/cpp/src/pass/compilepass.h @@ -1,219 +1,207 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * Author: pgess * * compilepass.h */ #ifndef COMPILEPASS_H #define COMPILEPASS_H #include "abstractpass.h" #include "llvm/IR/Function.h" namespace xreate { class ClaspLayer; class CompilePass; class LLVMLayer; - namespace adhoc{ - class AdhocScheme; - } - - namespace context{ - class ContextQuery; - class LateContextCompiler2; - } - namespace interpretation{ class TargetInterpretation; } } namespace xreate { namespace compilation { class ICodeScopeUnit; class IFunctionUnit; class TransformationsManager; /** \brief Holds current position in %AST while traversing*/ struct Context{ ICodeScopeUnit* scope; IFunctionUnit* function; CompilePass* pass; }; /** \brief Interface to specify custom way of function invocation * \details Default implementation is xreate::compilation::CallStatementRaw */ class ICallStatement { public: /** \brief Returns result of custom function invocation for given arguments*/ virtual llvm::Value* operator() (std::vector&& args, const std::string& hintDecl="") = 0; }; /** \brief Default ICallStatement implementation */ class CallStatementRaw: public ICallStatement{ 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) {} /** \brief Makes type conversions and returns LLVM call statement with given arguments*/ llvm::Value* operator() (std::vector&& args, const std::string& hintDecl=""); private: llvm::Value* __callee; llvm::FunctionType* __calleeTy; LLVMLayer* llvm; }; /** \brief Interface to allow modification of CodeScope compilation * \details Default implementation defined in xreate::compilation::DefaultCodeScopeUnit */ class ICodeScopeUnit{ public: CompilePass* const pass; IFunctionUnit* const function; const CodeScope* const scope; llvm::BasicBlock* currentBlockRaw; ICodeScopeUnit(const CodeScope* const codeScope, IFunctionUnit* f, CompilePass* compilePass); virtual ~ICodeScopeUnit(); 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 Symbol bindArg(llvm::Value* value, std::string&& alias)=0; virtual void bindArg(llvm::Value* value, const ScopedSymbol& s)=0; protected: virtual ICallStatement* findFunction(const Expression& opCall)=0; }; /** \brief Minimal useful ICodeScopeUnit implementation suited for inheritance */ class BasicCodeScopeUnit: public ICodeScopeUnit{ public: BasicCodeScopeUnit(const CodeScope* const codeScope, IFunctionUnit* f, CompilePass* compilePass); llvm::Value* processSymbol(const Symbol& s, std::string hintRetVar="") override; llvm::Value* process(const Expression& expr, const std::string& hintVarDecl="") override; llvm::Value* compile(const std::string& hintBlockDecl="") override; protected: ICallStatement* findFunction(const Expression& opCall) override; }; /** \brief Interface to specify compilation of %Function */ class IFunctionUnit{ public: IFunctionUnit(ManagedFnPtr f, CompilePass* p): function(f), pass(p) {} virtual ~IFunctionUnit(); llvm::Function* compile(); ICodeScopeUnit* getEntry(); ICodeScopeUnit* getScopeUnit(const CodeScope * const scope); ICodeScopeUnit* getScopeUnit(ManagedScpPtr scope); ManagedFnPtr function; llvm::Function* raw = nullptr; protected: CompilePass* pass=nullptr; virtual std::string prepareName() = 0; virtual std::vector prepareArguments() = 0; virtual llvm::Type* prepareResult() = 0; virtual llvm::Function::arg_iterator prepareBindings() = 0; private: std::map> __scopes; std::list> __orphanedScopes; }; /** \brief Minimal useful IFunctionUnit implementation suited for inheritance */ class BasicFunctionUnit: public IFunctionUnit{ public: BasicFunctionUnit(ManagedFnPtr f, CompilePass* p) : IFunctionUnit(f, p) {} protected: std::string prepareName() override; virtual std::vector prepareArguments() override; virtual llvm::Type* prepareResult() override; virtual llvm::Function::arg_iterator prepareBindings() override; }; } // end of namespace compilation class CompilePass : public AbstractPass { - friend class context::LateContextCompiler2; friend class compilation::BasicCodeScopeUnit; friend class compilation::IFunctionUnit; public: compilation::TransformationsManager* managerTransformations; interpretation::TargetInterpretation* targetInterpretation; CompilePass(PassManager* manager): AbstractPass(manager) {} /** \brief Executes compilation process */ void run() override; /**\brief Returns compiled specified %Function * \details Executes function compilation or read cache if it's already done */ compilation::IFunctionUnit* getFunctionUnit(const ManagedFnPtr& function); /**\brief Returns compiled main(entry) %Function in program */ llvm::Function* getEntryFunction(); /** \brief Initializes queries required by compiler. See xreate::IQuery, xreate::ClaspLayer */ static void prepareQueries(ClaspLayer* clasp); protected: virtual compilation::IFunctionUnit* buildFunctionUnit(const ManagedFnPtr& function)=0; virtual compilation::ICodeScopeUnit* buildCodeScopeUnit(const CodeScope* const scope, compilation::IFunctionUnit* function)=0; private: //TODO free `functions` in destructor std::map functions; llvm::Function* entry = 0; - - context::ContextQuery* queryContext; }; namespace compilation{ /** \brief Constructs compiler with desired %Function and %Code Scope decorators. See adaptability in xreate::CompilePass*/ template class CompilePassCustomDecorators: public ::xreate::CompilePass{ public: CompilePassCustomDecorators(PassManager* manager): ::xreate::CompilePass(manager) {} virtual compilation::IFunctionUnit* buildFunctionUnit(const ManagedFnPtr& function) override{ return new FUNCTION_DECORATOR(function, this); } virtual compilation::ICodeScopeUnit* buildCodeScopeUnit(const CodeScope* const scope, IFunctionUnit* function) override{ return new SCOPE_DECORATOR(scope, function, this); } }; template<> compilation::IFunctionUnit* CompilePassCustomDecorators::buildFunctionUnit(const ManagedFnPtr& function); template<> compilation::ICodeScopeUnit* CompilePassCustomDecorators::buildCodeScopeUnit(const CodeScope* const scope, IFunctionUnit* function); }} //end of namespace xreate::compilation #endif // COMPILEPASS_H diff --git a/cpp/src/query/containers.cpp b/cpp/src/query/containers.cpp index fe51b5f..023551e 100644 --- a/cpp/src/query/containers.cpp +++ b/cpp/src/query/containers.cpp @@ -1,178 +1,178 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * Author: pgess * * containers.cpp * Created on 3/14/15. */ /** * \file query/containers.h * \brief Represents reasoner's solution on [Container implementations](/w/concepts/containers) */ #include #include "query/containers.h" using namespace std; using namespace xreate::containers; using namespace xreate; Implementation Query::queryImplementation(xreate::Symbol const &s) { if (Attachments::exists(s)) { return Attachments::get(s); } return Implementation::create(s); } Query::Query(){ Attachments::init(); } void Query::init(ClaspLayer* clasp) { if (flagIsDataLoaded) return; map prototypes; map roots; - //read all proto data + //Read all proto data auto range = clasp->query(Config::get("containers.id.prototypes")); - if (range) - for(ClaspLayer::ModelIterator atom = range->first; atom != range->second; ++atom) { - auto data = ClaspLayer::parse(atom->second); + if (range.size()) + for(auto atom: range) { + auto data = ClaspLayer::parse(atom.second); Symbol root = clasp->unpack(get<0> (data)); Symbol prototype = clasp->unpack(get<1> (data)); prototypes[root] = prototype; } - // fill implementation data for a data sources: + //Fill implementation data for a data sources: range = clasp->query(Config::get("containers.id.implementations")); - if (range) - for(ClaspLayer::ModelIterator atom = range->first; atom != range->second; ++atom) + if (range.size()) + for(auto atom: range) { - auto data = ClaspLayer::parse(atom->second); + auto data = ClaspLayer::parse(atom.second); Symbol var = clasp->unpack(get<0>(data)); string implSerialized = get<1>(data); //data source, has no prototypes: if (!prototypes.count(var)) { Implementation impl = Implementation::create(var); Attachments::put(var, move(impl)); continue; } roots.emplace(move(var), move(implSerialized)); } //fill implementation data for a cluster roots for (const pair & root: roots) { Symbol prototype = prototypes[root.first]; while (prototypes.count(prototype)) { prototype = prototypes.at(prototype); } Attachments::put(root.first, Implementation(Attachments::get(prototype))); } // read cluster data and fill implementation data for cluster members range = clasp->query(Config::get("containers.id.clusters")); - if (range) - for(ClaspLayer::ModelIterator atom = range->first; atom != range->second; ++atom) + if (range.size()) + for(auto atom: range) { - auto info = ClaspLayer::parse(atom->second); + auto info = ClaspLayer::parse(atom.second); Symbol root = clasp->unpack(get<0>(info)); Symbol child = clasp->unpack(get<1>(info)); if (!(child == root) && (Attachments::exists(root))) { Implementation rootImpl = Attachments::get(root); Attachments::put(child, move(rootImpl)); } } flagIsDataLoaded = true; } //static ImplementationData* create(Symbol var, std::string implSerialized, const ImplementationData* implPrototype); Implementation Implementation::create(const Symbol &var) { //TODO review implementation determination strategy Expression varDecl = CodeScope::getDefinition(var); switch (varDecl.op) { case Operator::LIST_RANGE: { ImplementationRec rec{var}; return {ON_THE_FLY, rec}; } case Operator::LIST: { return {SOLID, ImplementationRec {varDecl.getOperands().size()}}; } default: break; }; ImplementationLinkedList ill(var); if (ill){ return ill.getImplementationData(); } assert(false && "Unable to determine proper implementation for the symbol"); return Implementation(); } Implementation Implementation::create(const Symbol& var, const std::string& implSerialized) { Expression varDecl = CodeScope::getDefinition(var); if (implSerialized == Config::get("containers.impl.solid")) { return {SOLID, ImplementationRec{varDecl.operands.size()}}; } else if (implSerialized == Config::get("containers.impl.onthefly")) { return {ON_THE_FLY, ImplementationRec{var}}; } assert(false && "unable to determine proper implementation for the symbol"); return Implementation(); } ImplementationLinkedList::ImplementationLinkedList(const Symbol& source) : flagIsValid(false), s(source){ const Expression& sourceExpr = CodeScope::getDefinition(source); if (sourceExpr.tags.count(Config::get("containers.id.linkedlist"))){ flagIsValid = true; Expression tagLinkedlist = sourceExpr.tags.at(Config::get("containers.id.linkedlist")); assert(tagLinkedlist.operands.size() == 2); fieldPointer = tagLinkedlist.operands.at(0).getValueString(); terminator = tagLinkedlist.operands.at(1); } } ImplementationLinkedList:: operator bool () const{ return flagIsValid; } Implementation ImplementationLinkedList::getImplementationData() const { return {ON_THE_FLY, ImplementationRec{s}}; } diff --git a/cpp/src/query/context.cpp b/cpp/src/query/context.cpp deleted file mode 100644 index ba9acdd..0000000 --- a/cpp/src/query/context.cpp +++ /dev/null @@ -1,219 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - * - * context.cpp - * - * Created on: Dec 1, 2015 - * Author: pgess - */ - -/** - * \file query/context.h - * \brief Represents reasoner's solution on [Context](/w/concepts/context) - * - * \class xreate::context::ContextQuery - * Currently context compilation governed by xreate::compilation::BasicCodeScopeUnit - * \sa LateContextCompiler2, [Context Concept](/w/concepts/context) - */ - -#include -#include -#include - -using namespace std; -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::context */ diff --git a/cpp/src/query/context.h b/cpp/src/query/context.h deleted file mode 100644 index 93f99cf..0000000 --- a/cpp/src/query/context.h +++ /dev/null @@ -1,101 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - * - * context.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 context{ - -typedef ExpressionSerialization::Serializer Domain; -typedef boost::bimap FunctionDemand; -typedef std::map Decisions; -typedef std::map DependentDecision; - -/** \brief Extracts logic solver's solutions about Context */ -class ContextQuery: public IQuery { - //AdhocQuery(); -public: - /**\brief Returns scope's context */ - const Domain& getContext(const ScopePacked& scopeId) const; - /**\brief Returns scope's context */ - 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::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/src/query/polymorph.cpp b/cpp/src/query/polymorph.cpp index fa4038b..2302d9f 100644 --- a/cpp/src/query/polymorph.cpp +++ b/cpp/src/query/polymorph.cpp @@ -1,34 +1,33 @@ /* * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * File: polymorph.cpp * Author: pgess * * Created on November 9, 2017, 12:14 PM */ #include "polymorph.h" using namespace std; namespace xreate { namespace polymorph { void PolymorphQuery::init(ClaspLayer* clasp){ const std::string& atomGuard = "dfa_callguard"; - ClaspLayer::ModelFragment query = clasp->query(atomGuard); - if (query){ - for (auto entry = query->first; entry!=query->second; ++entry){ + StaticModel queryResult = clasp->query(atomGuard); + if (queryResult.size()){ + for (auto entry: queryResult){ unsigned int callId; Expression exprGuard; - - tie(callId, exprGuard)=ClaspLayer::parse(entry->second); + tie(callId, exprGuard)=ClaspLayer::parse(entry.second); Attachments::put(callId, exprGuard); } } } }} //end of xreate::polymorph diff --git a/cpp/src/xreatemanager.cpp b/cpp/src/xreatemanager.cpp index fa1ae01..47fbf75 100644 --- a/cpp/src/xreatemanager.cpp +++ b/cpp/src/xreatemanager.cpp @@ -1,156 +1,157 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * xreatemanager.cpp * * Author: pgess * Created on July 3, 2017, 6:03 PM */ #include "xreatemanager.h" +#include "pass/abstractpass.h" #include "clasplayer.h" #include "aux/xreatemanager-decorators.h" #include "llvmlayer.h" #include "main/Parser.h" #include #include namespace xreate { void PassManager::registerPass(IPass* pass, const PassId& id, IPass* parent) { __passes.emplace(id, pass); __passDependencies.emplace(parent, pass); } IPass* PassManager::getPassById(const PassId& id){ assert(__passes.count(id)); return __passes[id]; } bool PassManager::isPassRegistered(const PassId& id){ return __passes.count(id); } void PassManager::executePasses(){ std::list passes{nullptr}; while (passes.size()){ IPass* parent = passes.front(); auto range = __passDependencies.equal_range(parent); for (auto i=range.first; i!=range.second; ++i){ IPass* pass = i->second; pass->run(); pass->finish(); passes.push_back(pass); } passes.pop_front(); } } void PassManager::prepare(AST* ast){ root = ast; clasp = new ClaspLayer(); clasp->ast = ast; llvm = new LLVMLayer(ast); } PassManager::~PassManager(){} typedef XreateManagerDecoratorFull XreateManagerDecoratorDefault; namespace details{ namespace tier2{ XreateManager* XreateManager::prepare(std::string&& code){ auto man = new XreateManagerImpl; man->prepareCode(std::move(code)); return man; } XreateManager* XreateManager::prepare(FILE* code){ auto man = new XreateManagerImpl; man->prepareCode(code); return man; } }} namespace details { namespace tier1 { XreateManager* XreateManager::prepare(std::string&& code){ auto man = new XreateManagerImpl; man->prepareCode(std::move(code)); return man; } XreateManager* XreateManager::prepare(FILE* code){ auto man = new XreateManagerImpl; man->prepareCode(code); return man; } }} /** * \class xreate::XreateManager * \brief Entry point of Xreate API * * Manages whole Xreate's internal workflow. There are 4 distinctive stages covered by XreateManager: * - initPasses() To init passes * - executePasses() To execute passes * - analyse() To run reasoner * - run() To run compiler * * For adaptability manager comes with several *Frontends*: * - xreate::details::tier2::XreateManager has all stages accessible by client for full control * - xreate::details::tier1::XreateManager has only analyse() and run(), where analyse() combines execution of all previous stages * - xreate::XreateManager has only run() to combine all stages for convenient use * * Moreover there are *Backends*: * - xreate::XreateManagerDecoratorBase Simple backend intended for inheritance without much functionality * - XreateManagerDecoratorFull Backend intended to initialize all builtin passes * * Thus, client's code could combine desired frontend and desired backend as see fit. * Default xreate::XreateManager connects full backend to init all builtin passes * to a simplest frontend with only run() available to execute all stages at once */ /** *\brief Constructs XreateManager for a given code */ XreateManager* XreateManager::prepare(std::string&& code) { auto man = new XreateManagerImpl; man->prepareCode(std::move(code)); return man; } /** *\brief Constructs XreateManager for a given script file */ XreateManager* XreateManager::prepare(FILE* code){ auto man = new XreateManagerImpl; man->prepareCode(code); return man; } } diff --git a/cpp/src/xreatemanager.h b/cpp/src/xreatemanager.h index 800191e..d5fbf43 100644 --- a/cpp/src/xreatemanager.h +++ b/cpp/src/xreatemanager.h @@ -1,142 +1,141 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * xreatemanager.h * * Author: pgess * Created on July 3, 2017, 6:03 PM */ /** * \file * \brief Entry point of Xreate API. * */ #ifndef PASSMANAGER_H #define PASSMANAGER_H #include #include //stdio external struct _IO_FILE; typedef struct _IO_FILE FILE; namespace xreate { namespace grammar { namespace main { class Scanner; }}} namespace xreate { class IPass; class ClaspLayer; class LLVMLayer; class AST; enum class PassId { CFGPass, CompilePass, DFGPass, EnvironmentTestsPass, LoggerPass, - AdhocPass, RulesPass, InterpretationPass, VersionsPass }; /** * \class PassManager * \brief Base class to control passes */ class PassManager{ public: void prepare(AST* ast); void registerPass(IPass* pass, const PassId& id, IPass* prerequisite=nullptr); IPass* getPassById(const PassId& id); bool isPassRegistered(const PassId& id); void executePasses(); virtual ~PassManager(); ClaspLayer* clasp; LLVMLayer* llvm; AST* root; private: std::map __passes; std::multimap __passDependencies; }; namespace details{ namespace tier2{ class XreateManager: public virtual PassManager{ public: virtual ~XreateManager(){}; virtual void initPasses()=0; // virtual void executePasses()=0; virtual void analyse()=0; virtual void* run()=0; static XreateManager* prepare(std::string&& code); static XreateManager* prepare(FILE* code); }; template class XreateManagerImpl: public Decorator { public: }; }} //namespace details::tier2 namespace details{ namespace tier1{ class XreateManager: public virtual PassManager{ public: virtual void analyse()=0; virtual void* run()=0; static XreateManager* prepare(std::string&& code); static XreateManager* prepare(FILE* code); }; template class XreateManagerImpl: public XreateManager, public details::tier2::XreateManagerImpl { typedef details::tier2::XreateManagerImpl PARENT; public: void analyse(){ PARENT::initPasses(); PARENT::executePasses(); PARENT::analyse(); } void* run(){ return PARENT::run(); } }; }} //namespace details::tier1 class XreateManager: public virtual PassManager{ public: virtual void* run()=0; static XreateManager* prepare(std::string&& code); static XreateManager* prepare(FILE* code); }; template class XreateManagerImpl: public XreateManager, public details::tier1::XreateManagerImpl{ typedef details::tier1::XreateManagerImpl PARENT; public: void* run(){ PARENT::analyse(); return PARENT::run(); } }; } //namespace xreate #endif diff --git a/cpp/tests/CMakeLists.txt b/cpp/tests/CMakeLists.txt index fae4c99..9faa990 100644 --- a/cpp/tests/CMakeLists.txt +++ b/cpp/tests/CMakeLists.txt @@ -1,54 +1,54 @@ cmake_minimum_required(VERSION 2.8.11) project(xreate-tests) find_package(GTest REQUIRED) INCLUDE_DIRECTORIES(${GTEST_INCLUDE_DIRS}) INCLUDE_DIRECTORIES("/usr/include/libxml2") INCLUDE_DIRECTORIES($) # TESTS #========================= FIND_PACKAGE (LLVM REQUIRED) message("LLVM_LIBRARY_DIRS: " ${LLVM_LIBRARY_DIRS}) link_directories(${LLVM_LIBRARY_DIRS}) set (LIBCLASP_PATH ${POTASSCO_PATH}/build/debug) link_directories(${LIBCLASP_PATH}) #aux_source_directory(. TEST_FILES) set(TEST_FILES + latereasoning.cpp virtualization.cpp exploitation.cpp communication.cpp polymorph.cpp association.cpp main.cpp modules.cpp - adhoc.cpp attachments.cpp ast.cpp cfa.cpp dfa.cpp compilation.cpp ExpressionSerializer.cpp externc.cpp types.cpp vendorAPI/clangAPI.cpp vendorAPI/xml2.cpp vendorAPI/json.cpp containers.cpp interpretation.cpp loops.cpp #supplemental/versions-algorithm-data_dependency.cpp effects-versions.cpp ) add_executable(${PROJECT_NAME} ${TEST_FILES}) target_link_libraries(${PROJECT_NAME} xreate ${GTEST_LIBRARIES} pthread xml2 gcov) add_custom_target (coverage COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/src/code-coverage.sh WORKING_DIRECTORY ${CMAKE_BINARY_DIR}) diff --git a/cpp/tests/adhoc.cpp b/cpp/tests/adhoc.cpp deleted file mode 100644 index 8e9578b..0000000 --- a/cpp/tests/adhoc.cpp +++ /dev/null @@ -1,196 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - * http://creativecommons.org/publicdomain/zero/1.0/ - * - * 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" - "}"); - - const 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)::unknType {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" - "}" - ); - - const 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()); -} diff --git a/cpp/tests/cfa.cpp b/cpp/tests/cfa.cpp index 409ecc9..f520b39 100644 --- a/cpp/tests/cfa.cpp +++ b/cpp/tests/cfa.cpp @@ -1,195 +1,190 @@ /* Any copyright is dedicated to the Public Domain. * http://creativecommons.org/publicdomain/zero/1.0/ * * 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 "analysis/cfagraph.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); + StaticModel answer = man->clasp->query("annotationF1"); + EXPECT_EQ(1, answer.size()); answer = man->clasp->query("annotationF2"); - countNoneValue = 0; - if (answer) countNoneValue = std::distance(answer->first, answer->second); - - EXPECT_EQ(1, countNoneValue); + EXPECT_EQ(1, answer.size()); } 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)); + StaticModel model = man->clasp->query("annotation1"); + ScopePacked scopeIdActual = std::get<0>(ClaspLayer::parse(model.begin()->second)); CodeScope* scopeEntry = man->root->findFunction("main")->getEntryScope(); const Expression& exprSum = scopeEntry->getDefinition(scopeEntry->getSymbol("sum")); CodeScope* scopeExpected = exprSum.blocks.front(); ScopePacked scopeIdExpected = man->clasp->pack(scopeExpected); ASSERT_EQ(scopeIdExpected, scopeIdActual); } TEST(CFA, DependenciesFnCall){ details::tier2::XreateManager* man = details::tier2::XreateManager::prepare( R"Code( a = function::int{ seq {x = 0:: int. x} {x = b():: int. x}::int } b = function::int {y = 0. y} )Code"); CodeScope* scopeSeq1 = man->root->findFunction("a")->getEntryScope()->getBody().blocks.front(); CodeScope* scopeSeq2 = *(++man->root->findFunction("a")->getEntryScope()->getBody().blocks.begin()); CodeScope* scopeB = man->root->findFunction("b")->getEntryScope(); ScopePacked psSeq1 = man->clasp->pack(scopeSeq1); ScopePacked psSeq2 = man->clasp->pack(scopeSeq2); ScopePacked psB = man->clasp->pack(scopeB); CFAPass* pass = new CFAPass(man); man->registerPass(pass, PassId::CFGPass); man->executePasses(); const CFAGraph* report = dynamic_cast(man->getPassById(PassId::CFGPass))->getReport(); auto dependencies = report->__dependencyRelations; delete pass; ASSERT_EQ(1, dependencies.count(psSeq2)); ASSERT_EQ(1, dependencies.count(psB)); } TEST(CFA, DependenciesChildScope){ details::tier2::XreateManager* man = details::tier2::XreateManager::prepare( R"Code( a = function::int{ seq {x = 0:: int. x} {x=0::int. if(x>0)::int{1} else {0}}::int } )Code"); CodeScope* scopeSeq1 = man->root->findFunction("a")->getEntryScope()->getBody().blocks.front(); CodeScope* scopeSeq2 = *(++man->root->findFunction("a")->getEntryScope()->getBody().blocks.begin()); CodeScope* scopeIf1 = scopeSeq2->getBody().blocks.front(); CodeScope* scopeIf2 = *(++scopeSeq2->getBody().blocks.begin()); ScopePacked psSeq1 = man->clasp->pack(scopeSeq1); ScopePacked psSeq2 = man->clasp->pack(scopeSeq2); ScopePacked psIf1 = man->clasp->pack(scopeIf1); ScopePacked psIf2 = man->clasp->pack(scopeIf2); CFAPass* pass = new CFAPass(man); man->registerPass(pass, PassId::CFGPass); man->executePasses(); const CFAGraph* report = dynamic_cast(man->getPassById(PassId::CFGPass))->getReport(); auto dependencies = report->__dependencyRelations; delete pass; ASSERT_EQ(0, dependencies.count(psSeq1)); ASSERT_EQ(1, dependencies.count(psSeq2)); ASSERT_EQ(1, dependencies.count(psIf1)); ASSERT_EQ(1, dependencies.count(psIf2)); for(auto rec: dependencies) { std::cout << rec.first << " " << rec.second << std::endl; } } TEST(CFA, DomReportOneRoot){ std::string program = R"CODE( a = function:: int; entry{ seq {x = 0:: int. x} {x = 1:: int. x}::int } )CODE"; std::unique_ptr man(details::tier2::XreateManager::prepare(move(program))); CFAPass* pass = new CFAPass(man.get()); man->registerPass(pass, PassId::CFGPass); pass->run(); ScopePacked scope1 = man->clasp->pack(man->root->findFunction("a")->getEntryScope()->getBody().blocks.front()); ScopePacked scope2 = man->clasp->pack(*++man->root->findFunction("a")->getEntryScope()->getBody().blocks.begin()); dominators::DominatorsTreeAnalysisProvider* providerDomAnalysis = new dominators::DominatorsTreeAnalysisProvider(); providerDomAnalysis->run(pass->getReport()); dominators::DominatorsTreeAnalysisProvider::Dominators expectedFDom= { {1, {0, 3}} ,{2, {1, 2}} }; dominators::DominatorsTreeAnalysisProvider::Dominators expectedPostDom= { {2, {0, 3}} ,{1, {1, 2}} }; auto actualFDom = providerDomAnalysis->getForwardDominators(); auto actualPostDom = providerDomAnalysis->getPostDominators(); ASSERT_EQ(expectedFDom, actualFDom); ASSERT_EQ(expectedPostDom, actualPostDom); delete providerDomAnalysis; delete pass; } diff --git a/cpp/tests/exploitation.cpp b/cpp/tests/exploitation.cpp index e1a17dd..9ac2d1d 100644 --- a/cpp/tests/exploitation.cpp +++ b/cpp/tests/exploitation.cpp @@ -1,27 +1,25 @@ -/* - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - * +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ + * * exploitation.cpp * * Author: pgess * Created on February 15, 2018, 6:17 PM */ #include "xreatemanager.h" #include "gtest/gtest.h" using namespace xreate; TEST(Exploitation, test1){ FILE* input = fopen("scripts/exploitation/test1.xreate","r"); assert(input != nullptr); std::unique_ptr man(XreateManager::prepare(input)); int (*main)() = (int (*)())man->run(); int result = main(); ASSERT_EQ(1, result); } \ No newline at end of file diff --git a/cpp/tests/latereasoning.cpp b/cpp/tests/latereasoning.cpp new file mode 100644 index 0000000..5e5f54d --- /dev/null +++ b/cpp/tests/latereasoning.cpp @@ -0,0 +1,86 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ + * + * latereasoning.cpp + * + * Author: pgess + * Created on April 21, 2018, 5:10 PM + */ + +#include "xreatemanager.h" +#include "clasplayer.h" +#include +#include "gtest/gtest.h" + +using namespace xreate; + +TEST(LateReasoning, test2) { + FILE* input = fopen("scripts/latereasoning/test2.xreate", "r"); + assert(input != nullptr); + + std::unique_ptr man(XreateManager::prepare(input)); + + int (*main)() = (int (*)())man->run(); + int result = main(); + + ASSERT_EQ(3, result); +} + +/** + * Test plan: + * - add late annotation(several variants) + * - define late bindings + * - get late variant wrt defined bindings + **/ + +TEST(LateReasoning, PutAndGetLateAnnotation1) { +#define FORMATSYMBOL(s) (formatSymb % s.identifier % s.version % s.scope).str() + Attachments::init(); + std::unique_ptr clasp(new ClaspLayer()); + + std::unique_ptr scope(new CodeScope(nullptr)); + Symbol symbA = scope->addDefinition(Atom("a"), Expression()); + Symbol symbB = scope->addDefinition(Atom("b"), Expression()); + Symbol symbC = scope->addDefinition(Atom("c"), Expression()); + Symbol symbTarget = scope->addDefinition(Atom("target"), Expression()); + + SymbolPacked symbpA = clasp->pack(symbA, "a"); + SymbolPacked symbpB = clasp->pack(symbB, "b"); + SymbolPacked symbpC = clasp->pack(symbC, "c"); + SymbolPacked symbpTarget = clasp->pack(symbTarget, "target"); + + boost::format formatSymb("s(%1%,%2%,%3%)"); + boost::format formatLateAnnotation("late(%1%, (%2%, %3%, %4%), (%5%, %6%, %7%), %8%)."); + + //Add `variant1` variant + clasp->addRawScript((formatLateAnnotation + % FORMATSYMBOL(symbpTarget) + % FORMATSYMBOL(symbpA) % FORMATSYMBOL(symbpB) % FORMATSYMBOL(symbpC) + % "guard1" % "guard1" % "guard1" + % "result(variant1)" + ). str()); + + //Add `result2` variant + clasp->addRawScript((formatLateAnnotation + % FORMATSYMBOL(symbpTarget) + % FORMATSYMBOL(symbpA) % FORMATSYMBOL(symbpB) % FORMATSYMBOL(symbpC) + % "guard2" % "guard2" % "guard2" + % "result(variant2)" + ). str()); + + clasp->run(); + + //Define keys + Attachments::put(symbA, Expression(Operator::CALL, {Atom("guard2")})); + Attachments::put(symbB, Expression(Operator::CALL, {Atom("guard2")})); + Attachments::put(symbC, Expression(Operator::CALL, {Atom("guard2")})); + + //Fetch late annotation + ReasoningModel model = clasp->queryCompiled(""); + StaticModel answer = model.queryLate("result", symbpTarget); + ASSERT_EQ(1, answer.size()); + + auto answerParsed = clasp->parse(answer.begin()->second); + std::tuple answerOption = clasp->parse(std::get<3>(answerParsed)); + ASSERT_STREQ("variant2", std::get<0>(answerOption).c_str()); +} \ No newline at end of file diff --git a/cpp/tests/virtualization.cpp b/cpp/tests/virtualization.cpp index eccbd29..d5c10ec 100644 --- a/cpp/tests/virtualization.cpp +++ b/cpp/tests/virtualization.cpp @@ -1,38 +1,24 @@ -/* - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - = +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ + * * virtualization.cpp * * Author: pgess * Created on February 24, 2018, 4:30 PM */ #include "xreatemanager.h" #include "gtest/gtest.h" using namespace xreate; TEST(Virtualization, test1){ FILE* input = fopen("scripts/virtualization/test1.xreate","r"); assert(input != nullptr); std::unique_ptr man(XreateManager::prepare(input)); int (*main)() = (int (*)())man->run(); int result = main(); ASSERT_EQ(1, result); -} - -TEST(Virtualization, test2){ - FILE* input = fopen("scripts/virtualization/test2.xreate","r"); - assert(input != nullptr); - - std::unique_ptr man(XreateManager::prepare(input)); - - int (*main)() = (int (*)())man->run(); - int result = main(); - - ASSERT_EQ(3, result); } \ No newline at end of file diff --git a/grammar/xreate.ATG b/grammar/xreate.ATG index 408c907..4e3818e 100644 --- a/grammar/xreate.ATG +++ b/grammar/xreate.ATG @@ -1,663 +1,644 @@ //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 std; COMPILER Xreate details::inconsistent::AST* root = nullptr; // current program unit void ensureInitalizedAST(){ if (root == nullptr) root = new details::inconsistent::AST(); } struct { 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 checkTokenAfterIdent(int key){ if (la->kind != _ident) return false; return nextToken() == key; } 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)){ 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 | GuardSection | 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 (. const_cast(entry->getBody()).bindType(move(typOut));.) . GuardSection<>= (. Expression guard; Function* f; .) "guard" tagcolon MetaSimpExpr lcurbrack { FDecl (. f->guard = guard; 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 | TVariant | 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::LIST, {ty}); .) . TStruct = (. TypeAnnotation t; std::wstring key; size_t keyCounter=0; .) lcurbrack ( IF(checkTokenAfterIdent(_tagcolon)) Ident tagcolon Type | Type (. key = to_wstring(keyCounter++); .) ) (. typ = TypeAnnotation(TypeOperator::LIST_NAMED, {t}); typ.fields.push_back(Atom(key).get()); .) {',' ( IF(checkTokenAfterIdent(_tagcolon)) Ident tagcolon Type | Type (. key = to_wstring(keyCounter++); .) ) (. typ.__operands.push_back(t); typ.fields.push_back(Atom(key).get()); .) } rcurbrack. TVariant= (. TypeAnnotation t, typVoid(TypeOperator::LIST_NAMED, {}); std::vector operands; std::vector> keys; std::wstring variant; .) "variant" lcurbrack Ident (. t=typVoid; .) [tagcolon Type] (. keys.push_back(Atom(variant)); operands.push_back(t); .) {',' Ident (. t=typVoid; .) [tagcolon Type] (. keys.push_back(Atom(variant)); operands.push_back(t); .) } rcurbrack (. typ = TypeAnnotation(TypeOperator::VARIANT, {}); typ.__operands = operands; typ.addFields(std::move(keys)); .) . TDecl = (. TypeAnnotation t; std::wstring tname, arg; std::vector> args; .) Ident assign "type" ['(' 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 (. Symbol identSymbol = f->addDefinition(move(var), move(value)); Attachments::put(value, identSymbol); .) . BDecl = lcurbrack (. Expression body; pushContextScope(scope); .) {(IF(checkAssignment()) VDecl '.' | RuleContextDecl | ContextDecl'.' | ExprTyped (. scope->setBody(body); Attachments::put(body, Symbol{ScopedSymbol::RetSymbol, scope});.) )} rcurbrack (. popContextScope(); .) . 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 CodeScope(context.scope)); .) "loop" ("map" '(' Expr implic Ident (. e = Expression(Operator::MAP, {eIn}); .) tagcolon ExprAnnotations ')' tagcolon ExprAnnotations (. e.addBindings({Atom(varEl)}); block->addBinding(Atom(varEl), move(tagsEl)); .) BDecl<&*block> (. e.addBlock(block); .) |"fold" ("inf" '(' Expr implic Ident ')' (. e = Expression(Operator::FOLD_INF, {eAcc}); e.addBindings({Atom(varAcc)}); block->addBinding(Atom(varAcc), Expression()); .) tagcolon ExprAnnotations BDecl<&*block> (. 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 (. block->addBinding(Atom(varEl), move(tagsEl)); block->addBinding(Atom(varAcc), Expression()); .) BDecl<&*block> (. e.addBlock(block); .) ) | "context" '(' string (. contextClass = t->val; .) ')' BDecl<&*block> (. e = Expression(Operator::LOOP_CONTEXT, {Expression(Atom(std::move(contextClass)))}); e.addBlock(block); .) ). // Switches SwitchDecl = (. TypeAnnotation typ; eSwitch = Expression(Operator::SWITCH, {}); Expression eCondition; Expression tag;.) "switch" ( SwitchVariantDecl | lparen ExprTyped rparen tagcolon ExprAnnotations (. eSwitch.operands.push_back(eCondition);.) CaseDecl {CaseDecl} ) . 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 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(); .) . SwitchVariantDecl = (. Expression varTested; std::wstring varAlias; bool flagAliasFound = false; expr = Expression(Operator::SWITCH_VARIANT, {}); .) "variant" lparen Expr [implic Ident (. flagAliasFound = true; .) ] [tagcolon ExprAnnotations] rparen tagcolon ExprAnnotations (. expr.addArg(std::move(varTested)); if (flagAliasFound) { expr.addBindings({Atom(varAlias)}); } else { if(varTested.__state == Expression::IDENT){ expr.addBindings({Atom(string(varTested.getValueString()))}); } } .) CaseVariantDecl {CaseVariantDecl} . CaseVariantDecl = (. ManagedScpPtr scope = root->add(new CodeScope(context.scope)); std::wstring key; scope->addBinding(Atom(string(expr.bindings.front())), Expression()); .) "case" lparen Ident rparen (. expr.addArg(root->recognizeVariantConstructor(Atom(std::move(key)))); .) BDecl<&*scope> (. expr.addBlock(scope); .) . IntrinsicDecl= (. std::wstring name; .) "intrinsic" Ident< name> (. outer = Expression(Operator::CALL_INTRINSIC, {}); outer.setValue(Atom(name)); .) lparen [CalleeParams] rparen . SequenceDecl = (. sequence = Expression(); sequence.setOp(Operator::SEQUENCE); ManagedScpPtr scope = root->add(new CodeScope(context.scope)); .) "seq" BDecl<&*scope> (. sequence.blocks.push_back(&*scope); scope = root->add(new CodeScope(&*scope)); .) { (. scope = root->add(new CodeScope(&*scope)); .) BDecl<&*scope> (. sequence.blocks.push_back(&*scope); .) }. /*============================ 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<> = (. ExternData data; .) '{' {IncludeExternDecl | LibExternDecl } '}' (. root->addExternData(move(data)); .) . LibExternDecl = (. std::wstring pkgname, libname; .) Ident assign "library" tagcolon "pkgconfig" '(' string (. pkgname = t->val; .) ')' '.' (. data.addLibrary(Atom(libname), Atom(pkgname)); .) . 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(Operator::CALL, {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 [ (. e = Expression(Operator::INDEX, {e}); .) {lbrack CalleeParams rbrack } ]. Term< Expression& e> (. std::wstring name; e = Expression(); .) = (IF (checkParametersList()) Ident< name> (. e = Expression(Operator::CALL, {Atom(name)}); root->recognizeVariantConstructor(e); .) '(' [CalleeParams] ')' | VarIdent (. recognizeIdentifier(e); .) | ListLiteral (. /* tuple */.) | StructLiteral (. /* struct */.) | LoopDecl | IfDecl | SwitchDecl - | AdhocDecl | IntrinsicDecl | SequenceDecl | number (. e = Expression(Atom(t->val)); .) | string (. e = Expression(Atom(t->val)); .) | "true" (. e = Expression(Atom(1)); e.bindType(TypePrimitive::Bool); .) | "false" (. e = Expression(Atom(0)); e.bindType(TypePrimitive::Bool); .) | "undef" (. e = Expression(Operator::UNDEF, {}); .) | '-' Term (. e = Expression(Operator::NEG, {e}); .) | '(' ExprTyped ')' ). StructLiteral = (. std::wstring key; Expression val; std::list> keys; size_t keyCounter=0; .) lcurbrack (IF(checkTokenAfterIdent(_assign)) Ident '=' Expr | Expr (. key = to_wstring(keyCounter++); .) ) (. keys.push_back(Atom(key)); e = Expression(Operator::LIST_NAMED, {val}); .) {',' (IF(checkTokenAfterIdent(_assign)) Ident '=' Expr | Expr (. key = to_wstring(keyCounter++); .) ) (. e.addArg(Expression(val)); keys.push_back(Atom(key)); .) } rcurbrack (. e.addBindings(keys.begin(), keys.end()); .) . ListLiteral = (. Expression eFrom, eTo; .) '[' (. e.setOp(Operator::LIST); .) [ Expr (. e.addArg(Expression(eFrom)); .) ( ".." Expr (. e.addArg(Expression(eTo)); e.setOp(Operator::LIST_RANGE); .) |{',' Expr (. e.addArg(Expression(eFrom)); .) } ) ] ']'. -AdhocDecl = (. Expression command; .) -"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. diff --git a/scripts/virtualization/context-v1.lp b/scripts/latereasoning/context-v1.lp similarity index 100% rename from scripts/virtualization/context-v1.lp rename to scripts/latereasoning/context-v1.lp diff --git a/scripts/virtualization/test2.assembly.lp b/scripts/latereasoning/test2.assembly.lp similarity index 100% rename from scripts/virtualization/test2.assembly.lp rename to scripts/latereasoning/test2.assembly.lp diff --git a/scripts/virtualization/test2.xreate b/scripts/latereasoning/test2.xreate similarity index 96% rename from scripts/virtualization/test2.xreate rename to scripts/latereasoning/test2.xreate index 12942f9..5eeb13b 100644 --- a/scripts/virtualization/test2.xreate +++ b/scripts/latereasoning/test2.xreate @@ -1,101 +1,101 @@ -import raw ("scripts/virtualization/context-v1.lp"). -import raw ("scripts/virtualization/test2.assembly.lp"). +import raw ("scripts/latereasoning/context-v1.lp"). +import raw ("scripts/latereasoning/test2.assembly.lp"). Annotation = type variant { Num:: int, String:: string, Func:: {name::string, arguments::[Annotation]} }. FnControl = type variant { Variant1, Variant2 }. main = function:: int; entry { funcA() + funcB() :: int } funcA = function::int{ context:: variant1. testedFunc(prepareCtrlArg("testedFunc", intrinsic query_scope())) } funcB = function::int { context:: variant2. testedFunc(prepareCtrlArg("testedFunc", intrinsic query_scope())) } testedFunc = function(ctrl::FnControl):: int { context:: kleo_manual_demand(funcC). switch variant(ctrl)::int case(Variant1){context:: callguard(variant1). funcC():: int; dfa_polym(cntxt)} case(Variant2){context:: callguard(variant2). funcC():: int; dfa_polym(cntxt)} } guard:: variant1 { funcC = function:: int {1} } guard:: variant2 { funcC = function:: int {2} } selectSecond = function (db:: [Annotation], argFirst::Annotation):: Annotation; interpretation(force) { resultWrong = String("wrong")::Annotation. loop fold(db->entry:: Annotation, resultWrong->result):: Annotation{ switch variant(entry):: Annotation case (Num) {resultWrong} case (String) {resultWrong} case (Func) { if(entry["arguments"][0] == argFirst)::Annotation {entry["arguments"][1]::Annotation; break} else {result} } } } selectThird = function (db:: [Annotation], argFirst::Annotation, argSecond:: Annotation):: Annotation; interpretation(force){ resultWrong = String("wrong")::Annotation. loop fold(db->entry:: Annotation, resultWrong->result):: Annotation{ switch variant(entry):: Annotation case (Num) {resultWrong} case (String) {resultWrong} case (Func) { if(entry["arguments"][0] == argFirst)::Annotation{ if (entry["arguments"][1] == argSecond):: Annotation{ entry["arguments"][2]:: Annotation; break } else {result} } else {result} } } } prepareCtrlArg = function(fnName:: string; interpretation(force), scope:: Annotation; interpretation(force)) :: FnControl { demandsDb = intrinsic query("kleo_fn_demand")::[Annotation]. decisionsDb = intrinsic query("kleo_scope_decision")::[Annotation]. demandKey = selectSecond(demandsDb, Func({name = fnName, arguments = []})):: Annotation. decisionKey = Func({name="kleo_arg", arguments=[demandKey]}):: Annotation. decision = selectThird(decisionsDb, scope, decisionKey)::Annotation. switch variant(decision):: FnControl case (Num) {Variant1()} case (String) {Variant1()} case (Func) { switch(decision["name"]):: FnControl case("variant1") {Variant1()} case("variant2") {Variant2()} case default {Variant1()} } }