diff --git a/config/default.json b/config/default.json index e7f99d6..cb11b3f 100644 --- a/config/default.json +++ b/config/default.json @@ -1,74 +1,75 @@ { "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", "transcend": { "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": "intrinsic-query", + "template": "latex", "templates": { "current-fix":"*", "default": "*-Adhoc.*:Containers.*:Compilation.full_IFStatementWithVariantType:Types.full_VariantType_Switch1:Context.full_LateContext:Context.pathDependentContext:CFA.testLoopContextExists", "ast": "AST.*", "effects": "Effects.*", "basic": "Attachments.*", "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.Compilation2", + "latereasoning": "LateReasoning.Syntax1:LateReasoning.Pass_DFAPassDec_1", + "latex": "Latex.Compilation_TransitFn1", "modules": "Modules.*", "polymorphs": "Polymorphs.*", "intrinsic-query": "Types.SlaveTypes*:Association.TypedQuery*", "types": "Types.*", "virtualization": "Virtualization.test2", "vendorsAPI/clang": "ClangAPI.*", "vendorsAPI/xml2": "libxml2*" } } } diff --git a/cpp/src/CMakeLists.txt b/cpp/src/CMakeLists.txt index 8fd4295..2be602b 100644 --- a/cpp/src/CMakeLists.txt +++ b/cpp/src/CMakeLists.txt @@ -1,232 +1,236 @@ 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(STATUS "LLVM DEFS: " ${LLVM_DEFINITIONS}) execute_process( COMMAND llvm-config --libs OUTPUT_VARIABLE LLVM_LIBS OUTPUT_STRIP_TRAILING_WHITESPACE) message(STATUS "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 - compilation/interpretation-instructions.cpp - analysis/typeinference.cpp + analysis/cfagraph.cpp compilation/latereasoning.cpp + analysis/interpretation.cpp + query/latex.cpp + query/polymorph.cpp + compilation/polymorph.cpp aux/latereasoning.cpp + compilation/latex.cpp + compilation/interpretation-instructions.cpp + analysis/typeinference.cpp xreatemanager.cpp transcendlayer.cpp analysis/dfagraph.cpp analysis/DominatorsTreeAnalysisProvider.cpp llvmlayer.cpp ExternLayer.cpp pass/compilepass.cpp - query/polymorph.cpp analysis/utils.cpp pass/dfapass.cpp compilation/targetinterpretation.cpp pass/interpretationpass.cpp ast.cpp aux/xreatemanager-decorators.cpp compilation/operators.cpp compilation/transformations.cpp compilation/transformersaturation.cpp pass/versionspass.cpp attachments.cpp - analysis/cfagraph.cpp compilation/containers.cpp compilation/advancedinstructions.cpp utils.cpp pass/abstractpass.cpp pass/cfapass.cpp contextrule.cpp query/containers.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 aa97363..9d3caa9 100644 --- a/cpp/src/analysis/cfagraph.cpp +++ b/cpp/src/analysis/cfagraph.cpp @@ -1,204 +1,221 @@ /* 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/utils.h" using namespace xreate::cfa; using namespace std; void CFAGraph::print(std::ostringstream& output) const { - const std::string& atomBinding = Config::get("transcend.bindings.function"); - const std::string& atomBindingScope = Config::get("transcend.bindings.scope"); + const std::string& atomBinding = Config::get("transcend.bindings.function"); + const std::string& atomBindingScope = Config::get("transcend.bindings.scope"); - //show function tags + output << endl << "%\t\tStatic analysis: CFA" << endl; + output << __outputPrecomputed.str(); + + //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) { + 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)){ + for (const auto& tag_ : boost::make_iterator_range(tags)) { const Expression& tag = tag_.second; list tagRaw = xreate::analysis::compile(tag); - assert(tagRaw.size() == 1); + assert(tagRaw.size() == 1); output << formatBind - % (function.second) - % (tagRaw.front()) + % (function.second) + % (tagRaw.front()) << endl; ++counterTags; } } - if (bufFunctionNames.tellp()){ - output << formatFunction % (bufFunctionNames.str().substr(2)) << std::endl; + if (bufFunctionNames.tellp()) { + output << formatFunction % (bufFunctionNames.str().substr(2)) << std::endl; } if (counterTags == 0) { output << "%no functtion tags at all" << endl; } - //declare scopes + //declare scopes boost::format formatScope("scope(0..%1%)."); output << formatScope % (__transcend->getScopesCount() - 1) << std::endl; //show context rules: - for (auto rule: this->__contextRules) { - output << ContextRule(rule.second).compile(rule.first) << std::endl; + for (auto rule : this->__contextRules) { + output << ContextRule(rule.second).compile(rule.first) << std::endl; }; - //show scope tags: + //show scope tags: counterTags = 0; boost::format formatScopeBind(atomBindingScope + "(%1%, %2%, strong)."); - for (auto entry: this->__scopeTags) { + 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; + output << formatScopeBind % scopeId % (tagRaw.front()) << endl; ++counterTags; } if (counterTags == 0) { - output << "%scope tags: no tags at all" << endl; + output << "%scope tags: no tags at all" << endl; } - output << endl << "%\t\tStatic analysis: CFA" << endl; - - //parent connections - //TOTEST CFG parent function + //parent connections + //TOTEST CFG parent function boost::format formatFunctionParent("cfa_parent(%1%, function(%2%))."); - for (const auto &relation: this->__parentFunctionRelations) { + 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 + //TOTEST CFG parent scope boost::format formatScopeParent("cfa_parent(%1%, scope(%2%))."); - for (const auto &relation: this->__parentScopeRelations) { + for (const auto &relation : this->__parentScopeRelations) { output << formatScopeParent % relation.first % relation.second << endl; } - //call connections + //call connections boost::format formatCall("cfa_call(%1%, %2%)."); - for (const auto &relation: this->__callRelations) { + 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 + //function specializations descrtiption + //SECTIONTAG late-context cfa_function_specializations boost::format formatSpecializations("cfa_function_specializations(%1%, %2%)."); const list& functions = __transcend->ast->getAllFunctions(); - for (auto f: functions){ - if (f->guard.isValid()){ + 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){ + 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); + 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); +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); +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){ +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){ +CFAGraph::addParentConnection(const ScopePacked& scope, const ScopePacked& scopeParent) { __parentScopeRelations.emplace(scope, scopeParent); } unsigned int -CFAGraph::registerNodeFunction(const std::string& fname){ +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){ +CFAGraph::addDependency(const ScopePacked& scope, const ScopePacked& scopeDependency) { __dependencyRelations.emplace(scope, scopeDependency); } -bool CFAGraph::isDependent(const ScopePacked& scope) const{ +bool +CFAGraph::isDependent(const ScopePacked& scope) const { return __dependencyRelations.count(scope) > 0; } -void CFAGraph::transmitDependencies(const ScopePacked& scopeTo, const ScopePacked& scopeFrom){ +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){ + for (auto pairI = range.first; pairI != range.second; ++pairI) { dependencies.push_back(pairI->second); } - for(auto dep: dependencies){ + for(auto dep : dependencies) { __dependencyRelations.emplace(scopeTo, dep); } } + +void +CFAGraph::addScope(CodeScope* scope) { + boost::format formatScopeBinding("ast_scope_binding(%1%, %2%, \"%3%\")."); + + ScopePacked scopeId = __transcend->pack(scope); + for (int id, size = scope->__bindings.size(); id < size; ++id) { + __outputPrecomputed << formatScopeBinding + % scopeId + % id + % scope->__bindings.at(id) + << endl; + } +} \ No newline at end of file diff --git a/cpp/src/analysis/cfagraph.h b/cpp/src/analysis/cfagraph.h index 743799e..a4e1dc4 100644 --- a/cpp/src/analysis/cfagraph.h +++ b/cpp/src/analysis/cfagraph.h @@ -1,63 +1,64 @@ /* 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.h * Author: pgess * * Created on June 27, 2016, 2:09 PM */ #ifndef CFAGRAPH_H #define CFAGRAPH_H #include "transcendlayer.h" namespace xreate {namespace cfa { /** \brief Represents CFA analysis data produced by CFAPass */ class CFAGraph: public IAnalysisReport { public: typedef boost::bimap> PARENT_FUNCTION_RELATIONS; PARENT_FUNCTION_RELATIONS __parentFunctionRelations; std::map __parentScopeRelations; std::multimap __dependencyRelations; typedef boost::bimap< boost::bimaps::multiset_of, boost::bimaps::multiset_of, boost::bimaps::set_of_relation<> > CALL_RELATIONS; CALL_RELATIONS __callRelations; boost::bimap __nodesFunction; std::multimap __functionTags; std::multimap __scopeTags; std::multimap __contextRules; void print(std::ostringstream& output) const override; CFAGraph(TranscendLayer* engine): __transcend(engine){} void addFunctionAnnotations(const std::string& function, const std::map& tags); void addScopeAnnotations(const ScopePacked& scope, const std::vector&tags); void addContextRules(const ScopePacked& scope, const std::vector&rules); - void addCallConnection(const ScopePacked& scopeFrom, const std::string& functionTo); void addParentConnection(const ScopePacked& scope, const std::string& functionParent); void addParentConnection(const ScopePacked& scope, const ScopePacked& scopeParent); void addDependency(const ScopePacked& scope, const ScopePacked& scopeDependency); bool isDependent(const ScopePacked& scope) const; void transmitDependencies(const ScopePacked& scopeTo, const ScopePacked& scopeFrom); + void addScope(CodeScope* scope); private: TranscendLayer* __transcend; + std::ostringstream __outputPrecomputed; unsigned int registerNodeFunction(const std::string& fname); }; }} //end of namespace xreate::cfa #endif /* CFAGRAPH_H */ diff --git a/cpp/src/analysis/interpretation.cpp b/cpp/src/analysis/interpretation.cpp index 58c7cb6..79e2bf8 100644 --- a/cpp/src/analysis/interpretation.cpp +++ b/cpp/src/analysis/interpretation.cpp @@ -1,234 +1,273 @@ /* * 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 * Created on June 25, 2018, 3:25 PM * * \file interpretation.cpp * \brief interpretation */ #include "analysis/interpretation.h" using namespace std; namespace xreate{ namespace interpretation{ +typedef vector InstancePacked; + +std::list +generateAllInstancesInDomain2(const ExpandedType& domainT) { + if(!domainT->isValid()) { + return {Expression()}; + } + assert(domainT->__operator == TypeOperator::VARIANT); + std::list results; + int variantId = -1; + + bool flagDomainStateless = std::all_of(domainT->__operands.begin(), domainT->__operands.end(), + [](const TypeAnnotation & subdomainT) { + return !subdomainT.isValid(); + }); + + for(const TypeAnnotation& subdomainT : domainT->__operands) { + ++variantId; + + if(flagDomainStateless) { + Expression result(Operator::VARIANT,{}); + result.setValueDouble(variantId); + results.push_back(result); + continue; + } + + std::list subresults = generateAllInstancesInDomain2(ExpandedType(subdomainT)); + for (const Expression& subresult : subresults) { + Expression result(Operator::VARIANT,{}); + result.setValueDouble(variantId); + result.operands.push_back(subresult); + + results.push_back(result); + } + } + + return results; +} + TypeAnnotation collapseFnGroup(const std::list& symbols) { Gringo::Symbol symbolAny = symbols.front(); size_t operandsCount = symbolAny.args().size; TypeAnnotation resultT; resultT.__operands.reserve(operandsCount); for(size_t operandId = 0; operandId < operandsCount; ++operandId) { std::list column; for(const Gringo::Symbol& row : symbols) { column.push_back(row.args()[operandId]); } TypeAnnotation operandT = collapseColumn(column); resultT.__operands.push_back(operandT); } if(resultT.__operands.size() == 1) { return resultT.__operands.front(); } if(resultT.__operands.size() > 1) { resultT.__operator = TypeOperator::LIST_NAMED; return resultT; } return resultT; } TypeAnnotation collapseColumn(const std::list& symbols) { TypeAnnotation resultT; if(!symbols.size()) return resultT; Gringo::Symbol symbolAny = symbols.front(); switch(symbolAny.type()) { case Gringo::SymbolType::Num: { return TypeAnnotation(TypePrimitive::Num); } case Gringo::SymbolType::Str: { return TypeAnnotation(TypePrimitive::String); } case Gringo::SymbolType::Fun: { map> fnGroups; for(const Gringo::Symbol& row : symbols) { fnGroups[row.name().c_str()].push_back(row); } TypeAnnotation resultT; resultT.__operands.reserve(fnGroups.size()); resultT.bindings.reserve(fnGroups.size()); for(const auto& group : fnGroups) { if(!group.second.size()) continue; TypeAnnotation variantT = collapseFnGroup(group.second); Gringo::Symbol symbolAny = group.second.front(); string variantName = symbolAny.name().c_str(); resultT.fields.push_back(variantName); resultT.__operands.push_back(variantT); } resultT.__operator = TypeOperator::VARIANT; // if(resultT.__operands.size() == 1) { // return resultT.__operands.front(); // } return resultT; } case Gringo::SymbolType::Inf: case Gringo::SymbolType::Special: case Gringo::SymbolType::Sup: { break; } } assert(false); return TypeAnnotation(); } ExpandedType dereferenceSlaveType(ExpandedType t, const TranscendLayer* transcend) { assert(t->__operator == TypeOperator::SLAVE); const string& domain = t->__valueCustom; StaticModel model = transcend->query(domain); if(!model.size()) return ExpandedType(TypeAnnotation()); std::list symbols; for(auto row : model) { symbols.push_back(row.second); } return ExpandedType(collapseFnGroup(symbols)); } Expression representTransExpression(const Gringo::Symbol& atom, ExpandedType schemaT, TranscendLayer* transcend) { switch(schemaT->__operator) { case TypeOperator::NONE: { switch(schemaT->__value) { case TypePrimitive::I8: case TypePrimitive::I32: case TypePrimitive::I64: case TypePrimitive::Num: case TypePrimitive::Int: { return Expression(Atom(atom.num())); } case TypePrimitive::String: { return Expression(Atom(atom.string().c_str())); } case TypePrimitive::Invalid: case TypePrimitive::Bool: case TypePrimitive::Float: { assert(false); return Expression(); } } break; } case TypeOperator::SLAVE: { ExpandedType contentT = dereferenceSlaveType(schemaT, transcend); return representTransExpression(atom, contentT, transcend); } case TypeOperator::VARIANT: { map dictVariants; for(size_t variantId = 0; variantId < schemaT->fields.size(); ++variantId) { dictVariants.emplace(schemaT->fields.at(variantId), variantId); } string predicateName = atom.name().c_str(); assert(dictVariants.count(predicateName)); size_t predicateId = dictVariants.at(predicateName); Expression result(Operator::VARIANT,{}); result.op = Operator::VARIANT; result.setValueDouble(predicateId); if(!schemaT->__operands.size()) return result; ExpandedType contentT = schemaT->__operands.at(predicateId).__operator == TypeOperator::SLAVE ? dereferenceSlaveType(ExpandedType(schemaT->__operands.at(predicateId)), transcend) : ExpandedType(schemaT->__operands.at(predicateId)); //edge case, content's type is LIST_NAMED: if (contentT->__operator == TypeOperator::LIST_NAMED) { result.operands.push_back(representTransExpression(atom, contentT, transcend)); } else if(!contentT->isValid()) { return result; } else { assert(atom.args().size); result.operands.push_back(representTransExpression(atom.args()[0], contentT, transcend)); } return result; } case TypeOperator::LIST_NAMED: { const Gringo::SymSpan& operandsRaw = atom.args(); size_t opCount = operandsRaw.size; assert(opCount == schemaT->__operands.size()); size_t operandId = 0; std::vector operands; operands.reserve(opCount); for(const TypeAnnotation operandT : schemaT->__operands) { operands.push_back(representTransExpression(operandsRaw[operandId], ExpandedType(operandT), transcend)); ++operandId; } Expression result(Operator::LIST_NAMED,{}); result.operands = operands; result.type = schemaT; return result; } case TypeOperator::LIST: case TypeOperator::CALL: case TypeOperator::CUSTOM: case TypeOperator::ACCESS: case TypeOperator::LINK: { assert(false); return Expression(); } } assert(false); return Expression(); } } } //end of xreate namespace \ No newline at end of file diff --git a/cpp/src/analysis/interpretation.h b/cpp/src/analysis/interpretation.h index 8a806a0..7716eb8 100644 --- a/cpp/src/analysis/interpretation.h +++ b/cpp/src/analysis/interpretation.h @@ -1,31 +1,31 @@ /* * 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 * Created on June 25, 2018, 3:24 PM * * \file interpretation.h * \brief interpretation */ #ifndef INTERPRETATION_H #define INTERPRETATION_H #include "transcendlayer.h" namespace xreate{ namespace interpretation{ TypeAnnotation collapseColumn(const std::list& symbols); ExpandedType dereferenceSlaveType(ExpandedType t, const TranscendLayer* transcend); - Expression representTransExpression(const Gringo::Symbol& atom, ExpandedType schemaT, TranscendLayer* transcend); +std::list generateAllInstancesInDomain2(const ExpandedType& domainT); } } #endif /* INTERPRETATION_H */ diff --git a/cpp/src/analysis/typeinference.cpp b/cpp/src/analysis/typeinference.cpp index 8d3992c..379739c 100644 --- a/cpp/src/analysis/typeinference.cpp +++ b/cpp/src/analysis/typeinference.cpp @@ -1,185 +1,79 @@ /* 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/. * * typeinference.cpp * * Author: pgess * Created on April 16, 2017, 10:13 AM */ /** * \file typeinference.h * \brief Type inference analysis */ #include "typeinference.h" #include "llvmlayer.h" #include "llvm/IR/Function.h" #include "llvm/IR/DerivedTypes.h" #include "transcendlayer.h" using namespace std; namespace xreate{ namespace typeinference{ //TODO type conversion: //a) automatically expand types int -> bigger int; int -> floating //b) detect exact type of `num` based on max used numeral / function type //c) warning if need to truncate (allow/dissalow based on annotations) llvm::Value* doAutomaticTypeConversion(llvm::Value* source, llvm::Type* tyTarget, llvm::IRBuilder<>& builder) { if(tyTarget->isIntegerTy() && source->getType()->isIntegerTy()) { llvm::IntegerType* tyTargetInt = llvm::dyn_cast(tyTarget); llvm::IntegerType* tySourceInt = llvm::dyn_cast(source->getType()); if(tyTargetInt->getBitWidth() < tySourceInt->getBitWidth()) { return builder.CreateCast(llvm::Instruction::Trunc, source, tyTarget); } if(tyTargetInt->getBitWidth() > tySourceInt->getBitWidth()) { return builder.CreateCast(llvm::Instruction::SExt, source, tyTarget); } } if(source->getType()->isIntegerTy() && tyTarget->isFloatingPointTy()) { return builder.CreateCast(llvm::Instruction::SIToFP, source, tyTarget); } return source; } ExpandedType getType(const Expression& expression, const AST& ast) { if(expression.type.isValid()) { return ast.expandType(expression.type); } if(expression.__state == Expression::IDENT) { Symbol s = Attachments::get(expression); return getType(CodeScope::getDefinition(s), ast); } if(Attachments::exists(expression)) { return Attachments::get(expression); } if(expression.__state == Expression::NUMBER) { return ExpandedType(TypeAnnotation(TypePrimitive::I32)); } assert(false && "Type can't be determined for an expression"); } -TypeAnnotation collapseColumn(const std::list& symbols); - -TypeAnnotation -collapseFnGroup(const std::list& symbols) { - Gringo::Symbol symbolAny = symbols.front(); - size_t operandsCount = symbolAny.args().size; - - TypeAnnotation resultT; - resultT.__operands.reserve(operandsCount); - - for(size_t operandId = 0; operandId < operandsCount; ++operandId) { - std::list column; - - for(const Gringo::Symbol& row : symbols) { - column.push_back(row.args()[operandId]); - } - - TypeAnnotation operandT = collapseColumn(column); - resultT.__operands.push_back(operandT); - } - - if(resultT.__operands.size() == 1) { - return resultT.__operands.front(); - } - - if(resultT.__operands.size() > 1) { - resultT.__operator = TypeOperator::LIST_NAMED; - return resultT; - } - - return resultT; -} - -TypeAnnotation -collapseColumn(const std::list& symbols) { - TypeAnnotation resultT; - if(!symbols.size()) return resultT; - - Gringo::Symbol symbolAny = symbols.front(); - - switch(symbolAny.type()) { - case Gringo::SymbolType::Num: - { - return TypeAnnotation(TypePrimitive::Num); - } - - case Gringo::SymbolType::Str: - { - return TypeAnnotation(TypePrimitive::String); - } - - case Gringo::SymbolType::Fun: - { - map> fnGroups; - - for(const Gringo::Symbol& row : symbols) { - fnGroups[row.name().c_str()].push_back(row); - } - - TypeAnnotation resultT; - resultT.__operands.reserve(fnGroups.size()); - resultT.bindings.reserve(fnGroups.size()); - - for(const auto& group : fnGroups) { - if(!group.second.size()) continue; - - TypeAnnotation variantT = collapseFnGroup(group.second); - Gringo::Symbol symbolAny = group.second.front(); - string variantName = symbolAny.name().c_str(); - resultT.fields.push_back(variantName); - resultT.__operands.push_back(variantT); - } - - resultT.__operator = TypeOperator::VARIANT; - if(resultT.__operands.size() == 1) { - return resultT.__operands.front(); - } - return resultT; - } - - case Gringo::SymbolType::Inf: - case Gringo::SymbolType::Special: - case Gringo::SymbolType::Sup: - { - break; - } - } - - assert(false); - return TypeAnnotation(); -} - -ExpandedType -dereferenceSlaveType(ExpandedType t, const TranscendLayer* transcend) { - assert(t->__operator == TypeOperator::SLAVE); - const string& domain = t->__valueCustom; - StaticModel model = transcend->query(domain); - if(!model.size()) return ExpandedType(TypeAnnotation()); - - std::list symbols; - for(auto row : model) { - symbols.push_back(row.second); - } - return ExpandedType(collapseFnGroup(symbols)); -} - } } //end of namespace xreate::typeinference diff --git a/cpp/src/analysis/typeinference.h b/cpp/src/analysis/typeinference.h index 500fc17..df6ce78 100644 --- a/cpp/src/analysis/typeinference.h +++ b/cpp/src/analysis/typeinference.h @@ -1,37 +1,31 @@ /* 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: typeinference.h * Author: pgess * * Created on April 16, 2017, 10:17 AM */ #ifndef TYPEINFERENCE_H #define TYPEINFERENCE_H #include "ast.h" #include "llvm/IR/IRBuilder.h" namespace llvm{ class Value; class Type; }; -namespace xreate{ -class TranscendLayer; -}; - namespace xreate{ namespace typeinference{ llvm::Value* doAutomaticTypeConversion(llvm::Value* source, llvm::Type* tyTarget, llvm::IRBuilder<>& builder); ExpandedType getType(const Expression& expression, const AST& ast); -ExpandedType dereferenceSlaveType(ExpandedType t, const TranscendLayer* transcend); - } }//namespace xreate::typeinference #endif /* TYPEINFERENCE_H */ diff --git a/cpp/src/attachments.h b/cpp/src/attachments.h index 3b82d43..a9bc42b 100644 --- a/cpp/src/attachments.h +++ b/cpp/src/attachments.h @@ -1,202 +1,179 @@ /* 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 (next vacant id - 13); + // static const unsigned int key (next vacant id - 12); // Defined attachments: //----------------------------------------------------- // 1 containers::Implementation // 3 interpretation::InterpretationData // 5 interpretation::FunctionInterpretationData // 6 VariableVersion // 7 IdentifierSymbol // 8 versions::VersionImposedDependency // 9 SymbolAlias // 11 TypeInferred -// 12 LateBindingT }; 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; - virtual void __update(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); } - template - void update(const Id& object, Data data){ - unsigned int id = AttachmentsId::getId(object); - - __update(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); } - virtual void __update(const unsigned int id, Data data){ - assert(__data.count(id)); - __data.at(id) = data; - } - 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 update(const Id& object, Data data){ - assert(AttachmentsDict::key < __storage.size()); - assert(__storage.at(AttachmentsDict::key)); - - IAttachmentsContainer>* self = reinterpret_cast>*>(__storage.at(AttachmentsDict::key)); - self->update(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/latereasoning.cpp b/cpp/src/aux/latereasoning.cpp index 8dc3366..c70ef88 100644 --- a/cpp/src/aux/latereasoning.cpp +++ b/cpp/src/aux/latereasoning.cpp @@ -1,40 +1,57 @@ /* * 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 * Created on June 7, 2018, 6:01 PM * * \file latereasoning.cpp * \brief Late reasoninf support */ #include "aux/latereasoning.h" +#include "analysis/interpretation.h" #include "ast.h" -namespace xreate {namespace latereasoning { +using namespace std; -boost::optional -LateAnnotation::select(const std::list& keys) const { - for(const auto& entry : guardedSymbols) { - const std::list& keysExpected = entry.first; +namespace xreate{ +namespace latereasoning{ + +LateAnnotation::LateAnnotation(const Gringo::Symbol& symbolStatic) { + guardedContent.push_back(pair, Gringo::Symbol>({}, symbolStatic)); +} - auto keysIt = keys.begin(); +boost::optional +LateAnnotation::select(const std::list& keys, AST* root, TranscendLayer* transcend) const { + for(const auto& entry : guardedContent) { + const std::list& guardsExpected = entry.first; + auto keyPSIt = guardKeys.begin(); + auto keyActualIt = keys.begin(); bool result = true; - for(const Expression& keyExpected : keysExpected) { - if(!(keyExpected == *keysIt)) { + for(const Gringo::Symbol& guardExpectedGS : guardsExpected) { + auto keyS = transcend->unpack(*keyPSIt); + const ExpandedType& keyT = root->getType(CodeScope::getDefinition(keyS)); + const ExpandedType& keyTPlain = keyT->__operator == TypeOperator::SLAVE ? + interpretation::dereferenceSlaveType(keyT, transcend) + : keyT; + Expression guardExpectedE = interpretation::representTransExpression( + guardExpectedGS, keyTPlain, transcend); + if(!(guardExpectedE == *keyActualIt)) { result = false; break; } - ++keysIt; + ++keyActualIt; + ++keyPSIt; } if(!result) continue; return entry.second; } return boost::none; } -}} +} +} diff --git a/cpp/src/aux/latereasoning.h b/cpp/src/aux/latereasoning.h index 5eb2f21..a20dbe1 100644 --- a/cpp/src/aux/latereasoning.h +++ b/cpp/src/aux/latereasoning.h @@ -1,113 +1,84 @@ /* * 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 latereasoning.h * \brief Late reasoning support * * Author: pgess * * Created on June 2, 2018, 1:08 PM */ #ifndef LATEREASONING_H #define LATEREASONING_H #include "transcendlayer.h" -namespace xreate { - struct LateBindingT; - - template<> - struct AttachmentsDict{ - typedef Expression Data; - static const unsigned int key = 12; - }; -} - namespace xreate{ namespace latereasoning{ struct LateAnnotation{ - std::list, Gringo::Symbol>> guardedSymbols; - boost::optional select(const std::list& keys) const; + LateAnnotation(){} + LateAnnotation(const Gringo::Symbol& symbolStatic); + std::list, Gringo::Symbol>> guardedContent; + std::list guardKeys; + boost::optional select(const std::list& keys, AST* root, TranscendLayer* transcend) const; }; struct LateAnnotationsGroup{ - std::unordered_map annotations; - std::unordered_map> bindings; + std::unordered_map annotations; }; -//DEBT implement querying as a view/joining iterators without actual data copying -//DEBT how to implement late model RESET(invalidate all child models) +typedef std::map LateModel; + template class LateReasoningTranscendDecorator: public Parent{ public: - StaticModel queryLate(const std::string& alias, const SymbolNode& symbol) const{ - StaticModel result; - if(!__modelLate.count(alias)) return StaticModel(); - - const LateAnnotationsGroup& group = __modelLate.at(alias); - assert(group.bindings.count(symbol)); - const std::list& bindings = group.bindings.at(symbol); - std::list&& keys = findKeys(bindings); - - const LateAnnotation& annLate = group.annotations.at(symbol); - auto ann = annLate.select(keys); - if(ann){ - result.emplace(std::make_pair(alias, *ann)); - } + const LateAnnotationsGroup& queryLate(const std::string& alias) const{ + static LateAnnotationsGroup groupInvalid; + if(!__modelLate.count(alias)) return groupInvalid; - return result; + return __modelLate.at(alias); } protected: virtual bool processSolution(Gringo::Model const &model) override{ const std::string& atomLateStatement = "late"; for(const Gringo::Symbol& atom: model.atoms(clingo_show_type_atoms)){ std::string atomName(atom.name().c_str()); - SymbolPacked aaaa; if(atomName == atomLateStatement){ - //late atom's format: (Symbol, (tuple of keys), (tuple of values), late-annotation) - auto atomLate = TranscendLayer::parse, std::list, Gringo::Symbol>(atom); + //late atom's format: (Target, (tuple of keys), (tuple of values), late-annotation) + auto atomLate = TranscendLayer::parse, std::list, Gringo::Symbol>(atom); const std::string& atomAlias = std::get<3>(atomLate).name().c_str(); addLateAtom(atomAlias, std::get<0>(atomLate), std::get<3>(atomLate), std::get<1>(atomLate), std::get<2>(atomLate)); } } return Parent::processSolution(model); } private: std::map __modelLate; - void addLateAtom(const std::string& alias, const SymbolNode& symbol, - const Gringo::Symbol& atom, const std::list& guardKeys, - const std::list& guardBindings){ + void addLateAtom(const std::string& alias, const Gringo::Symbol& annId, + const Gringo::Symbol& content, const std::list& guardKeys, + const std::list& guardValues){ LateAnnotationsGroup& group = __modelLate[alias]; - if(!group.bindings.count(symbol)){ - group.bindings.emplace(symbol, guardKeys); - } - - LateAnnotation& annotation = group.annotations[symbol]; - annotation.guardedSymbols.push_back(std::make_pair(guardBindings, atom)); - } - std::list findKeys(const std::list& keys) const{ - std::list result; - std::transform(keys.begin(), keys.end(), std::inserter(result, result.end()), [this](const SymbolPacked & key){ - return Attachments::get(Parent::unpack(key)); - }); - - return result; + LateAnnotation& annotation = group.annotations[annId]; + if (annotation.guardedContent.empty()){ + annotation.guardKeys = guardKeys; + } + annotation.guardedContent.push_back(std::make_pair(guardValues, content)); } }; }} // end of xreate::latereasoning #endif /* LATEREASONING_H */ diff --git a/cpp/src/aux/transcend-decorators.h b/cpp/src/aux/transcend-decorators.h index 77a04d6..321b66c 100644 --- a/cpp/src/aux/transcend-decorators.h +++ b/cpp/src/aux/transcend-decorators.h @@ -1,27 +1,34 @@ /* * 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 * Created on June 7, 2018, 6:47 PM * * \file transcend-decorators.h * \brief TranscendLevel decorators management */ #include "transcendlayer.h" #include "aux/latereasoning.h" #ifndef TRANSCEND_DECORATORS_H #define TRANSCEND_DECORATORS_H namespace xreate { typedef latereasoning::LateReasoningTranscendDecorator DefaultTranscendLayerImpl; + + struct LateReasoningTranscendDecoratorTag; + + template<> + struct DecoratorsDict{ + typedef latereasoning::LateReasoningTranscendDecorator result; +}; } #endif /* TRANSCEND_DECORATORS_H */ diff --git a/cpp/src/aux/xreatemanager-decorators.cpp b/cpp/src/aux/xreatemanager-decorators.cpp index 2b3a9ba..40bf519 100644 --- a/cpp/src/aux/xreatemanager-decorators.cpp +++ b/cpp/src/aux/xreatemanager-decorators.cpp @@ -1,72 +1,74 @@ /* 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/cfapass.h" #include "pass/dfapass.h" #include "pass/interpretationpass.h" #include "pass/versionspass.h" -namespace xreate { +namespace xreate{ void -XreateManagerDecoratorBase::prepareCode(std::string&& code){ - grammar::main::Scanner scanner(reinterpret_cast(code.c_str()), code.size()); +XreateManagerDecoratorBase::initPasses() { } + +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){ +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(){ +XreateManagerDecoratorBase::analyse() { CompilePass::prepareQueries(transcend); transcend->run(); } void -XreateManagerDecoratorFull::initPasses(){ +XreateManagerDecoratorFull::initPasses() { cfa::CFAPass* passCFG = new cfa::CFAPass(this); - //TODO is it really DFGPass needs CFGpass? - registerPass(new dfa::DFAPass(this), PassId::DFAPass, passCFG); + registerPass(new dfa::DFAPass(this), PassId::DFAPass); registerPass(passCFG, PassId::CFAPass); - this->registerPass(new interpretation::InterpretationPass(this), PassId::InterpretationPass); - this->registerPass(new versions::VersionsPass(this), PassId::VersionsPass); + registerPass(new interpretation::InterpretationPass(this), PassId::InterpretationPass); + 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/aux/xreatemanager-decorators.h b/cpp/src/aux/xreatemanager-decorators.h index 9dd7a3f..d1cfe71 100644 --- a/cpp/src/aux/xreatemanager-decorators.h +++ b/cpp/src/aux/xreatemanager-decorators.h @@ -1,36 +1,38 @@ /* 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: xreatemanager-decorators.h * Author: pgess * * Created on July 16, 2017, 4:37 PM */ #ifndef XREATEMANAGER_DECORATORS_H #define XREATEMANAGER_DECORATORS_H #include "xreatemanager.h" -namespace xreate { - +namespace xreate{ + class XreateManagerDecoratorBase: public details::tier2::XreateManager{ public: - void analyse(); - + virtual void initPasses() override; + virtual void analyse(); + virtual void* run(){}; + public: virtual void prepareCode(std::string&& code); virtual void prepareCode(FILE* code); }; -class XreateManagerDecoratorFull: public XreateManagerDecoratorBase { +class XreateManagerDecoratorFull: public XreateManagerDecoratorBase{ public: - void initPasses() override; + virtual void initPasses() override; void* run(); }; } #endif /* XREATEMANAGER_DECORATORS_H */ diff --git a/cpp/src/compilation/interpretation-instructions.cpp b/cpp/src/compilation/interpretation-instructions.cpp index 97c2634..4b0da50 100644 --- a/cpp/src/compilation/interpretation-instructions.cpp +++ b/cpp/src/compilation/interpretation-instructions.cpp @@ -1,167 +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/. */ /* * Author: pgess * Created on June 15, 2018, 5:32 PM * */ #include "compilation/interpretation-instructions.h" -#include "analysis/typeinference.h" +#include "analysis/interpretation.h" #include "transcendlayer.h" #include "targets.h" using namespace std; namespace xreate{ namespace interpretation{ -Expression -IntrinsicQueryInstruction::representTransExpression(const Gringo::Symbol& atom, ExpandedType schemaT) { - TranscendLayer* transcend = static_cast (__scope->function->man)->pass->man->transcend; - - switch(schemaT->__operator) { - case TypeOperator::NONE: - { - switch(schemaT->__value) { - case TypePrimitive::I8: - case TypePrimitive::I32: - case TypePrimitive::I64: - case TypePrimitive::Num: - case TypePrimitive::Int: - { - return Expression(Atom(atom.num())); - } - - case TypePrimitive::String: - { - return Expression(Atom(atom.string().c_str())); - } - - case TypePrimitive::Invalid: - case TypePrimitive::Bool: - case TypePrimitive::Float: - { - assert(false); - return Expression(); - } - } - break; - } - - case TypeOperator::SLAVE: - { - ExpandedType contentT = typeinference::dereferenceSlaveType(schemaT, transcend); - return representTransExpression(atom, contentT); - } - - case TypeOperator::VARIANT: - { - map dictVariants; - for(size_t variantId = 0; variantId < schemaT->fields.size(); ++variantId) { - dictVariants.emplace(schemaT->fields.at(variantId), variantId); - } - - string predicateName = atom.name().c_str(); - assert(dictVariants.count(predicateName)); - - size_t predicateId = dictVariants.at(predicateName); - Expression result(Operator::VARIANT,{}); - result.op = Operator::VARIANT; - result.setValueDouble(predicateId); - - if(!schemaT->__operands.size()) return result; - ExpandedType contentT = schemaT->__operands.at(0).__operator == TypeOperator::SLAVE - ? typeinference::dereferenceSlaveType(ExpandedType(schemaT->__operands.at(0)), transcend) - : ExpandedType(schemaT->__operands.at(0)); - - //edge case, content's type is LIST_NAMED: - if (contentT->__operator == TypeOperator::LIST_NAMED) { - result.operands.push_back(representTransExpression(atom, contentT)); - - } else { - assert(atom.args().size); - result.operands.push_back(representTransExpression(atom.args()[0], contentT)); - } - - return result; - } - - case TypeOperator::LIST_NAMED: - { - const Gringo::SymSpan& operandsRaw = atom.args(); - size_t opCount = operandsRaw.size; - assert(opCount == schemaT->__operands.size()); - - size_t operandId = 0; - std::vector operands; - operands.reserve(opCount); - for(const TypeAnnotation operandT : schemaT->__operands) { - operands.push_back(representTransExpression(operandsRaw[operandId], ExpandedType(operandT))); - ++operandId; - } - - Expression result(Operator::LIST_NAMED,{}); - result.operands = operands; - result.type = schemaT; - return result; - } - - case TypeOperator::LIST: - case TypeOperator::CALL: - case TypeOperator::CUSTOM: - case TypeOperator::ACCESS: - case TypeOperator::LINK: - { - assert(false); - return Expression(); - } - } - - assert(false); - return Expression(); -} - Expression IntrinsicQueryInstruction::process(const Expression& expression) { AST* ast = static_cast (__scope->function->man)->ast; TranscendLayer* transcend = static_cast (__scope->function->man)->pass->man->transcend; InterpretationFunction* function = static_cast (__scope->function); ExpandedType targetT = ast->expandType(expression.type); assert(expression.operands.size() == 1); assert(expression.operands.front().__state == Expression::STRING); assert(targetT->__operator == TypeOperator::LIST); std::string namePredicate = expression.operands.front().getValueString(); StaticModel model = (static_cast (function->man))->pass->man->transcend->query(namePredicate); Expression result(Operator::LIST,{}); result.operands.reserve(model.size()); ExpandedType elementT = targetT->__operands.at(0).__operator == TypeOperator::SLAVE - ? typeinference::dereferenceSlaveType(ExpandedType(targetT->__operands.at(0)), transcend) + ? dereferenceSlaveType(ExpandedType(targetT->__operands.at(0)), transcend) : ExpandedType(targetT->__operands.at(0)); if(model.size()) { if (elementT->__operator == TypeOperator::LIST_NAMED) { //edge case, content's type is LIST_NAMED: for(const auto& row : model) { - result.operands.push_back(representTransExpression(row.second, elementT)); + result.operands.push_back(representTransExpression(row.second, elementT, transcend)); } } else { for (const auto& row : model) { assert(row.second.args().size); - result.operands.push_back(representTransExpression(row.second.args()[0], elementT)); + result.operands.push_back(representTransExpression(row.second.args()[0], elementT, transcend)); } } } return result; } } } //end of xreate::interpretation \ No newline at end of file diff --git a/cpp/src/compilation/interpretation-instructions.h b/cpp/src/compilation/interpretation-instructions.h index 2ff6c8c..9f1c0a5 100644 --- a/cpp/src/compilation/interpretation-instructions.h +++ b/cpp/src/compilation/interpretation-instructions.h @@ -1,39 +1,38 @@ /* * 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 * Created on June 15, 2018, 5:28 PM * * \file interpretation-instructions.h * \brief Additional intepretation statements */ #ifndef INTERPRETATION_INSTRUCTIONS_H #define INTERPRETATION_INSTRUCTIONS_H #include "compilation/targetinterpretation.h" #include "ast.h" namespace xreate{ namespace interpretation{ class IntrinsicQueryInstruction{ public: IntrinsicQueryInstruction(InterpretationScope* scope): __scope(scope){ } Expression process(const Expression& expression); private: InterpretationScope* __scope; - Expression representTransExpression(const Gringo::Symbol& atom, ExpandedType schemaT); }; } } //end of xreate::interpretation #endif /* INTERPRETATION_INSTRUCTIONS_H */ diff --git a/cpp/src/compilation/latereasoning.cpp b/cpp/src/compilation/latereasoning.cpp index e62201f..34e8882 100644 --- a/cpp/src/compilation/latereasoning.cpp +++ b/cpp/src/compilation/latereasoning.cpp @@ -1,79 +1,166 @@ /* * 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/. * * latereasoning.cpp * * Author: pgess * Created on May 26, 2018, 3:54 PM */ #include "compilation/latereasoning.h" -#include "aux/latereasoning.h" +//#include "aux/latereasoning.h" #include "compilation/scopedecorators.h" -#include "analysis/typeinference.h" +#include "analysis/interpretation.h" +#include "compilation/targetinterpretation.h" + #include +using namespace xreate::interpretation; using namespace xreate::compilation; using namespace std; -namespace xreate{ namespace latereasoning { +namespace xreate{ +namespace latereasoning{ + +#define HINT(x) (hint.empty()? x : hint) llvm::Value* -LateReasoningCompiler::compile(const Expression& expr, const std::string& identHint){ - #define HINT(x) (identHint.empty()? x : identHint) +LateReasoningCompiler::processSwitchLateStatement(const Expression& expr, const std::string& hint) { + AST* root = __context.pass->man->root; + LLVMLayer* llvm = __context.pass->man->llvm; - LLVMLayer* llvm = context.pass->man->llvm; - compilation::ICodeScopeUnit* scope = context.scope; - AST* root = context.pass->man->root; - llvm::IRBuilder<>& builder = llvm->builder; - compilation::IFunctionUnit* function = context.function; - llvm::Type* typI8= llvm::Type::getInt8Ty(llvm->llvmContext); CodeScope* scopeBody = expr.blocks.front(); Symbol guardS = Symbol{scopeBody->getSymbol(expr.bindings.front()), scopeBody}; + const ExpandedType& guardT = root->getType(expr.operands.at(0)); + const ExpandedType& guardTPlain = interpretation::dereferenceSlaveType(guardT, __context.pass->man->transcend); + + llvm::Value * guardRaw = __context.scope->process(expr.operands.at(0)); + llvm::Type* instructionT = llvm->toLLVMType(root->getType(expr)); - const ExpandedType& conditionT = root->getType(expr.operands.at(0)); - const ExpandedType& conditionTPlain = typeinference::dereferenceSlaveType(conditionT, context.pass->man->transcend); - const int countVariants = conditionTPlain->fields.size(); - assert(countVariants); + return compileExpand(guardS, guardRaw, guardTPlain, instructionT, hint, [this, scopeBody]() { + ICodeScopeUnit* bodyUnit = this->__context.function->getScopeUnit(scopeBody); + bodyUnit->reset(); + return this->__context.function->getScopeUnit(scopeBody)->compile(); + }); +} - llvm::Value * conditionRaw = scope->process(expr.operands.at(0)); - llvm::Value* variantRaw = builder.CreateExtractValue(conditionRaw, llvm::ArrayRef({0})); - llvm::SwitchInst * instructionSwitch = builder.CreateSwitch(variantRaw, nullptr, countVariants); +llvm::Value* +LateReasoningCompiler::compileAutoExpand(const LateAnnotation& annotation, + llvm::Type* resultT, + const std::string& hint, + Handler handler) { + TranscendLayer* transcend = __context.pass->man->transcend; + InterpretationFunction* functionI12n = + dynamic_cast (__scopeI12n->function); + AST* root = __context.pass->man->root; - llvm::BasicBlock *blockEpilog = llvm::BasicBlock::Create(llvm->llvmContext, "switchLateAfter", function->raw); - builder.SetInsertPoint(blockEpilog); - llvm::Type* exprSwitchType = llvm->toLLVMType(root->getType(expr)); - llvm::PHINode *ret = builder.CreatePHI(exprSwitchType, countVariants, HINT("switchLate")); - llvm::BasicBlock* blockDefault = nullptr; + const std::list& guardKeys = annotation.guardKeys; + std::list notfound_guardKeys; + for(const SymbolPacked key : guardKeys) { + const Symbol& keyS = transcend->unpack(key); + InterpretationScope* keyScope = functionI12n->getScope(keyS.scope); + if (!keyScope->isBindingDefined(keyS.identifier)) { + notfound_guardKeys.push_back(keyS); + } + } + + typedef std::function < llvm::Value * () > Compiler; + Compiler programInit([handler, annotation, this]() { + std::list&& values = findKeys(annotation.guardKeys); + auto answer = annotation.select(values, __context.pass->man->root, __context.pass->man->transcend); + assert(answer); + return handler(*answer); + }); + + Compiler aggregate = std::accumulate(notfound_guardKeys.begin(), notfound_guardKeys.end(), + programInit, + [this, root, transcend, &resultT, hint](Compiler program, const Symbol & key) { + const ExpandedType& keyT = root->getType(CodeScope::getDefinition(key)); + const ExpandedType& keyTPlain = keyT->__operator == TypeOperator::SLAVE? + interpretation::dereferenceSlaveType(keyT, transcend) + : keyT; + + return Compiler([this, key, keyTPlain, resultT, hint, program](){ + llvm::Value * keyRaw = __context.scope->processSymbol(key); + return compileExpand(key, keyRaw, keyTPlain, resultT, hint, program); + }); + } + ); + + return aggregate(); +} + +llvm::Value* +LateReasoningCompiler::compileExpand(const Symbol& keyS, + llvm::Value* keyRaw, + const ExpandedType& domainT, + llvm::Type* resultT, + const std::string& hint, + CompilerHandler compilerBody) { - bool flagFirstPass = true; - for (int variantId = 0; variantId(guardS, Expression(Operator::CALL, {Expression(Atom(string(conditionTPlain->fields.at(variantId))))})) - : Attachments::update(guardS, Expression(Operator::CALL, {Expression(Atom(string(conditionTPlain->fields.at(variantId))))})); - flagFirstPass = false; + assert(domainT->__operator == TypeOperator::VARIANT); + std::list domInstancesList = generateAllInstancesInDomain2(domainT); + std::vector domInstances(domInstancesList.begin(), domInstancesList.end()); + const int countInstances = domInstances.size(); + assert(countInstances); + LLVMLayer* llvm = __context.pass->man->llvm; + llvm::IRBuilder<>& builder = llvm->builder; + compilation::IFunctionUnit* function = __context.function; + llvm::Type* typI8 = llvm::Type::getInt8Ty(llvm->llvmContext); + InterpretationFunction* functionI12n = dynamic_cast (__scopeI12n->function); + + llvm::Value* keyVariantRaw = builder.CreateExtractValue(keyRaw, llvm::ArrayRef({0})); + llvm::SwitchInst* instructionSwitch = builder.CreateSwitch(keyVariantRaw, nullptr, countInstances); + + llvm::BasicBlock *blockEpilog = llvm::BasicBlock::Create( + llvm->llvmContext, "epilog", function->raw); + + builder.SetInsertPoint(blockEpilog); + llvm::PHINode *ret = builder.CreatePHI(resultT, countInstances, HINT("reverse")); + llvm::BasicBlock* blockDefault = nullptr; + + for (int instanceId = 0; instanceId < countInstances; ++instanceId) { llvm::BasicBlock *blockCase = llvm::BasicBlock::Create( llvm->llvmContext, - "case" + std::to_string(variantId), + "case" + std::to_string(instanceId), function->raw); - if(variantId == 0) blockDefault = blockCase; + if(instanceId == 0) blockDefault = blockCase; builder.SetInsertPoint(blockCase); - auto scopeBody = Decorators::getInterface<>( - function->getScopeUnit(expr.blocks.back())); - scopeBody->reset(); - llvm::Value* resultCase = scopeBody->compile(); + //assign bindings + + const Expression& instanceE = domInstances.at(instanceId); + functionI12n->getScope(keyS.scope)->overrideBindings({ + {instanceE, keyS.identifier} + }); + + //invoke further compilation handler + llvm::Value* resultCase = compilerBody(); + ret->addIncoming(resultCase, builder.GetInsertBlock()); - instructionSwitch->addCase(llvm::dyn_cast(llvm::ConstantInt::get(typI8, variantId)), blockCase); + instructionSwitch->addCase(llvm::dyn_cast(llvm::ConstantInt::get(typI8, instanceId)), blockCase); builder.CreateBr(blockEpilog); } instructionSwitch->setDefaultDest(blockDefault); builder.SetInsertPoint(blockEpilog); return ret; } -}} \ No newline at end of file + +std::list +LateReasoningCompiler::findKeys(const std::list& keys) { + TranscendLayer* transcend = __context.pass->man->transcend; + std::list result; + + std::transform(keys.begin(), keys.end(), std::inserter(result, result.end()), + [this, transcend](const SymbolPacked & key) { + return __scopeI12n->processSymbol(transcend->unpack(key)); + }); + + return result; +} +} +} \ No newline at end of file diff --git a/cpp/src/compilation/latereasoning.h b/cpp/src/compilation/latereasoning.h index 84adc4f..a065fde 100644 --- a/cpp/src/compilation/latereasoning.h +++ b/cpp/src/compilation/latereasoning.h @@ -1,33 +1,68 @@ /* * 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: latereasoning.h * Author: pgess * * Created on May 26, 2018, 3:44 PM */ #ifndef CMPLLATEREASONING_H #define CMPLLATEREASONING_H #include "ast.h" +#include "aux/latereasoning.h" #include "pass/compilepass.h" #include "llvmlayer.h" +#include "transcendlayer.h" -namespace xreate{ namespace latereasoning { +namespace xreate{ +namespace interpretation{ +class InterpretationScope; +} +} + +namespace llvm{ +class Value; +} + +namespace xreate{ +namespace latereasoning{ + +typedef std::function CompilerHandler; +typedef std::function Handler; + +class LateReasoningCompiler{ +public: + LateReasoningCompiler(interpretation::InterpretationScope* scope, + compilation::Context ctx) + : __context(ctx), __scopeI12n(scope) {} + + llvm::Value* processSwitchLateStatement(const Expression& expr, + const std::string& identHint); + llvm::Value* compileAutoExpand(const LateAnnotation& annotation, + llvm::Type* resultT, + const std::string& hint, + Handler handler); -class LateReasoningCompiler { -public: - LateReasoningCompiler(compilation::Context ctx): context(ctx){} - llvm::Value* compile(const Expression& expr, const std::string& identHint); - private: - compilation::Context context; + compilation::Context __context; + interpretation::InterpretationScope* __scopeI12n; + + llvm::Value* compileExpand(const Symbol& keyS, + llvm::Value* keyRaw, + const ExpandedType& domainT, + llvm::Type* resultT, + const std::string& hint, + CompilerHandler compilerBody); + + std::list findKeys(const std::list& keys); }; -}} +} +} #endif /* CMPLLATEREASONING_H */ diff --git a/cpp/src/compilation/latex.cpp b/cpp/src/compilation/latex.cpp index 4386fe7..b853fd8 100644 --- a/cpp/src/compilation/latex.cpp +++ b/cpp/src/compilation/latex.cpp @@ -1,36 +1,36 @@ /* * 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 * Created on June 23, 2018, 4:33 PM * * \file latex.cpp * \brief latex */ #include "compilation/latex.h" #include "analysis/interpretation.h" #include "llvmlayer.h" namespace xreate{ namespace latex{ ExpandedType getSubjectDomain(const std::string& subject, LatexQuery* query){ std::list&& column = query->getSubjectDomain(subject); return ExpandedType(interpretation::collapseColumn(column)); } llvm::Value* -ExtraArgsCallStatement::operator() (std::vector&& args, const std::string& hintDecl) { +ExtraArgsFnInvocation::operator() (std::vector&& args, const std::string& hintDecl) { args.insert(args.end(), __argsLatex.begin(), __argsLatex.end()); return __parent->operator ()(std::move(args), hintDecl); } } } \ No newline at end of file diff --git a/cpp/src/compilation/latex.h b/cpp/src/compilation/latex.h index 8de19d2..e5c7fc1 100644 --- a/cpp/src/compilation/latex.h +++ b/cpp/src/compilation/latex.h @@ -1,128 +1,135 @@ /* * 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 * Created on June 23, 2018, 2:51 PM * * \file latex.h * \brief latex */ #ifndef LATEX_H #define LATEX_H +#include "compilation/latereasoning.h" #include "compilation/interpretation-instructions.h" #include "query/latex.h" #include "pass/compilepass.h" #include "analysis/interpretation.h" namespace xreate{ namespace latex{ ExpandedType getSubjectDomain(const std::string& subject, LatexQuery* query); /** \brief Latex(Late Context)-enabled decorator for IFunctionUnit * \extends IFunctionUnit */ template class LatexBruteFunctionDecorator: public Parent{ public: LatexBruteFunctionDecorator(ManagedFnPtr f, CompilePass* p) : Parent(f, p){ __query = reinterpret_cast (Parent::pass->man->transcend->getQuery(QueryId::LatexQuery)); } protected: std::vector prepareSignature(){ std::vector&& signature = Parent::prepareSignature(); const Demand& demand = __query->getFnDemand(Parent::function->getName()); signature.reserve(signature.size() + demand.size()); for(const std::string& subject: demand){ - llvm::Type* subjectTRaw = Parent::pass->man->llvm->toLLVMType( - getSubjectDomain(subject, __query)); + const ExpandedType& subjectT = getSubjectDomain(subject, __query); + Expression bindingE; + bindingE.type = subjectT; + std::string argCaption = std::string("latex_") + subject; + Parent::function->addBinding(Atom(std::string(argCaption)), std::move(bindingE)); + + llvm::Type* subjectTRaw = Parent::pass->man->llvm->toLLVMType(subjectT); signature.push_back(subjectTRaw); } return signature; } - llvm::Function::arg_iterator - prepareBindings(){ - llvm::Function::arg_iterator fargsI = Parent::prepareBindings(); - - const Demand& demand = __query->getFnDemand(Parent::function->getName()); - for(const std::string& subject: demand){ - std::string argTitle = std::string("latex_") + subject; - fargsI->setName(argTitle); - ++fargsI; - } - - return fargsI; - } - public: LatexQuery* __query; }; -class ExtraArgsCallStatement: public compilation::ICallStatement{ +class ExtraArgsFnInvocation: public compilation::IFnInvocation{ public: - ExtraArgsCallStatement(std::vector argsLatex, compilation::ICallStatement* parent) + ExtraArgsFnInvocation(std::vector argsLatex, compilation::IFnInvocation* parent) : __argsLatex(argsLatex), __parent(parent){ } llvm::Value* operator()(std::vector&& args, const std::string& hintDecl = ""); private: std::vector __argsLatex; - compilation::ICallStatement* __parent; + compilation::IFnInvocation* __parent; }; template class LatexBruteScopeDecorator: public Parent{ public: LatexBruteScopeDecorator(const CodeScope * const codeScope, compilation::IFunctionUnit* f, CompilePass* compilePass) : Parent(codeScope, f, compilePass){ } - compilation::ICallStatement* + compilation::IFnInvocation* findFunction(const Expression& opCall){ - compilation::ICallStatement* stmntCallParent = Parent::findFunction(opCall); + compilation::IFnInvocation* invocDefault = Parent::findFunction(opCall); const std::string& calleeName = opCall.getValueString(); LatexQuery* query = reinterpret_cast (Parent::pass->man->transcend->getQuery(QueryId::LatexQuery)); const Demand& fnCalleeDemand = query->getFnDemand(calleeName); - if(!fnCalleeDemand.size()) return stmntCallParent; + if(!fnCalleeDemand.size()) return invocDefault; //prepare latex arguments std::vector argsLatex; argsLatex.reserve(fnCalleeDemand.size()); for(const std::string& subject: fnCalleeDemand){ ExpandedType subjectT = getSubjectDomain(subject, query); - - Gringo::Symbol decision = query->getDecision(subject, Parent::scope); - const Expression& decisionE = interpretation::representTransExpression( - decision, subjectT, Parent::pass->man->transcend); - Attachments::put(decisionE, subjectT); - argsLatex.push_back(Parent::process(decisionE, subject)); + llvm::Type* subjectTRaw = Parent::pass->man->llvm->toLLVMType(subjectT); + const latereasoning::LateAnnotation& decision = query->getDecision(subject, Parent::scope); + + compilation::Context ctx{this, Parent::function, Parent::pass}; + interpretation::InterpretationScope* scopeIntrpr = + Parent::pass->targetInterpretation->transformContext(ctx); + latereasoning::LateReasoningCompiler* compiler + = new latereasoning::LateReasoningCompiler(scopeIntrpr, ctx); + + llvm::Value* subjectRaw = compiler->compileAutoExpand( + decision, + subjectTRaw, + subject, + [&](const Gringo::Symbol & decisionRaw){ + const Expression& decisionE = interpretation::representTransExpression( + decisionRaw.args()[2], subjectT, Parent::pass->man->transcend); + Attachments::put(decisionE, subjectT); + return Parent::process(decisionE, subject); + }); + + argsLatex.push_back(subjectRaw); } - return new ExtraArgsCallStatement(std::move(argsLatex), stmntCallParent); + return new ExtraArgsFnInvocation(std::move(argsLatex), invocDefault); } }; } } //end of namespace xreate::context #endif /* LATEX_H */ diff --git a/cpp/src/compilation/polymorph.cpp b/cpp/src/compilation/polymorph.cpp new file mode 100644 index 0000000..64bbeb9 --- /dev/null +++ b/cpp/src/compilation/polymorph.cpp @@ -0,0 +1,53 @@ +/* + * 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 + * Created on July 9, 2018, 6:04 PM + * + * \file polymorph.cpp + * \brief polymorph + */ + +#include "compilation/polymorph.h" +using namespace std; + +namespace xreate{ +namespace polymorph{ + +PolymorphFnInvocation::PolymorphFnInvocation(const latereasoning::LateAnnotation& selector, + std::list calleeSpecializations, + CompilePass* pass, + PolymorphQuery* query, + LLVMLayer* llvm, + latereasoning::LateReasoningCompiler* compiler) +: __selector(selector), __calleeSpecializations(calleeSpecializations), +__pass(pass), __query(query), __llvm(llvm), __compiler(compiler) { } + +llvm::Value* +PolymorphFnInvocation::operator()(std::vector&& args, const std::string& hintDecl) { + std::map dictSelectors; + for(ManagedFnPtr specialization : __calleeSpecializations) { + dictSelectors.emplace(specialization->guard, specialization); + } + + compilation::IFunctionUnit* specAny = __pass->getFunctionUnit(__calleeSpecializations.front()); + return __compiler->compileAutoExpand( + __selector, + specAny->prepareResult(), + hintDecl, + [this, &args, hintDecl, &dictSelectors](const Gringo::Symbol & selectorRaw) { + const Expression & selectorE = __query->getValue(selectorRaw); + assert(dictSelectors.count(selectorE) && "Inappropriate specialization guard"); + compilation::RawFnInvocation* invoc = new compilation::RawFnInvocation( + __pass->getFunctionUnit(dictSelectors.at(selectorE))->compile(), + __llvm); + + return invoc->operator()(move(args), hintDecl); + }); +} +} +} diff --git a/cpp/src/compilation/polymorph.h b/cpp/src/compilation/polymorph.h index 7088afe..e49d7bd 100644 --- a/cpp/src/compilation/polymorph.h +++ b/cpp/src/compilation/polymorph.h @@ -1,64 +1,95 @@ /* * 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: polymorphcompiler.h * Author: pgess * * Created on October 7, 2017 */ #ifndef POLYMORPHCOMPILER_H #define POLYMORPHCOMPILER_H #include "pass/compilepass.h" #include "query/polymorph.h" +#include "compilation/latereasoning.h" -namespace xreate { namespace polymorph { +namespace xreate{ +namespace polymorph{ + +typedef Expression Selector; + +class PolymorphFnInvocation: public compilation::IFnInvocation{ +public: + PolymorphFnInvocation(const latereasoning::LateAnnotation& selector, + std::list calleeSpecializations, + CompilePass* pass, + PolymorphQuery* query, + LLVMLayer* llvm, + latereasoning::LateReasoningCompiler* compiler); + + llvm::Value* operator()(std::vector&& args, const std::string& hintDecl = ""); + +private: + latereasoning::LateAnnotation __selector; + std::list __calleeSpecializations; + + CompilePass* __pass; + PolymorphQuery* __query; + LLVMLayer* __llvm; + latereasoning::LateReasoningCompiler* __compiler; +}; -typedef Expression Guard; - template class PolymorphCodeScopeUnit: public Parent{ public: - PolymorphCodeScopeUnit(const CodeScope* const codeScope, compilation::IFunctionUnit* f, CompilePass* compilePass) - : Parent(codeScope, f, compilePass) {} + + PolymorphCodeScopeUnit(const CodeScope * const codeScope, + compilation::IFunctionUnit* f, + CompilePass* compilePass) + : Parent(codeScope, f, compilePass){ } protected: - compilation::ICallStatement* findFunction(const Expression& opCall) override { - - //Check does invocation require guards + + compilation::IFnInvocation* + findFunction(const Expression& opCall) override{ +// //Check does invocation require guards satisfaction const std::string& nameCallee = opCall.getValueString(); - const std::list& specializations = Parent::pass->man->root->getFunctionSpecializations(nameCallee); - + const std::list& specializations = + Parent::pass->man->root->getFunctionSpecializations(nameCallee); + //Extern function - if (specializations.size() == 0){ + if(specializations.size() == 0){ return Parent::findFunction(opCall); } - + //No other specializations. Check if it has no guard - if (specializations.size() == 1){ - if (!specializations.front()->guard.isValid()) { + if(specializations.size() == 1){ + if(!specializations.front()->guard.isValid()){ return Parent::findFunction(opCall); } } - + //Several specializations - PolymorphQuery* query = dynamic_cast(Parent::pass->man->transcend->getQuery(QueryId::PolymorphQuery)); - const Expression& guardSelected = query->get(opCall); - - std::map indexSpecs; - for(ManagedFnPtr specialization: specializations){ - indexSpecs.emplace(specialization->guard, specialization); - } - - assert(indexSpecs.count(guardSelected) && "Can't find appropriate guard"); - return new compilation::CallStatementRaw(Parent::pass->getFunctionUnit(indexSpecs.at(guardSelected))->compile(), Parent::pass->man->llvm); + PolymorphQuery* query = dynamic_cast ( + Parent::pass->man->transcend->getQuery(QueryId::PolymorphQuery)); + const latereasoning::LateAnnotation& selector = query->get(opCall); + + compilation::Context ctx{this, Parent::function, Parent::pass}; + interpretation::InterpretationScope* scopeIntrpr = + Parent::pass->targetInterpretation->transformContext(ctx); + latereasoning::LateReasoningCompiler* compiler + = new latereasoning::LateReasoningCompiler(scopeIntrpr, ctx); + + return new PolymorphFnInvocation(selector, specializations, Parent::pass, + query, Parent::pass->man->llvm, compiler); } }; -} } //end of xreate::polymorph +} +} //end of xreate::polymorph #endif /* POLYMORPHCOMPILER_H */ diff --git a/cpp/src/compilation/targetinterpretation.cpp b/cpp/src/compilation/targetinterpretation.cpp index 1658d2f..9314a6c 100644 --- a/cpp/src/compilation/targetinterpretation.cpp +++ b/cpp/src/compilation/targetinterpretation.cpp @@ -1,593 +1,597 @@ /* 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 "compilation/interpretation-instructions.h" #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)); 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 SWITCH_LATE: { + latereasoning::LateReasoningCompiler compiler(this, context); + return compiler.processSwitchLateStatement(expression, ""); + } 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)); + boost::scoped_ptr statement(new RawFnInvocation(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"){ return IntrinsicQueryInstruction(this).process(expression); } else if(nameFunction=="query_scope"){ ScopePacked scopeId = man->transcend->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) * */ diff --git a/cpp/src/compilation/targetinterpretation.h b/cpp/src/compilation/targetinterpretation.h index ba03f34..ad9db20 100644 --- a/cpp/src/compilation/targetinterpretation.h +++ b/cpp/src/compilation/targetinterpretation.h @@ -1,129 +1,130 @@ /* 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: targetstatic.h * Author: pgess * * Created on July 2, 2016, 1:25 PM */ #ifndef TARGETSTATIC_H #define TARGETSTATIC_H #include "ast.h" #include "pass/compilepass.h" #include "compilation/targets.h" #include "pass/interpretationpass.h" #include "transcendlayer.h" namespace xreate{ namespace interpretation{ class TargetInterpretation; class InterpretationScope; class InterpretationFunction; }} namespace xreate{ namespace compilation{ template <> struct TargetInfo { typedef Expression Result; typedef interpretation::InterpretationScope Scope; typedef interpretation::InterpretationFunction Function; }; }} namespace xreate{ namespace interpretation{ /** \brief Encapsulates interpretation of a single Code Scope */ class InterpretationScope: public compilation::Scope{ typedef Scope Parent; public: InterpretationScope(const CodeScope* scope, compilation::Function* f): Parent(scope, f) {} Expression process(const Expression& expression) override; llvm::Value* compile(const Expression& expression, const compilation::Context& context); private: llvm::Value* compileHybrid(const InterpretationOperator& op, const Expression& expression, const compilation::Context& context); //llvm::Value* compilePartialFnCall(const Expression& expression, const Context& context); CodeScope* processOperatorIf(const Expression& expression); CodeScope* processOperatorSwitch(const Expression& expression); CodeScope* processOperatorSwitchVariant(const Expression& expression); }; /** \brief Encapsulates interpretation of a single %Function */ class InterpretationFunction: public compilation::Function{ public: InterpretationFunction(const ManagedFnPtr& function, compilation::Target* target); Expression process(const std::vector& args); }; /** \brief Signature of a partially interpreted function */ struct PIFSignature{ ManagedFnPtr declaration; std::vector bindings; }; class PIFunctionUnit; /** \brief Partially interpreted function */ class PIFunction: public InterpretationFunction{ public: PIFunctionUnit* functionUnit; PIFSignature signatureInstance; PIFunction(PIFSignature&& sig, size_t id, TargetInterpretation* target); llvm::Function* compile(); }; bool operator<(const PIFSignature& lhs, PIFunction* const rhs); bool operator<(PIFunction* const lhs, const PIFSignature& rhs); /** \brief Encapsulates actual [Interpretation](/w/concepts/dfa) based on InterpretationPass analysis results */ class TargetInterpretation: public compilation::Target{ public: TargetInterpretation(AST* root, CompilePass* passCompilation): Target(root), pass(passCompilation){} //target: public: InterpretationFunction* getFunction(compilation::IFunctionUnit* unit); PIFunction* getFunction(PIFSignature&& sig); private: std::map __pifunctions; std::map __dictFunctionsByUnit; //self: public: CompilePass* pass; llvm::Value* compile(const Expression& expression, const compilation::Context& ctx); -private: InterpretationScope* transformContext(const compilation::Context& c); + +private: }; /**\brief Interpretation-aware Code Scope decorator * \extends xreate::compilation::ICodeScopeUnit */ template class InterpretationScopeDecorator: public Parent{ public: InterpretationScopeDecorator(const CodeScope* const codeScope, compilation::IFunctionUnit* f, CompilePass* compilePass): Parent(codeScope, f, compilePass){} virtual llvm::Value* process(const Expression& expr, const std::string& hintVarDecl){ const InterpretationData& data = Attachments::get(expr, {ANY, NONE}); bool flagInterpretationEligible = (data.resolution == INTR_ONLY || data.op != InterpretationOperator::NONE); if (flagInterpretationEligible){ compilation::Context ctx{this, this->function, this->pass}; return Parent::pass->targetInterpretation->compile(expr, ctx); } return Parent::process(expr, hintVarDecl); } }; }} //end of xreate:: interpretation #endif /* TARGETSTATIC_H */ \ No newline at end of file diff --git a/cpp/src/compilation/targets.h b/cpp/src/compilation/targets.h index df281ca..0b31ddd 100644 --- a/cpp/src/compilation/targets.h +++ b/cpp/src/compilation/targets.h @@ -1,198 +1,213 @@ /* 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: targetabstract.h * Author: pgess * * Created on July 2, 2016, 1:25 PM */ /** * \file * \brief Compilation targets infrastructure */ #ifndef TARGETABSTRACT_H #define TARGETABSTRACT_H #include "ast.h" #include #include #include namespace xreate{ namespace compilation { template struct TargetInfo{ //typedef Result //typedef Function //typedef Scope }; template class Function; template class Target; template class Scope{ typedef typename TargetInfo::Scope Self; public: const CodeScope* scope; Function* function=0; typename TargetInfo::Result processSymbol(const Symbol& s){ const CodeScope* scope = s.scope; Self* self = function->getScope(scope); if (self->__bindings.count(s.identifier)) { return self->__bindings[s.identifier]; } const Expression& declaration = CodeScope::getDefinition(s, true); if (!declaration.isDefined()){ assert(false); //for bindings there should be result already } return self->__bindings[s.identifier] = self->process(declaration); } typename TargetInfo::Result processScope() { return process(scope->getBody()); } // typename TargetInfo::Result // processFunction(typename TargetInfo::Function* fnRemote, const std::vector::Result>& args){ // Scope scopeRemote = fnRemote->getScope(fnRemote->__function->__entry); // // if (scopeRemote->raw){ // return scopeRemote->raw; // } // // return fnRemote->process(args); // } virtual typename TargetInfo::Result process(const Expression& expression)=0; Scope(const CodeScope* codeScope, Function* f) : scope(codeScope), function(f) {} virtual ~Scope(){} void overrideBindings(std::list::Result, std::string>> bindings){ - reset(); + std::list::Result, ScopedSymbol>> bindingsSymbols; for (auto entry: bindings){ assert(scope->__identifiers.count(entry.second)); ScopedSymbol id{scope->__identifiers.at(entry.second), versions::VERSION_NONE}; - - __bindings[id] = entry.first; + bindingsSymbols.push_back(std::make_pair(entry.first, id)); } + + overrideBindings(bindingsSymbols); + } + + void + overrideBindings(std::list::Result, ScopedSymbol>> bindings){ + reset(); + + for (auto entry: bindings){ + __bindings[entry.second] = entry.first; + } + } + + bool + isBindingDefined(const ScopedSymbol& id){ + return __bindings.count(id); } void registerChildScope(std::shared_ptr scope){ __childScopes.push_back(scope); } void reset(){ __bindings.clear(); __childScopes.clear(); } protected: std::map::Result> __bindings; std::list> __childScopes; }; template class Function{ typedef typename TargetInfo::Result Result; typedef typename TargetInfo::Scope ConcreteScope; public: Function(const ManagedFnPtr& function, Target* target) : man(target), __function(function) {} virtual ~Function(){}; ConcreteScope* getScope(const CodeScope* const scope){ if (__scopes.count(scope)) { auto result = __scopes.at(scope).lock(); if (result){ return result.get(); } } std::shared_ptr unit(new ConcreteScope(scope, this)); if (scope->__parent != nullptr){ getScope(scope->__parent)->registerChildScope(unit); } else { assert(!__entryScope); __entryScope = unit; } if (!__scopes.emplace(scope, unit).second){ __scopes[scope] = unit; } return unit.get(); } virtual Result process(const std::vector& args)=0; Target* man=0; ManagedFnPtr __function; protected: std::map> __scopes; std::shared_ptr __entryScope; }; /** \brief Similar to xreate::IPass */ template class Target { typedef typename TargetInfo::Function ConcreteFunction; public: Target(AST* root): ast(root){} ConcreteFunction* getFunction(const ManagedFnPtr& function){ unsigned int id = function.id(); if (!__functions.count(id)){ ConcreteFunction* unit = new ConcreteFunction(function, this); __functions.emplace(id, unit); return unit; } return __functions.at(id); } AST* ast; virtual ~Target(){ for (const auto& entry: __functions){ delete entry.second; } } protected: std::map __functions; }; }} #endif /* TARGETABSTRACT_H */ diff --git a/cpp/src/llvmlayer.cpp b/cpp/src/llvmlayer.cpp index 288d559..5b59ffa 100644 --- a/cpp/src/llvmlayer.cpp +++ b/cpp/src/llvmlayer.cpp @@ -1,241 +1,244 @@ /* 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/. * * llvmlayer.cpp * * Author: pgess */ /** * \file llvmlayer.h * \brief Wrapper over LLVM */ #include "ast.h" #include "llvmlayer.h" #include "ExternLayer.h" #include "llvm/ExecutionEngine/ExecutionEngine.h" #include "llvm/ExecutionEngine/MCJIT.h" #include "llvm/Support/TargetSelect.h" #include #include using namespace llvm; using namespace xreate; using namespace std; LLVMLayer::LLVMLayer(AST* root) - : llvmContext(), - builder(llvmContext), - ast(root), - module(new llvm::Module(root->getModuleName(), llvmContext)) -{ +: llvmContext(), +builder(llvmContext), +ast(root), +module(new llvm::Module(root->getModuleName(), llvmContext)) { layerExtern = new ExternLayer(this); layerExtern->init(root); } void* -LLVMLayer::getFunctionPointer(llvm::Function* function){ +LLVMLayer::getFunctionPointer(llvm::Function* function) { uint64_t entryAddr = jit->getFunctionAddress(function->getName().str()); return (void*) entryAddr; } void -LLVMLayer::initJit(){ +LLVMLayer::initJit() { std::string ErrStr; LLVMInitializeNativeTarget(); llvm::InitializeNativeTargetAsmPrinter(); llvm::EngineBuilder builder(std::unique_ptr(module.release())); jit.reset(builder .setEngineKind(llvm::EngineKind::JIT) .setErrorStr(&ErrStr) .setVerifyModules(true) .create() - ); + ); } void -LLVMLayer::print(){ +LLVMLayer::print() { llvm::PassManager PM; PM.addPass(llvm::PrintModulePass(llvm::outs(), "banner")); llvm::AnalysisManager aman; PM.run(*module.get(), aman); } void -LLVMLayer::moveToGarbage(void *o) -{ +LLVMLayer::moveToGarbage(void *o) { __garbage.push_back(o); } llvm::Type* -LLVMLayer:: -toLLVMType(const ExpandedType& ty) const { +LLVMLayer::toLLVMType(const ExpandedType& ty) const { std::map empty; return toLLVMType(ty, empty); } llvm::Type* -LLVMLayer:: -toLLVMType(const ExpandedType& ty, std::map& conjuctions) const{ +LLVMLayer::toLLVMType(const ExpandedType& ty, std::map& conjuctions) const { TypeAnnotation t = ty; - switch (t.__operator) + switch (t.__operator) { + case TypeOperator::LIST: { - case TypeOperator::LIST: - { - assert(t.__operands.size()==1); + assert(t.__operands.size() == 1); - TypeAnnotation elTy = t.__operands.at(0); - return llvm::ArrayType::get(toLLVMType(ExpandedType(move(elTy)), conjuctions), t.__size); - } + TypeAnnotation elTy = t.__operands.at(0); + return llvm::ArrayType::get(toLLVMType(ExpandedType(move(elTy)), conjuctions), t.__size); + } - case TypeOperator::LIST_NAMED: - { - std::vector pack_; - pack_.reserve(t.__operands.size()); + case TypeOperator::LIST_NAMED: + { + std::vector pack_; + pack_.reserve(t.__operands.size()); - std::transform(t.__operands.begin(), t.__operands.end(), std::inserter(pack_, pack_.end()), - [this, &conjuctions](const TypeAnnotation& t){ - return toLLVMType(ExpandedType(TypeAnnotation(t)), conjuctions); - }); + std::transform(t.__operands.begin(), t.__operands.end(), std::inserter(pack_, pack_.end()), + [this, &conjuctions](const TypeAnnotation & t) { + return toLLVMType(ExpandedType(TypeAnnotation(t)), conjuctions); + }); - llvm::ArrayRef pack(pack_); + llvm::ArrayRef pack(pack_); - //process recursive types: - if (conjuctions.count(t.conjuctionId)) { - auto result = conjuctions[t.conjuctionId]; - result->setBody(pack, false); + //process recursive types: + if (conjuctions.count(t.conjuctionId)) { + auto result = conjuctions[t.conjuctionId]; + result->setBody(pack, false); - return result; - } + return result; + } - return llvm::StructType::get(llvmContext, pack, false); - }; + return llvm::StructType::get(llvmContext, pack, false); + }; - case TypeOperator::LINK: { - llvm::StructType* conjuction = llvm::StructType::create(llvmContext); - int id = t.conjuctionId; + case TypeOperator::LINK: + { + llvm::StructType* conjuction = llvm::StructType::create(llvmContext); + int id = t.conjuctionId; - conjuctions.emplace(id, conjuction); - return conjuction; - }; + conjuctions.emplace(id, conjuction); + return conjuction; + }; - case TypeOperator::CALL: - { - assert(false); - }; - - case TypeOperator::CUSTOM: - { - //Look in extern types - clang::QualType qt = layerExtern->lookupType(t.__valueCustom); - return layerExtern->toLLVMType(qt); - }; - - case TypeOperator::VARIANT: { - /* Variant Type Layout: - * struct { - * id: i8, Holds stored variant id - * storage: type of biggest variant - * } - */ - uint64_t sizeStorage=0; - llvm::Type* typStorageRaw = llvm::Type::getVoidTy(llvmContext); - for(const TypeAnnotation& subtype: t.__operands){ - llvm::Type* subtypeRaw = toLLVMType(ExpandedType(subtype), conjuctions); - - uint64_t sizeSubtype = module->getDataLayout().getTypeStoreSize(subtypeRaw); - if (sizeSubtype > sizeStorage){ - sizeStorage = sizeSubtype; - typStorageRaw = subtypeRaw; - } - } + case TypeOperator::CALL: + { + assert(false); + }; - std::vector layout; - layout.push_back(llvm::Type::getInt8Ty(llvmContext)); //id + case TypeOperator::CUSTOM: + { + //Look in extern types + clang::QualType qt = layerExtern->lookupType(t.__valueCustom); + return layerExtern->toLLVMType(qt); + }; - const bool flagHoldsData = sizeStorage > 0; - if (flagHoldsData) { - layout.push_back(typStorageRaw); //storage + //DEBT omit ID field in case of single variant. + case TypeOperator::VARIANT: + { + /* Variant Type Layout: + * { + * id :: i8, Holds stored variant id + * storage:: type of biggest variant + * } + */ + uint64_t sizeStorage = 0; + llvm::Type* typStorageRaw = llvm::Type::getVoidTy(llvmContext); + for(const TypeAnnotation& subtype : t.__operands) { + llvm::Type* subtypeRaw = toLLVMType(ExpandedType(subtype), conjuctions); + if (subtypeRaw->isVoidTy()) continue; + + uint64_t sizeSubtype = module->getDataLayout().getTypeStoreSize(subtypeRaw); + if (sizeSubtype > sizeStorage) { + sizeStorage = sizeSubtype; + typStorageRaw = subtypeRaw; } + } - return llvm::StructType::get(llvmContext, llvm::ArrayRef(layout)); + std::vector layout; + layout.push_back(llvm::Type::getInt8Ty(llvmContext)); //id + + const bool flagHoldsData = sizeStorage > 0; + if (flagHoldsData) { + layout.push_back(typStorageRaw); //storage } - case TypeOperator::NONE: { - switch (t.__value) { - case TypePrimitive::I32: - case TypePrimitive::Int: - case TypePrimitive::Num: - return llvm::Type::getInt32Ty(llvmContext); + return llvm::StructType::get(llvmContext, llvm::ArrayRef(layout)); + } + + case TypeOperator::NONE: + { + switch (t.__value) { + case TypePrimitive::I32: + case TypePrimitive::Int: + case TypePrimitive::Num: + return llvm::Type::getInt32Ty(llvmContext); - case TypePrimitive::Bool: - return llvm::Type::getInt1Ty(llvmContext); + case TypePrimitive::Bool: + return llvm::Type::getInt1Ty(llvmContext); - case TypePrimitive::I8: - return llvm::Type::getInt8Ty(llvmContext); + case TypePrimitive::I8: + return llvm::Type::getInt8Ty(llvmContext); - case TypePrimitive::I64: - return llvm::Type::getInt64Ty(llvmContext); + case TypePrimitive::I64: + return llvm::Type::getInt64Ty(llvmContext); - case TypePrimitive::Float: - return llvm::Type::getDoubleTy(llvmContext); + case TypePrimitive::Float: + return llvm::Type::getDoubleTy(llvmContext); - case TypePrimitive::String: - return llvm::Type::getInt8PtrTy(llvmContext); + case TypePrimitive::String: + return llvm::Type::getInt8PtrTy(llvmContext); - default: - assert(false); - } - } + case TypePrimitive::Invalid: + return llvm::Type::getVoidTy(llvmContext); default: assert(false); + } + } + + default: + assert(false); } assert(false); return nullptr; } -bool TypeUtils::isStruct(const ExpandedType& ty){ +bool +TypeUtils::isStruct(const ExpandedType& ty) { const TypeAnnotation& t = ty.get(); - if (t.__operator==TypeOperator::LIST_NAMED) { + if (t.__operator == TypeOperator::LIST_NAMED) { return true; } if (t.__operator != TypeOperator::CUSTOM) { return false; } clang::QualType tqual = llvm->layerExtern->lookupType(t.__valueCustom); const clang::Type * raw = tqual.getTypePtr(); - // TODO skip ALL the pointers until non-pointer type found + // TODO skip ALL the pointers until non-pointer type found if (raw->isStructureType()) return true; if (!raw->isAnyPointerType()) return false; clang::QualType pointee = raw->getPointeeType(); return pointee->isStructureType(); } - -bool TypeUtils::isPointer(const ExpandedType &ty) { +bool +TypeUtils::isPointer(const ExpandedType &ty) { if (ty.get().__operator != TypeOperator::CUSTOM) return false; clang::QualType qt = llvm->layerExtern->lookupType(ty.get().__valueCustom); return llvm->layerExtern->isPointer(qt); } - std::vector TypeUtils::getStructFields(const ExpandedType &t) { return (t.get().__operator == TypeOperator::LIST_NAMED) - ? t.get().fields - : llvm->layerExtern->getStructFields( - llvm->layerExtern->lookupType(t.get().__valueCustom)); + ? t.get().fields + : llvm->layerExtern->getStructFields( + llvm->layerExtern->lookupType(t.get().__valueCustom)); } diff --git a/cpp/src/pass/cfapass.cpp b/cpp/src/pass/cfapass.cpp index de391a6..ac93e15 100644 --- a/cpp/src/pass/cfapass.cpp +++ b/cpp/src/pass/cfapass.cpp @@ -1,196 +1,198 @@ /* 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/. * * cfapass.cpp * * Author: pgess */ /** * \file cfapass.h * \brief Control Flow Analysis(CFA) */ #include "cfapass.h" #include "analysis/cfagraph.h" #include "analysis/DominatorsTreeAnalysisProvider.h" #include using namespace std; using namespace xreate::cfa; void CFAPassBasic::initSignatures(){ auto range = man->root->__interfacesData.equal_range(CFA); for (auto i = range.first; i!= range.second; ++i){ __signatures.emplace(i->second.op, i->second); } } void CFAPassBasic::run(){ initSignatures(); return AbstractPass::run(); } void CFAPassBasic::finish(){ man->transcend->registerReport(__context.graph); dominators::DominatorsTreeAnalysisProvider* reportDominators = new dominators::DominatorsTreeAnalysisProvider(); reportDominators->run(__context.graph); man->transcend->registerReport(reportDominators); return AbstractPass::finish(); } void CFAPassBasic::processFnCall(ManagedFnPtr function, PassContext context){ TranscendLayer* transcend = man->transcend; __context.graph->addCallConnection(transcend->pack(context.scope), function->getName()); return AbstractPass::processFnCall(function, context); } void CFAPassBasic::processFnCallUncertain(ManagedFnPtr function, PassContext context){ TranscendLayer* transcend = man->transcend; __context.graph->addCallConnection(transcend->pack(context.scope), function->getName()); return AbstractPass::processFnCallUncertain(function, context); } void CFAPassBasic::process(CodeScope* scope, PassContext context, const std::string& hintBlockDecl){ TranscendLayer* transcend = man->transcend; const CodeScope* scopeParent = context.scope; ScopePacked scopeId = transcend->pack(scope); + __context.graph->addScope(scope); + //Parent Relations if (scopeParent){ __context.graph->addParentConnection(scopeId, transcend->pack(scopeParent)); } else { __context.graph->addParentConnection(scopeId, context.function->getName()); } //TOTEST scope annotations //SECTIONTAG context gather scope annotations __context.graph->addScopeAnnotations(scopeId, scope->tags); __context.graph->addContextRules(scopeId, scope->contextRules); return AbstractPass::process(scope, context, hintBlockDecl); } //TOTEST scope annotations via scheme void CFAPassBasic::process(const Expression& expression, PassContext context, const std::string& varDecl){ TranscendLayer* transcend = man->transcend; if (expression.__state == Expression::COMPOUND){ Operator op= expression.op; if (__signatures.count(op)) { assert(expression.blocks.size()); for (const auto& scheme: boost::make_iterator_range(__signatures.equal_range(expression.op))) { __context.graph->addScopeAnnotations(transcend->pack(expression.blocks.front()), scheme.second.getOperands()); } } } return AbstractPass::process(expression, context, varDecl); } void CFAPassBasic::process(ManagedFnPtr function){ __context.graph->addFunctionAnnotations(function->getName(), function->getTags()); return AbstractPass::process(function); } CFAPassBasic::CFAPassBasic(PassManager* manager) : AbstractPass(manager) , __context{new CFAGraph(manager->transcend)} {} /****************************SCOPE DEPENDENCIES********************************/ void CFAPassDependenciesDecorator::process(const Expression& expression, PassContext context, const std::string& varDecl){ TranscendLayer* transcend = man->transcend; if (expression.__state == Expression::COMPOUND) switch(expression.op){ case Operator::SEQUENCE:{ ScopePacked scopePrev = transcend->pack(expression.blocks.front()); for(auto scopeIt= ++expression.blocks.begin(); scopeIt != expression.blocks.end(); ++scopeIt){ ScopePacked scopeCurrent = transcend->pack(*scopeIt); __context.graph->addDependency(scopeCurrent, scopePrev); scopePrev = scopeCurrent; } break; } default: break; } return Parent::process(expression, context, varDecl); } void CFAPassDependenciesDecorator::processFnCall(ManagedFnPtr function, PassContext context){ TranscendLayer* transcend = man->transcend; const CodeScope* scopeCaller = context.scope; assert(scopeCaller); ScopePacked scopeCallerPacked = transcend->pack(scopeCaller); if(__context.graph->isDependent(scopeCallerPacked)){ ScopePacked scopeCalleePacked = transcend->pack(function->getEntryScope()); __context.graph->transmitDependencies(scopeCalleePacked, scopeCallerPacked); } Parent::processFnCall(function, context); } void CFAPassDependenciesDecorator::processFnCallUncertain(ManagedFnPtr function, PassContext context){ TranscendLayer* transcend = man->transcend; const CodeScope* scopeCaller = context.scope; assert(scopeCaller); ScopePacked scopeCallerPacked = transcend->pack(scopeCaller); if(__context.graph->isDependent(scopeCallerPacked)){ ScopePacked scopeCalleePacked = transcend->pack(function->getEntryScope()); __context.graph->transmitDependencies(scopeCalleePacked, scopeCallerPacked); } Parent::processFnCallUncertain(function, context); } void CFAPassDependenciesDecorator::process(CodeScope* scope, PassContext context, const std::string& hintBlockDecl){ TranscendLayer* transcend = man->transcend; const CodeScope* scopeParent = context.scope; if (scopeParent){ ScopePacked scopePacked = transcend->pack(scope); ScopePacked scopeParentPacked = transcend->pack(scopeParent); if (!__context.graph->isDependent(scopePacked) && __context.graph->isDependent(scopeParentPacked)) { __context.graph->transmitDependencies(scopePacked, scopeParentPacked); } } Parent::process(scope, context, hintBlockDecl); } /** * \class xreate::cfa::CFAPass * \details Provides CFA, important analysis for reasoning. Iterates over AST and stores collected data in CFAGraph */ diff --git a/cpp/src/pass/compilepass.cpp b/cpp/src/pass/compilepass.cpp index 21d3234..9d011d6 100644 --- a/cpp/src/pass/compilepass.cpp +++ b/cpp/src/pass/compilepass.cpp @@ -1,720 +1,717 @@ /* 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 "transcendlayer.h" #include #include "llvmlayer.h" #include "query/containers.h" #include "compilation/containers.h" #include "ExternLayer.h" #include "compilation/targetinterpretation.h" #include "pass/versionspass.h" #include "compilation/scopedecorators.h" #include "compilation/operators.h" -#include "aux/latereasoning.h" -#include "compilation/latereasoning.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() { +BasicFunctionUnit::prepareSignature() { 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 BasicFunctionUnit DefaultFunctionUnit; +typedef BasicFunctionUnit BruteFunctionDefault; 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) { +RawFnInvocation::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 { +class CallStatementInline : public IFnInvocation { 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* +IFnInvocation* 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); + return new RawFnInvocation(external, llvm); } //There should be only one specialization without any valid guards at this point - return new CallStatementRaw(pass->getFunctionUnit( + return new RawFnInvocation(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)); + 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::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); } }; 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::SWITCH_LATE: { - latereasoning::LateReasoningCompiler compiler({this, function, pass}); - return compiler.compile(expr, DEFAULT("switchlate")); + assert(false && "Instruction's compilation should've been redirected to interpretation"); + return nullptr; } 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) { LLVMLayer* llvm = pass->man->llvm; if (!hintBlockDecl.empty()) { llvm::BasicBlock *block = llvm::BasicBlock::Create(llvm->llvmContext, 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(); + std::vector&& types = prepareSignature(); 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); + return new BruteFunctionDefault(function, this); } template<> compilation::ICodeScopeUnit* CompilePassCustomDecorators::buildCodeScopeUnit(const CodeScope* const scope, IFunctionUnit* function){ return new DefaultCodeScopeUnit(scope, function, this); } } // end of compilation compilation::IFunctionUnit* CompilePass::getFunctionUnit(const ManagedFnPtr& function) { unsigned int id = function.id(); if (!functions.count(id)) { compilation::IFunctionUnit* unit = buildFunctionUnit(function); functions.emplace(id, unit); return unit; } return functions.at(id); } void CompilePass::run() { //Initialization: managerTransformations = new xreate::compilation::TransformationsManager(); targetInterpretation = new interpretation::TargetInterpretation(this->man->root, this); - Attachments::init(); //Determine entry function: StaticModel model = man->transcend->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>(TranscendLayer::parse(model.begin()->second)); compilation::IFunctionUnit* unitMain = getFunctionUnit(man->root->findFunction(nameMain)); //Compilation itself: entry = unitMain->compile(); } llvm::Function* CompilePass::getEntryFunction() { assert(entry); return entry; } void CompilePass::prepareQueries(TranscendLayer* transcend) { transcend->registerQuery(new containers::Query(), QueryId::ContainersQuery); transcend->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:TranscendLayer 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 405aac0..fd2ab05 100644 --- a/cpp/src/pass/compilepass.h +++ b/cpp/src/pass/compilepass.h @@ -1,207 +1,208 @@ /* 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 TranscendLayer; class CompilePass; class LLVMLayer; 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 + * \details Default implementation is xreate::compilation::RawFnInvocation */ -class ICallStatement { +class IFnInvocation { 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{ +/** \brief Default IFnInvocation implementation */ +class RawFnInvocation: public IFnInvocation{ public: - CallStatementRaw(llvm::Function* callee, LLVMLayer* l) + RawFnInvocation(llvm::Function* callee, LLVMLayer* l) : __callee(callee), __calleeTy(callee->getFunctionType()), llvm(l) {} - CallStatementRaw(llvm::Value* callee, llvm::FunctionType* ty, LLVMLayer* l) + RawFnInvocation(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: +protected: 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; - + virtual void reset() = 0; protected: - virtual ICallStatement* findFunction(const Expression& opCall)=0; + virtual IFnInvocation* 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; + IFnInvocation* 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); + virtual llvm::Type* prepareResult() = 0; + 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 std::vector prepareSignature() = 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 std::vector prepareSignature() override; virtual llvm::Type* prepareResult() override; virtual llvm::Function::arg_iterator prepareBindings() override; }; } // end of namespace compilation class CompilePass : public AbstractPass { 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::TranscendLayer */ static void prepareQueries(TranscendLayer* transcend); 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; }; 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/pass/interpretationpass.cpp b/cpp/src/pass/interpretationpass.cpp index 5e8a0e3..1e4d33e 100644 --- a/cpp/src/pass/interpretationpass.cpp +++ b/cpp/src/pass/interpretationpass.cpp @@ -1,525 +1,533 @@ /* 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: interpretationpass.cpp * Author: pgess * * Created on July 5, 2016, 5:21 PM */ /** * \file interpretationpass.h * \brief Interpretation analysis: determines what parts of code could be interpreted */ #include "pass/interpretationpass.h" #include #include #include "ast.h" //DEBT implement InterpretationPass purely in transcend //DEBT represent InterpretationPass as general type inference using namespace std; namespace xreate { template<> interpretation::InterpretationResolution defaultValue() { return interpretation::CMPL_ONLY; } namespace interpretation { enum InterpretationQuery { QUERY_INTR_ONLY, QUERY_CMPL_ONLY }; namespace details { template bool checkConstraints(InterpretationResolution flag) { return( (flag==INTR_ONLY&&FLAG_REQUIRED==QUERY_INTR_ONLY) ||(flag==CMPL_ONLY&&FLAG_REQUIRED==QUERY_CMPL_ONLY)); } InterpretationResolution recognizeTags(const map& tags) { auto i=tags.find("interpretation"); if(i==tags.end()){ return ANY; } assert(i->second.op==Operator::CALL); const string& cmd=i->second.operands.at(0).getValueString(); //TODO make consistent names of annotation and resolution if(cmd=="force"){ return INTR_ONLY; } else if(cmd=="suppress"){ return CMPL_ONLY; } return ANY; } } InterpretationResolution unify(InterpretationResolution flag) { return flag; } template InterpretationResolution unify(FLAG_A flagA, FLAG_B flagB, FLAGS... flags) { if(flagA==ANY){ return unify(flagB, flags...); } if(flagB==ANY){ return unify(flagA, flags...); } assert(flagA==flagB); return flagA; } template bool checkConstraints(std::vector&& flags) { assert(flags.size()); InterpretationResolution flag=flags.front(); return details::checkConstraints(flag); } template bool checkConstraints(std::vector&& flags) { assert(flags.size()); InterpretationResolution flag=flags.front(); flags.pop_back(); if(details::checkConstraints(flag)){ return checkConstraints(move(flags)); } return false; } bool InterpretationData::isDefault() const { return(resolution==ANY&&op==NONE); } void recognizeTags(const Expression& e) { InterpretationData tag{details::recognizeTags(e.tags), NONE}; if(!tag.isDefault()) Attachments::put(e, tag); } InterpretationResolution recognizeTags(const ManagedFnPtr& f) { return details::recognizeTags(f->getTags()); } InterpretationPass::InterpretationPass(PassManager* manager) : AbstractPass(manager) { Attachments::init(); Attachments::init(); } void InterpretationPass::run() { ManagedFnPtr f=man->root->begin(); auto& visitedSymbols=getSymbolCache(); while(f.isValid()) { const Symbol&symbolFunction{ScopedSymbol::RetSymbol, f->getEntryScope()}; if(!visitedSymbols.isCached(symbolFunction)){ visitedSymbols.setCachedValue(symbolFunction, process(f)); } ++f; } } InterpretationResolution InterpretationPass::process(const Expression& expression, PassContext context, const std::string& decl) { recognizeTags(expression); InterpretationResolution resolution=ANY; InterpretationOperator op=NONE; switch(expression.__state) { case Expression::NUMBER: case Expression::STRING: { break; } case Expression::IDENT: { resolution=Parent::processSymbol(Attachments::get(expression), context); break; } case Expression::COMPOUND: break; default: { resolution=CMPL_ONLY; break; } } if(expression.__state==Expression::COMPOUND) switch(expression.op) { case Operator::EQU: case Operator::NE: { InterpretationResolution left=process(expression.operands[0], context); InterpretationResolution right=process(expression.operands[1], context); resolution=unify(left, right); break; } case Operator::LOGIC_AND: { assert(expression.operands.size()==1); resolution=process(expression.operands[0], context); break; } case Operator::CALL: { //TODO cope with static/dynamic context //TODO BUG here: if several variants they all are processed as CMPL regardless of signature list callees=man->root->getFunctionSpecializations(expression.getValueString()); if(callees.size()!=1){ resolution=CMPL_ONLY; break; } ManagedFnPtr callee=callees.front(); const Symbol& symbCalleeFunc{ScopedSymbol::RetSymbol, callee->getEntryScope()}; //recursion-aware processing: // - skip self recursion const Symbol&symbSelfFunc{ScopedSymbol::RetSymbol, context.function->getEntryScope()}; if(!(symbSelfFunc==symbCalleeFunc)){ InterpretationResolution resCallee=processFnCall(callee, context); assert(resCallee!=FUNC_POSTPONED&&"Indirect recursion detected: can't decide on interpretation resolution"); resolution=unify(resolution, resCallee); } //check arguments compatibility const FunctionInterpretationData& calleeSignature=FunctionInterpretationHelper::getSignature(callee); for(size_t op=0, size=expression.operands.size(); op({flagCondition})){ op=IF_INTERPRET_CONDITION; flagCondition=ANY; } resolution=unify(flagCondition, flagScope1, flagScope2); break; } case Operator::FOLD: { InterpretationResolution flagInput=process(expression.getOperands()[0], context); InterpretationResolution flagAccumInit=process(expression.getOperands()[1], context); CodeScope* scopeBody=expression.blocks.front(); const std::string& nameEl=expression.bindings[0]; Symbol symbEl{ScopedSymbol {scopeBody->__identifiers.at(nameEl), versions::VERSION_NONE}, scopeBody}; getSymbolCache().setCachedValue(symbEl, InterpretationResolution(flagInput)); const std::string& nameAccum=expression.bindings[1]; Symbol symbAccum{ScopedSymbol {scopeBody->__identifiers.at(nameAccum), versions::VERSION_NONE}, scopeBody}; getSymbolCache().setCachedValue(symbAccum, InterpretationResolution(flagAccumInit)); InterpretationResolution flagBody=Parent::process(expression.blocks.front(), context); //special case: FOLD_INTERPRET_INPUT if(checkConstraints({flagInput})){ op=FOLD_INTERPRET_INPUT; flagInput=ANY; } resolution=unify(flagInput, flagAccumInit, flagBody); break; } case Operator::INDEX: { for(const Expression &op : expression.getOperands()) { resolution=unify(resolution, process(op, context)); } break; } case Operator::SWITCH: { InterpretationResolution flagCondition=process(expression.operands[0], context); bool hasDefaultCase=expression.operands[1].op==Operator::CASE_DEFAULT; //determine conditions resolution InterpretationResolution flagHeaders=flagCondition; for(size_t size=expression.operands.size(), i=hasDefaultCase?2:1; i({flagHeaders})){ op=SWITCH_INTERPRET_CONDITION; flagHeaders=ANY; } //determine body resolutions resolution=flagHeaders; for(size_t size=expression.operands.size(), i=1; i({resolution})){ op=SWITCH_VARIANT; resolution=ANY; } const string identCondition=expression.bindings.front(); for(auto scope : expression.blocks) { //set binding resolution ScopedSymbol symbolInternal=scope->getSymbol(identCondition); getSymbolCache().setCachedValue(Symbol{symbolInternal, scope}, InterpretationResolution(resolutionCondition)); resolution=unify(resolution, Parent::process(scope, context)); } for(auto scope : expression.blocks) { resolution=unify(resolution, Parent::process(scope, context)); } break; } case Operator::LIST: case Operator::LIST_NAMED: { for(const Expression &op : expression.getOperands()) { resolution=unify(resolution, process(op, context)); } break; } case Operator::VARIANT: { if(expression.getOperands().size()){ resolution=process(expression.getOperands().front(), context); } else { resolution=ANY; } break; } default: { resolution=CMPL_ONLY; for(const Expression &op : expression.getOperands()) { process(op, context); } for(CodeScope* scope : expression.blocks) { Parent::process(scope, context); } break; } } InterpretationData dataExpected= Attachments::get(expression,{ANY, NONE}); resolution=unify(resolution, dataExpected.resolution); if(resolution!=dataExpected.resolution || op != dataExpected.op ){ Attachments::put(expression,{resolution, op}); } return resolution; } InterpretationResolution InterpretationPass::processFnCall(ManagedFnPtr function, PassContext context) { return process(function); } InterpretationResolution InterpretationPass::process(ManagedFnPtr function) { CodeScope* entry=function->getEntryScope(); std::vector arguments=entry->__bindings; const Symbol&symbSelfFunc{ScopedSymbol::RetSymbol, function->getEntryScope()}; auto& cache=getSymbolCache(); if(cache.isCached(symbSelfFunc)) return cache.getCachedValue(symbSelfFunc); const FunctionInterpretationData& fnSignature=FunctionInterpretationHelper::getSignature(function); InterpretationResolution fnResolutionExpected=details::recognizeTags(function->getTags()); //mark preliminary function resolution as expected if(fnResolutionExpected!=ANY){ cache.setCachedValue(symbSelfFunc, move(fnResolutionExpected)); } else { // - in order to recognize indirect recursion mark this function resolution as POSTPONED cache.setCachedValue(symbSelfFunc, FUNC_POSTPONED); } //set resolution for function arguments as expected for(int argNo=0, size=arguments.size(); argNo__identifiers.at(arguments[argNo]), versions::VERSION_NONE}, entry}; cache.setCachedValue(symbArg, InterpretationResolution(fnSignature.signature[argNo])); } PassContext context; context.function=function; context.scope=entry; InterpretationResolution resActual=process(CodeScope::getDefinition(symbSelfFunc), context); resActual=unify(resActual, fnResolutionExpected); return cache.setCachedValue(symbSelfFunc, move(resActual)); } const FunctionInterpretationData FunctionInterpretationHelper::getSignature(ManagedFnPtr function) { if(Attachments::exists(function)){ return Attachments::get(function); } FunctionInterpretationData&& data=recognizeSignature(function); Attachments::put(function, data); return data; } FunctionInterpretationData FunctionInterpretationHelper::recognizeSignature(ManagedFnPtr function) { CodeScope* entry=function->__entry; FunctionInterpretationData result; result.signature.reserve(entry->__bindings.size()); bool flagPartialInterpretation=false; for(size_t no=0, size=entry->__bindings.size(); no__bindings[no]; Symbol symbArg{ScopedSymbol {entry->__identifiers.at(argName), versions::VERSION_NONE}, entry}; const Expression& arg=CodeScope::getDefinition(symbArg); InterpretationResolution argResolution=details::recognizeTags(arg.tags); flagPartialInterpretation|=(argResolution==INTR_ONLY); result.signature.push_back(argResolution); } result.flagPartialInterpretation=flagPartialInterpretation; return result; } bool FunctionInterpretationHelper::needPartialInterpretation(ManagedFnPtr function) { const FunctionInterpretationData& data=getSignature(function); return data.flagPartialInterpretation; } } } //end of namespace xreate::interpretation /** \class xreate::interpretation::InterpretationPass * * Encapsulates *Interpretation Analysis* to support [Interpretation Concept](/w/concepts/dfa) * * Recognizes program functions, expressions, instructions eligible for interpretation * and stores output in Attachments and Attachments * * There are number of instructions currently able to be interpreted: * - Basic literals: numbers and strings * - Compounds: lists, structs, variants * - Non-versioned identifiers * - Comparison and logic operators * - %Function calls * - `query` intrinsic function calls * - Branching: `if`, `loop fold`, `switch`, `switch variant` statements * * Some of those instructions are eligibile for *hybrid interpretation* to allow coupling * of compiled instructions with interpreted ones, those are: * - Partial function calls * - Branching: `if`, `loop fold`, `switch`, `switch variant` statements * * \sa xreate::interpretation::TargetInterpretation, [Interpretation Concept](/w/concepts/dfa) */ diff --git a/cpp/src/pass/interpretationpass.h b/cpp/src/pass/interpretationpass.h index b5ebf20..21da1d3 100644 --- a/cpp/src/pass/interpretationpass.h +++ b/cpp/src/pass/interpretationpass.h @@ -1,92 +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: interpretationpass.h * Author: pgess * * Created on July 5, 2016, 5:21 PM */ #ifndef INTERPRETATIONPASS_H #define INTERPRETATIONPASS_H #include "abstractpass.h" #include #ifndef FRIENDS_INTERPRETATION_TESTS #define FRIENDS_INTERPRETATION_TESTS #endif //TODO refactor interpretation. Get rid of InterpretationOperator, put only one operator - Hybrid. namespace xreate{ namespace interpretation{ enum InterpretationResolution{ANY, INTR_ONLY, CMPL_ONLY, FUNC_POSTPONED}; - enum InterpretationOperator{NONE, IF_INTERPRET_CONDITION, FOLD_INTERPRET_INPUT, SWITCH_INTERPRET_CONDITION, SWITCH_VARIANT, CALL_INTERPRET_PARTIAL}; + enum InterpretationOperator{ + NONE, IF_INTERPRET_CONDITION, FOLD_INTERPRET_INPUT, + SWITCH_INTERPRET_CONDITION, SWITCH_VARIANT, SWITCH_LATE, + CALL_INTERPRET_PARTIAL + }; struct InterpretationData{ InterpretationResolution resolution; InterpretationOperator op; bool isDefault() const; }; struct FunctionInterpretationData{ typedef std::vector Signature; Signature signature; bool flagPartialInterpretation; }; class FunctionInterpretationHelper { public: static const FunctionInterpretationData getSignature(ManagedFnPtr function); static bool needPartialInterpretation(ManagedFnPtr function); private: static FunctionInterpretationData recognizeSignature(ManagedFnPtr function); }; /** \brief Determines parts of program eligible for Interpretation. */ class InterpretationPass: public AbstractPass { typedef AbstractPass Parent; public: InterpretationResolution process(const Expression& expression, PassContext context, const std::string& varDecl="") override; InterpretationResolution process(ManagedFnPtr function); InterpretationResolution processFnCall(ManagedFnPtr function, PassContext context); InterpretationPass(PassManager* manager); void run(); }; namespace details { InterpretationResolution recognizeTags(const std::map& tags); } } //end of namespace interpretation template<> interpretation::InterpretationResolution defaultValue(); template<> struct AttachmentsDict { typedef interpretation::FunctionInterpretationData Data; static const unsigned int key = 5; }; template<> struct AttachmentsDict { typedef interpretation::InterpretationData Data; static const unsigned int key = 3; }; } //end of namespace xreate #endif /* INTERPRETATIONPASS_H */ diff --git a/cpp/src/pass/latereasoningpass.h b/cpp/src/pass/latereasoningpass.h index c005673..6a9cde0 100644 --- a/cpp/src/pass/latereasoningpass.h +++ b/cpp/src/pass/latereasoningpass.h @@ -1,179 +1,182 @@ /* * 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 * Created on June 7, 2018, 7:20 PM * * \file latereasoningpass.h * \brief latereasoningpass */ #ifndef LATEREASONINGPASS_H #define LATEREASONINGPASS_H #include "pass/dfapass.h" namespace xreate { namespace latereasoning { class LateReasoningScope{ public: LateReasoningScope(LateReasoningScope* parent): __parent(parent){ } boost::optional recognizeIdentifier(const std::string& identifier){ //Search identifier in the current scope if(__identifiers.count(identifier)){ return make_pair(identifier, __identifiers.at(identifier)); } //Search in the parent scope if(__parent){ return __parent->recognizeIdentifier(identifier); } return boost::none; } void addIdentifier(std::string idenName, const SymbolPacked& identSymbol){ __identifiers.emplace(idenName, identSymbol); } private: std::map __identifiers; LateReasoningScope *__parent; }; +/** + * \note Limitation: Produces late annotation with target as a symbol to which annotation is attached + */ template class LateReasoningDFAPassDecorator: public Parent{ public: LateReasoningDFAPassDecorator(PassManager* manager): Parent(manager){ } void registerLateScope(CodeScope* scope, LateReasoningScope* scopeLate){ __dictScopes.emplace(scope, scopeLate); } private: LateReasoningScope* liftScope(const CodeScope* scope){ while(scope){ if(__dictScopes.count(scope)) return __dictScopes.at(scope); scope = scope->__parent; } return nullptr; } std::list recognizeLateIdentifiers(const Expression& expression, LateReasoningScope* scope){ std::list result; switch(expression.op){ case Operator::CALL: { for(const auto& op: expression.operands){ std::list opResult = recognizeLateIdentifiers(op, scope); result.insert(result.end(), opResult.begin(), opResult.end()); } if(!expression.operands.size()){ if(auto symbolRecognized = scope->recognizeIdentifier(expression.getValueString())){ result.push_back(*symbolRecognized); } } break; } case Operator::NEG: { assert(expression.operands.size() == 1); const Expression &op = expression.operands.at(0); std::list opResult = recognizeLateIdentifiers(op, scope); result.insert(result.end(), opResult.begin(), opResult.end()); }; case Operator::INVALID: { switch(expression.__state){ case Expression::NUMBER: break; default: assert(true); } break; } default: break; } return result; } protected: virtual SymbolNode process(const Expression& expression, PassContext context, const std::string& varDecl="") override{ if(expression.__state == Expression::COMPOUND && expression.op == Operator::SWITCH_LATE){ //Reserve late scope: LateReasoningScope* scopeLate = new LateReasoningScope(liftScope(context.scope)); CodeScope* scopeBody = expression.blocks.front(); registerLateScope(scopeBody, scopeLate); //Assign late identifiers for(const std::string& identLate: expression.bindings){ ScopedSymbol identLateS = scopeBody->getSymbol(identLate); SymbolPacked identLateSP = Parent::man->transcend->pack(Symbol{identLateS, scopeBody}); scopeLate->addIdentifier(identLate, identLateSP); } } return Parent::process(expression, context, varDecl); } virtual void processAnnotations(const Expression& expression, PassContext context, const SymbolNode& ident){ LateReasoningScope* scopeLate = liftScope(context.scope); if(!expression.tags.size() || !scopeLate) return Parent::processAnnotations(expression, context, ident); for(const std::pair& tag: expression.tags){ std::list symbols = recognizeLateIdentifiers(tag.second, scopeLate); if(!symbols.size()){ //Standard compilation Parent::graph->printInplaceAnnotation(ident, tag.second); } else{ //Late compilation std::list domains; for(const auto& symbol: symbols){ Symbol symbolUnpacked = Parent::man->transcend->unpack(symbol.second); ExpandedType typSymbol = Parent::man->root->getType(CodeScope::getDefinition(symbolUnpacked)); assert(typSymbol->__operator == TypeOperator::SLAVE); domains.push_back(typSymbol->__valueCustom); } Parent::graph->printLateAnnotation(ident, tag.second, symbols, domains); } } } private: std::unordered_map __dictScopes; }; }} #endif /* LATEREASONINGPASS_H */ diff --git a/cpp/src/query/latex.cpp b/cpp/src/query/latex.cpp index 12f3c65..5fc0816 100644 --- a/cpp/src/query/latex.cpp +++ b/cpp/src/query/latex.cpp @@ -1,80 +1,94 @@ /* * 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 * Created on June 25, 2018, 12:14 PM * * \file latex.cpp * \brief latex */ #include "query/latex.h" +#include "aux/transcend-decorators.h" + using namespace std; +using namespace xreate::latereasoning; namespace xreate{ namespace latex{ void LatexQuery::init(TranscendLayer* transcend) { __transcend = transcend; //schema: latex_fn_demand(Fn, Subject) - StaticModel data = __transcend->query("latex_fn_demand"); + StaticModel data = __transcend->query("latex_fn_demand_ordered"); for(const auto& entry : data) { - string fnName, subject; - tie(fnName, subject) = __transcend->parse(entry.second); - __demand[fnName].push_back(subject); + string fnName, subject; size_t id; + tie(fnName, subject, id) = __transcend->parse(entry.second); + __demand[fnName].resize(std::max(__demand[fnName].size(), id+1)); + __demand[fnName][id] = subject; } - //schema: Scope, Subject, Decision - data = __transcend->query("latex_decision"); + //schema: Subject, Decision + data = __transcend->query("latex_registered_subjects"); for(const auto& entry : data) { - ScopePacked scope; string subject; Gringo::Symbol decision; - tie(scope, subject, decision) = __transcend->parse(entry.second); - __decisions[make_pair(scope, subject)] = decision; + tie(subject, decision) = __transcend->parse(entry.second); + __domains[subject].push_back(decision); } - - //schema: Subject, Decision - data = __transcend->query("latex_registered_subjects"); + + //schema: Scope, Subject, Decision + data = __transcend->query("latex_decision"); for(const auto& entry : data) { + ScopePacked scope; string subject; Gringo::Symbol decision; - tie(subject, decision) = __transcend->parse(entry.second); - __domains[subject].push_back(decision); + tie(scope, subject, decision) = __transcend->parse(entry.second); + __decisions[make_pair(scope, subject)] = entry.second; + } + + auto transcendLate = + Decorators::getInterface(__transcend); + + //Later decisions. schema: Scope, Subject, Decision + LateAnnotationsGroup group = transcendLate->queryLate("latex_decision"); + for (auto entry: group.annotations) { + auto key = __transcend->parse(entry.first); + __decisionsLate.emplace(make_pair(get<0>(key), get<1>(key)), entry.second); } } Demand LatexQuery::getFnDemand(const std::string& fnName) { if (!__demand.count(fnName)) return Demand(); return __demand.at(fnName); } -Gringo::Symbol +latereasoning::LateAnnotation LatexQuery::getDecision(const std::string& subject, const CodeScope* scopeCaller) { ScopePacked scopeP = __transcend->pack(scopeCaller); if(__decisions.count(make_pair(scopeP, subject))){ //found static decision - return __decisions.at(make_pair(scopeP, subject)); + return LateAnnotation(__decisions.at(make_pair(scopeP, subject))); } - //... <- вытащить late decision + return __decisionsLate.at(make_pair(scopeP, subject)); } std::list LatexQuery::getSubjectDomain(const std::string& subject) { assert(__domains.count(subject)); return __domains.at(subject); } } } \ No newline at end of file diff --git a/cpp/src/query/latex.h b/cpp/src/query/latex.h index 7163ef4..89ccf56 100644 --- a/cpp/src/query/latex.h +++ b/cpp/src/query/latex.h @@ -1,43 +1,44 @@ /* * 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 query/context.h * \brief Represents reasoner's solution on [Context](/w/concepts/context) * * \class xreate::latex::LatexQuery */ #ifndef LATEXQUERY_H #define LATEXQUERY_H #include "transcendlayer.h" +#include "aux/latereasoning.h" #include namespace xreate{ namespace latex{ -typedef std::list Demand; +typedef std::vector Demand; class LatexQuery: public IQuery{ public: Demand getFnDemand(const std::string& fnName); - Gringo::Symbol getDecision(const std::string& subject, const CodeScope* scopeCaller); + latereasoning::LateAnnotation getDecision(const std::string& subject, const CodeScope* scopeCaller); std::list getSubjectDomain(const std::string& subject); void init(TranscendLayer* transcend); private: TranscendLayer* __transcend; std::map __demand; std::map, Gringo::Symbol> __decisions; + std::map, latereasoning::LateAnnotation> __decisionsLate; std::map> __domains; }; } } -#endif /* LATEXQUERY_H */ - +#endif \ No newline at end of file diff --git a/cpp/src/query/polymorph.cpp b/cpp/src/query/polymorph.cpp index 794b237..52f6aa0 100644 --- a/cpp/src/query/polymorph.cpp +++ b/cpp/src/query/polymorph.cpp @@ -1,57 +1,71 @@ /* * 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" #include "aux/transcend-decorators.h" using namespace std; -namespace xreate { namespace polymorph { +namespace xreate{ +namespace polymorph{ const std::string atomPolymorph = "dfa_callguard"; void -PolymorphQuery::init(TranscendLayer* transcend){ +PolymorphQuery::init(TranscendLayer* transcend) { __transcend = transcend; StaticModel queryResult = transcend->query(atomPolymorph); - if (queryResult.size()){ - for (auto entry: queryResult){ - auto answer = TranscendLayer::parse(entry.second); + if (queryResult.size()) { + for (auto entry : queryResult) { + auto answer = TranscendLayer::parse(entry.second); SymbolNode symbCaller = std::get<0>(answer); SymbolGeneralized symbCallerUnpacked = transcend->unpack(symbCaller); - Expression guard = std::get<1>(answer); - __cacheEarlyReasoning.emplace(symbCallerUnpacked, guard); + __cacheEarlyReasoning.emplace(symbCallerUnpacked, entry.second); } } + + auto transcendLate = + Decorators::getInterface(__transcend); + latereasoning::LateAnnotationsGroup group = transcendLate->queryLate(atomPolymorph); + + for(auto entry : group.annotations) { + auto targetWrapper = Gringo::Symbol::createTuple(Gringo::SymSpan{&entry.first, 1}); + auto targetSP = __transcend->parse(targetWrapper); + SymbolGeneralized targetS = __transcend->unpack(std::get<0>(targetSP)); + __cacheLateReasoning.emplace(targetS, entry.second); + } } -Expression -PolymorphQuery::get(const Expression& e){ - SymbolGeneralized symbol=Attachments::exists(e)? +latereasoning::LateAnnotation +PolymorphQuery::get(const Expression& e) const { + SymbolGeneralized targetS = Attachments::exists(e) ? SymbolGeneralized(Attachments::get(e)) : SymbolGeneralized(SymbolAnonymous{e.id}); - if (__cacheEarlyReasoning.count(symbol)){ - return __cacheEarlyReasoning.at(symbol); + if (__cacheEarlyReasoning.count(targetS)) { + return latereasoning::LateAnnotation(__cacheEarlyReasoning.at(targetS)); } - DefaultTranscendLayerImpl* transcendLate = dynamic_cast(__transcend); - SymbolNode symbolPacked = __transcend->pack(symbol, ""); + if (__cacheLateReasoning.count(targetS)) { + return __cacheLateReasoning.at(targetS); + } - StaticModel answer = transcendLate->queryLate(atomPolymorph, symbolPacked); - assert(answer.size() && "Can't find a guard"); + assert(false && "Can't find a guard"); +} - Expression guard; - tie(guard) = TranscendLayer::parse(answer.begin()->second); - return guard; +Expression +PolymorphQuery::getValue(const Gringo::Symbol& symbol) const { + auto result = __transcend->parse(symbol); + return std::get<1>(result); } -}} //end of xreate::polymorph +} +} //end of xreate::polymorph diff --git a/cpp/src/query/polymorph.h b/cpp/src/query/polymorph.h index 3b28263..f708fe6 100644 --- a/cpp/src/query/polymorph.h +++ b/cpp/src/query/polymorph.h @@ -1,32 +1,35 @@ /* * 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.h * Author: pgess * * Created on November 9, 2017, 12:14 PM */ #ifndef POLYMORPHQUERY_H #define POLYMORPHQUERY_H #include "transcendlayer.h" +#include "aux/latereasoning.h" #include namespace xreate { namespace polymorph { class PolymorphQuery: public IQuery { public: + latereasoning::LateAnnotation get(const Expression& e) const; + Expression getValue(const Gringo::Symbol& s) const; virtual void init(TranscendLayer* transcend) override; - Expression get(const Expression& e); private: - std::unordered_map __cacheEarlyReasoning; + std::unordered_map __cacheEarlyReasoning; + std::unordered_map __cacheLateReasoning; TranscendLayer* __transcend = nullptr; }; }}//end of xreate::polymorph #endif /* POLYMORPHQUERY_H */ diff --git a/cpp/src/transcendlayer.cpp b/cpp/src/transcendlayer.cpp index 3058778..e960481 100644 --- a/cpp/src/transcendlayer.cpp +++ b/cpp/src/transcendlayer.cpp @@ -1,486 +1,496 @@ /* 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: transcendlayer.cpp */ /** * \file transcendlayer.h * \brief Reasoner. Wrapper over the external Clasp reasoner library */ #include "transcendlayer.h" #include "analysis/utils.h" #include "utils.h" #include #include #include #include #include #include using namespace std; //TODO escape identifiers started with upper case symbol namespace xreate{ bool operator==(const SymbolAnonymous& s1, const SymbolAnonymous& s2) { return s1.id == s2.id && s1.flagIsUsed == s2.flagIsUsed; } struct VisitorSymbolNodeHash : public boost::static_visitor{ std::size_t operator()(const xreate::SymbolPacked& node) const noexcept { return 2 * (node.identifier + 3 * node.scope + 5 * std::abs(node.version)); } std::size_t operator()(const xreate::SymbolAnonymous& node) const noexcept { return 7 * node.id; } -}; +} ; } namespace std{ std::size_t hash::operator()(xreate::SymbolNode const& s) const noexcept { return boost::apply_visitor(xreate::VisitorSymbolNodeHash(), s); } std::size_t hash::operator()(xreate::SymbolGeneralized const& s) const noexcept { return xreate::AttachmentsId::getId(s); } } namespace xreate{ void TranscendLayer::printWarnings(std::ostream& out) { const std::string warningTag = "warning"; auto warningsModel = query(warningTag); if(warningsModel.size()) for(auto warning : warningsModel) { unsigned int warningId; Gringo::Symbol params; std::tie(warningId, params) = parse(warning.second); cout << "Warning: " << __warnings.at(warningId) << " "; params.print(out); out << params; } } bool TranscendLayer::processSolution(Gringo::Model const &model) { cout << "Model: " << endl; const string& atomBindVar = Config::get("transcend.bindings.variable"); const string& atomBindFunc = Config::get("transcend.bindings.function"); const string& atomBindScope = Config::get("transcend.bindings.scope"); for(Gringo::Symbol atom : model.atoms(clingo_show_type_atoms)) { atom.print(cout); cout << " | " << endl; string atomName(atom.name().c_str()); if(atomName == atomBindVar || atomName == atomBindFunc || atomName == atomBindScope) { string atomAlias = std::get<1>(parse(atom)).name().c_str(); __model.emplace(atomAlias, atom); continue; } __model.emplace(atomName, atom); } return true; } void TranscendLayer::registerReport(IAnalysisReport * report) { __reports.push_back(report); } void TranscendLayer::runReports() { for(IAnalysisReport* report : __reports) { report->print(__partGeneral); delete report; } __reports.clear(); } void TranscendLayer::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); - }); + [&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(); - }); + [](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); - }); + [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, ", ")) - << endl; + % (hook) + % (boost::algorithm::join(vars, ", ")) + % (branch) + % (guardsJoined) + % (boost::algorithm::join(domains, ", ")) + << endl; } } unsigned int TranscendLayer::registerWarning(std::string && message) { static int warningId = 0; __warnings.emplace(warningId, message); return warningId++; } void TranscendLayer::involveImports() { ostream &out = __partGeneral; if(ast) - for(string fn : ast->__rawImports) { - std::ifstream file(fn); - 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; + for(string fn : ast->__rawImports) { + std::ifstream file(fn); + 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 TranscendLayer::addRawScript(std::string && script) { __partGeneral << script; } void TranscendLayer::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); + {}} + }, nullptr); // solve Gringo::SolveResult result = ctl.solve([this](Gringo::Model const &model) { this->processSolution(model); return true; - }, {}); + }, + { + }); if(result.satisfiable() == Gringo::SolveResult::Satisfiable) { cout << FGRN("SUCCESSFULLY") << endl; } else { cout << FRED("UNSUCCESSFULLY") << endl; } // invoke all query plugins to process solution for(auto q : __queries) { q.second->init(this); } } -TranscendLayer::TranscendLayer(): ast(nullptr) { } +TranscendLayer::TranscendLayer() : ast(nullptr) { } StaticModel -TranscendLayer::query(const std::string & atom) const{ +TranscendLayer::query(const std::string & atom) const { StaticModel result; - if (! __model.count(atom)){ + if (! __model.count(atom)) { return result; } auto currentDataRange = __model.equal_range(atom); std::copy(currentDataRange.first, currentDataRange.second, std::inserter(result, result.end())); return result; } ScopePacked TranscendLayer::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 TranscendLayer::getScopesCount() const { return __registryScopes.size(); } SymbolPacked TranscendLayer::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 -TranscendLayer::unpack(const SymbolPacked & symbol) const{ +TranscendLayer::unpack(const SymbolPacked & symbol) const { return Symbol{ScopedSymbol {symbol.identifier, symbol.version}, __registryScopes[symbol.scope]}; }; std::string TranscendLayer::getHintForPackedSymbol(const SymbolPacked & symbol) { auto result = __indexSymbolNameHints.find(symbol); return(result == __indexSymbolNameHints.end()) ? "" : result->second; } IQuery * - TranscendLayer::registerQuery(IQuery *query, const QueryId & id) { +TranscendLayer::registerQuery(IQuery *query, const QueryId & id) { return __queries.emplace(id, query).first->second; } IQuery * - TranscendLayer::getQuery(const QueryId & id) { +TranscendLayer::getQuery(const QueryId & id) { assert(__queries.count(id) && "Undefined query"); return __queries.at(id); } class VisitorUnpackSymbol : public boost::static_visitor{ public: VisitorUnpackSymbol(const TranscendLayer* transcend) : __transcend(transcend) { } SymbolGeneralized operator()(const SymbolPacked& symbol) const { return __transcend->unpack(symbol); } SymbolGeneralized operator()(const SymbolAnonymous& symbol) const { return symbol; } private: const TranscendLayer* __transcend; -}; +} ; class VisitorPackSymbol : public boost::static_visitor{ public: VisitorPackSymbol(TranscendLayer* transcend, const std::string& hintSymbolName) : __transcend(transcend), __hint(hintSymbolName) { } SymbolNode operator()(const Symbol& symbol) const { return __transcend->pack(symbol, __hint); } SymbolNode operator()(const SymbolAnonymous& symbol) const { return symbol; } private: TranscendLayer* __transcend; std::string __hint; -}; +} ; SymbolNode TranscendLayer::pack(const SymbolGeneralized& symbol, const std::string & hintSymbolName) { return boost::apply_visitor(VisitorPackSymbol(this, hintSymbolName), symbol); } SymbolGeneralized -TranscendLayer::unpack(const SymbolNode & symbol) const{ +TranscendLayer::unpack(const SymbolNode & symbol) const { return boost::apply_visitor(VisitorUnpackSymbol(this), symbol); } 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); } Expression -ParseImplAtom::get(const Gringo::Symbol & atom) { +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) { +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) { +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) { +ParseImplAtom +::get(const Gringo::Symbol & atom) { auto result = TranscendLayer::parse(atom); return SymbolPacked(std::get<0>(result), std::get<1>(result), std::get<2>(result)); }; Gringo::Symbol -ParseImplAtom::get(const Gringo::Symbol & atom) { +ParseImplAtom +::get(const Gringo::Symbol & atom) { return atom; } SymbolNode -ParseImplAtom::get(const Gringo::Symbol & atom) { +ParseImplAtom +::get(const Gringo::Symbol & atom) { assert(atom.type() == Gringo::SymbolType::Fun - && "Inappropriate symbol type"); + && "Inappropriate symbol type"); if(atom.name() == "a") { return SymbolAnonymous{(unsigned int) std::get<0>(TranscendLayer::parse(atom))}; } else if(atom.name() == "s") { return ParseImplAtom::get(atom); } assert(false && "Wrong symbol format"); } class VisitorSymbolId : public boost::static_visitor{ public: unsigned int operator()(const Symbol& symbol) const { return AttachmentsId::getId(symbol); } unsigned int operator()(const SymbolAnonymous& symbol) const { return symbol.id; } -}; +} ; unsigned int -AttachmentsId::getId(const SymbolGeneralized & symbol) { +AttachmentsId +::getId(const SymbolGeneralized & symbol) { return boost::apply_visitor(VisitorSymbolId(), symbol); } } //end of xreate namespace /** * \class xreate::TranscendLayer * \brief Reasoning and logic Solver. * * Wraps external brilliant fantastic tool [Clasp solver](https://potassco.org/clasp/) * * For building *logic program* for reasoning TranscendLayer 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 TranscendLayer got input from all providers and logic program is fully constructed * it runs external Clasp reasoner and receives back desired solutions. * * Output of the external 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 */ diff --git a/cpp/src/transcendlayer.h b/cpp/src/transcendlayer.h index e52d91d..e657c1c 100644 --- a/cpp/src/transcendlayer.h +++ b/cpp/src/transcendlayer.h @@ -1,282 +1,283 @@ /* 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: transcendlayer.h */ #ifndef transcendLAYER_H #define transcendLAYER_H #include "ast.h" #include "contextrule.h" #include #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); struct SymbolAnonymous { unsigned int id; bool flagIsUsed = false; }; bool operator==(const SymbolAnonymous& s1, const SymbolAnonymous& s2); typedef boost::variant SymbolNode; //DEBT use SymbolGeneralized communicating with Analysis rather than Symbol typedef boost::variant SymbolGeneralized; template<> struct AttachmentsId{ static unsigned int getId(const SymbolGeneralized& symbol); }; } namespace std { template<> struct hash { std::size_t operator()(xreate::SymbolNode const& s) const noexcept; }; template<> struct hash { std::size_t operator()(xreate::SymbolGeneralized const& s) const noexcept; }; } namespace xreate { 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(TranscendLayer* transcend) = 0; virtual ~IQuery() {} }; enum class QueryId { ContainersQuery, - PolymorphQuery + PolymorphQuery, + LatexQuery }; namespace dfa{ class DFAGraph; } namespace cfa { class CFAGraph; } typedef std::multimap StaticModel; typedef StaticModel::const_iterator StaticModelIterator; class TranscendLayer { 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); StaticModel query(const std::string& atom) const; size_t getScopesCount() const; SymbolPacked pack(const Symbol& symbol, std::string hintSymbolName = ""); ScopePacked pack(const CodeScope * const scope); Symbol unpack(const SymbolPacked& symbol) const; SymbolNode pack(const SymbolGeneralized& symbol, const std::string& hintSymbolName); SymbolGeneralized unpack(const SymbolNode& symbol) const; std::string getHintForPackedSymbol(const SymbolPacked& symbol); ///@} private: std::map __queries; 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: TranscendLayer(); /** \brief Executes reasoning */ void run(); ///@} AST *ast; protected: virtual bool processSolution(Gringo::Model const &model); private: StaticModel __model; std::ostringstream __partTags; std::ostringstream __partGeneral; }; 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 SymbolNode 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){ bool flagIsList = (atom.type() == Gringo::SymbolType::Fun) && atom.name().empty(); std::list result; if(!flagIsList) { //treat as degenerate case: list with a single element result.push_back(ParseImplAtom::get(atom)); return 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 TranscendLayer::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/tests/CMakeLists.txt b/cpp/tests/CMakeLists.txt index 8124d0b..2d220d4 100644 --- a/cpp/tests/CMakeLists.txt +++ b/cpp/tests/CMakeLists.txt @@ -1,55 +1,56 @@ 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 + cfa.cpp + latex.cpp + polymorph.cpp transcend.cpp - latereasoning.cpp +# latereasoning.cpp virtualization.cpp exploitation.cpp effects-communication.cpp - polymorph.cpp association.cpp main.cpp modules.cpp attachments.cpp ast.cpp - cfa.cpp dfa.cpp compilation.cpp ExpressionSerializer.cpp externc.cpp types.cpp #vendorsAPI/clangAPI.cpp #vendorsAPI/xml2.cpp #vendorsAPI/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/cfa.cpp b/cpp/tests/cfa.cpp index 002cae2..325ee81 100644 --- a/cpp/tests/cfa.cpp +++ b/cpp/tests/cfa.cpp @@ -1,190 +1,224 @@ /* Any copyright is dedicated to the Public Domain. * http://creativecommons.org/publicdomain/zero/1.0/ * - * testsCFG.cpp + * cfa.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 "pass/compilepass.h" +#include "compilation/scopedecorators.h" + #include "gtest/gtest.h" +#include "aux/xreatemanager-decorators.h" #include #include +#include using namespace xreate; using namespace xreate::cfa; using namespace std; -TEST(CFA, testFunctionAnnotationstranscend){ +TEST(CFA, testFunctionAnnotations) { 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(); StaticModel answer = man->transcend->query("annotationF1"); EXPECT_EQ(1, answer.size()); answer = man->transcend->query("annotationF2"); EXPECT_EQ(1, answer.size()); } -TEST(CFA, testLoopContextExists){ +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(); StaticModel model = man->transcend->query("annotation1"); ScopePacked scopeIdActual = std::get<0>(TranscendLayer::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->transcend->pack(scopeExpected); ASSERT_EQ(scopeIdExpected, scopeIdActual); } -TEST(CFA, DependenciesFnCall){ +TEST(CFA, DependenciesFnCall) { details::tier2::XreateManager* man = details::tier2::XreateManager::prepare( - R"Code( + 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->transcend->pack(scopeSeq1); ScopePacked psSeq2 = man->transcend->pack(scopeSeq2); ScopePacked psB = man->transcend->pack(scopeB); CFAPass* pass = new CFAPass(man); man->registerPass(pass, PassId::CFAPass); man->executePasses(); - const CFAGraph* report = dynamic_cast(man->getPassById(PassId::CFAPass))->getReport(); + const CFAGraph* report = dynamic_cast (man->getPassById(PassId::CFAPass))->getReport(); auto dependencies = report->__dependencyRelations; delete pass; ASSERT_EQ(1, dependencies.count(psSeq2)); ASSERT_EQ(1, dependencies.count(psB)); } -TEST(CFA, DependenciesChildScope){ +TEST(CFA, DependenciesChildScope) { details::tier2::XreateManager* man = details::tier2::XreateManager::prepare( - R"Code( + 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->transcend->pack(scopeSeq1); ScopePacked psSeq2 = man->transcend->pack(scopeSeq2); ScopePacked psIf1 = man->transcend->pack(scopeIf1); ScopePacked psIf2 = man->transcend->pack(scopeIf2); CFAPass* pass = new CFAPass(man); man->registerPass(pass, PassId::CFAPass); man->executePasses(); - const CFAGraph* report = dynamic_cast(man->getPassById(PassId::CFAPass))->getReport(); + const CFAGraph* report = dynamic_cast (man->getPassById(PassId::CFAPass))->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) - { + for(auto rec : dependencies) { std::cout << rec.first << " " << rec.second << std::endl; } } - -TEST(CFA, DomReportOneRoot){ +TEST(CFA, DomReportOneRoot) { std::string program = -R"CODE( + 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::CFAPass); pass->run(); ScopePacked scope1 = man->transcend->pack(man->root->findFunction("a")->getEntryScope()->getBody().blocks.front()); ScopePacked scope2 = man->transcend->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 expectedFDom = { + {1, + {0, 3}} + , + {2, + {1, 2}} }; - dominators::DominatorsTreeAnalysisProvider::Dominators expectedPostDom= { - {2, {0, 3}} - ,{1, {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; } + +TEST(CFA, ASTCorrespondence_Scope_Bindings_1){ + std::string program = +R"CODE( + test = function(x::int, y::int):: int; entry{ + x + y + } +)CODE"; + + std::unique_ptr man(details::tier2::XreateManager::prepare(move(program))); + CFAPass* pass = new CFAPass(man.get()); + man->registerPass(pass, PassId::CFAPass); + man->executePasses(); + + testing::internal::CaptureStdout(); + man->analyse(); + std::string outputActual = testing::internal::GetCapturedStdout(); + cout << outputActual << endl; + + string outputExpected = "ast_scope_binding(0,0,\"x\")"; + ASSERT_NE(std::string::npos, outputActual.find(outputExpected)); + + outputExpected = "ast_scope_binding(0,1,\"y\")"; + ASSERT_NE(std::string::npos, outputActual.find(outputExpected)); +} diff --git a/cpp/tests/interpretation.cpp b/cpp/tests/interpretation.cpp index 336f58d..516fc7f 100644 --- a/cpp/tests/interpretation.cpp +++ b/cpp/tests/interpretation.cpp @@ -1,531 +1,532 @@ /* Any copyright is dedicated to the Public Domain. * http://creativecommons.org/publicdomain/zero/1.0/ * * interpretation.cpp * * Created on: - * Author: pgess */ #include "attachments.h" using namespace xreate; #include "xreatemanager.h" #include "compilation/targetinterpretation.h" +#include "analysis/interpretation.h" #include "gtest/gtest.h" #include "boost/scoped_ptr.hpp" //#define FRIENDS_INTERPRETATION_TESTS \ // friend class ::Modules_AST2_Test; \ // friend class ::Modules_Discovery1_Test; \ // friend class ::Modules_Solve1_Test; #include "pass/interpretationpass.h" using namespace xreate::grammar::main; using namespace xreate::interpretation; TEST(Interpretation, Analysis_StatementIF_1){ XreateManager* man = XreateManager::prepare( R"Code( main = function::bool { x = "a":: string. y = if (x=="b"):: bool; interpretation(force) { true } else { false }. y } )Code" ); InterpretationPass* pass = new InterpretationPass(man); pass->run(); CodeScope* scopeEntry = man->root->findFunction("main")->getEntryScope(); Symbol symbolY{scopeEntry->getSymbol("y"), scopeEntry}; InterpretationData& dataSymbolY = Attachments::get(symbolY); ASSERT_EQ(INTR_ONLY, dataSymbolY.resolution); } TEST(Interpretation, Compilation_StatementIF_1){ xreate::details::tier1::XreateManager* man = xreate::details::tier1::XreateManager::prepare( R"Code( main = function::int; entry { x = "a":: string. y = if (x=="b"):: string; interpretation(force) { 1 } else { 0 }. y } )Code" ); man->analyse(); InterpretationPass* pass; if (man->isPassRegistered(PassId::InterpretationPass)){ pass = (InterpretationPass*) man->getPassById(PassId::InterpretationPass); } else { pass = new InterpretationPass(man); pass->run(); } int (*main)() = (int (*)())man->run(); int result = main(); ASSERT_EQ(0, result); } TEST(Interpretation, Analysis_StatementIF_InterpretCondition_1){ XreateManager* man = XreateManager::prepare( R"Code( main = function(x:: int):: int { comm= "inc":: string; interpretation(force). y = if (comm == "inc")::int {x+1} else {x}. y } )Code" ); InterpretationPass* pass = new InterpretationPass(man); pass->run(); CodeScope* scopeEntry = man->root->findFunction("main")->getEntryScope(); Symbol symbolY{scopeEntry->getSymbol("y"), scopeEntry}; InterpretationData& dataSymbolY = Attachments::get(symbolY); ASSERT_EQ(CMPL_ONLY, dataSymbolY.resolution); ASSERT_EQ(IF_INTERPRET_CONDITION, dataSymbolY.op); } TEST(Interpretation, Compilation_StatementIF_InterpretCondition_1){ xreate::details::tier1::XreateManager* man = xreate::details::tier1::XreateManager::prepare( R"Code( main = function(x:: int):: int; entry { comm= "inc":: string; interpretation(force). y = if (comm == "inc")::int {x+1} else {x}. y } )Code" ); man->analyse(); InterpretationPass* pass; if (man->isPassRegistered(PassId::InterpretationPass)){ pass = (InterpretationPass*) man->getPassById(PassId::InterpretationPass); } else { pass = new InterpretationPass(man); pass->run(); } int (*main)(int) = (int (*)(int))man->run(); int result = main(1); ASSERT_EQ(2, result); } TEST(Interpretation, Compilation_StatementFOLD_INTERPRET_INPUT_1){ xreate::details::tier1::XreateManager* man = xreate::details::tier1::XreateManager::prepare( R"Code( main = function(x:: int):: int; entry { commands = ["inc", "double", "dec"]:: [string]; interpretation(force). loop fold(commands->comm::string, x->operand):: int{ switch(comm)::int case ("inc"){ operand + 1 } case ("dec"){ operand - 1 } case ("double"){ operand * 2 } } } )Code" ); man->analyse(); InterpretationPass* pass; if (man->isPassRegistered(PassId::InterpretationPass)){ pass = (InterpretationPass*) man->getPassById(PassId::InterpretationPass); } else { pass = new InterpretationPass(man); pass->run(); } const ManagedFnPtr& funcMain = man->root->findFunction("main"); InterpretationData& dataBody = Attachments::get(funcMain); ASSERT_EQ(FOLD_INTERPRET_INPUT, dataBody.op); int (*main)(int) = (int (*)(int))man->run(); int result = main(10); ASSERT_EQ(21, result); } TEST(Interpretation, StatementCall_RecursionNo_1){ xreate::details::tier1::XreateManager* man = xreate::details::tier1::XreateManager::prepare( R"Code( unwrap = function(data::unknType, keys::unknType):: unknType; interpretation(force){ loop fold(keys->key::string, data->a):: unknType { a[key] } } start = function::num; entry{ result = unwrap( { a = { b = { c = "core" } } }, ["a", "b", "c"])::unknType. result == "core" } )Code" ); man->analyse(); InterpretationPass* pass; if (man->isPassRegistered(PassId::InterpretationPass)){ pass = (InterpretationPass*) man->getPassById(PassId::InterpretationPass); } else { pass = new InterpretationPass(man); pass->run(); } int (*main)() = (int (*)())man->run(); int result = main(); ASSERT_EQ(1, result); } TEST(Interpretation, StatementCall_RecursionDirect_1){ xreate::details::tier1::XreateManager* man = xreate::details::tier1::XreateManager::prepare( R"Code( unwrap = function(data:: X):: Y { if (data[0] == "a")::Y {0} else {unwrap(data[0])} } entry = function:: i8; entry { unwrap([[[["a"]]]]):: i8; interpretation(force) } )Code" ); man->analyse(); InterpretationPass* pass; if (man->isPassRegistered(PassId::InterpretationPass)){ pass = (InterpretationPass*) man->getPassById(PassId::InterpretationPass); } else { pass = new InterpretationPass(man); pass->run(); } InterpretationResolution resolutionActual = pass->process(man->root->findFunction("unwrap")); ASSERT_EQ(ANY, resolutionActual); int (*main)() = (int (*)())man->run(); int result = main(); ASSERT_EQ(0, result); } TEST(Interpretation, StatementCall_RecursionIndirect_1){ XreateManager* man = XreateManager::prepare( R"Code( funcA = function(data:: X):: Y { if (data == "a")::Y {0} else {funcB(data)} } funcB = function(data:: X):: Y { if (data == "b")::Y {1} else {funcA(data)} } entry = function:: i8; entry { funcA(""):: i8; interpretation(force) } )Code" ); InterpretationPass* pass = new InterpretationPass(man); ASSERT_DEATH(pass->run(), "Indirect recursion detected"); } TEST(Interpretation, PartialIntr_1){ XreateManager* man = XreateManager::prepare( R"Code( evaluate= function(argument:: num, code:: string; interpretation(force)):: num { switch(code)::int case ("inc") {argument + 1} case ("dec") {argument - 1} case ("double") {argument * 2} } main = function::int; entry { commands= ["inc", "double", "dec"]:: [string]; interpretation(force). loop fold(commands->comm::string, 10->operand):: int{ evaluate(operand, comm) } } )Code" ); InterpretationPass* pass = new InterpretationPass(man); pass->run(); ManagedFnPtr fnEvaluate = man->root->findFunction("evaluate"); InterpretationResolution resFnEvaluate= pass->process(fnEvaluate); ASSERT_EQ(CMPL_ONLY, resFnEvaluate); ASSERT_TRUE(FunctionInterpretationHelper::needPartialInterpretation(fnEvaluate)); const Expression& exprLoop = man->root->findFunction("main")->__entry->getBody(); Symbol symbCallEv{{0, versions::VERSION_NONE}, exprLoop.blocks.front()}; InterpretationData dataCallEv = Attachments::get(symbCallEv); ASSERT_EQ(CMPL_ONLY, dataCallEv.resolution); ASSERT_EQ(CALL_INTERPRET_PARTIAL, dataCallEv.op); } TEST(Interpretation, Compilation_PartialIntr_2){ xreate::details::tier1::XreateManager* man = xreate::details::tier1::XreateManager::prepare( R"Code( evaluate= function(argument:: num, code:: string; interpretation(force)):: num { switch(code)::int case ("inc") {argument + 1} case ("dec") {argument - 1} case ("double") {argument * 2} case default {argument} } main = function::int; entry { commands= ["inc", "double", "dec"]:: [string]; interpretation(force). loop fold(commands->comm::string, 10->operand):: int{ evaluate(operand, comm) } } )Code" ); man->analyse(); if (!man->isPassRegistered(PassId::InterpretationPass)){ InterpretationPass* pass = new InterpretationPass(man); pass->run(); } int (*main)() = (int (*)())man->run(); int result = main(); ASSERT_EQ(21, result); } TEST(Interpretation, PartialIntr_3){ xreate::details::tier1::XreateManager* man = xreate::details::tier1::XreateManager::prepare( R"Code( Command= type variant {INC, DEC, DOUBLE}. evaluate= function(argument:: num, code:: Command; interpretation(force)):: num { switch variant(code)::int case (INC) {argument + 1} case (DEC) {argument - 1} case (DOUBLE) {argument * 2} } main = function::int; entry { commands= [INC(), DOUBLE(), DEC()]:: [Command]; interpretation(force). loop fold(commands->comm::Command, 10->operand):: int{ evaluate(operand, comm) } } )Code" ); man->analyse(); if (!man->isPassRegistered(PassId::InterpretationPass)){ InterpretationPass* pass = new InterpretationPass(man); pass->run(); } int (*main)() = (int (*)())man->run(); int result = main(); ASSERT_EQ(21, result); } TEST(Interpretation, PartialIntr_4){ xreate::details::tier1::XreateManager* man = xreate::details::tier1::XreateManager::prepare( R"Code( Command= type variant {INC, DEC, DOUBLE}. evaluate= function(argument:: num, code:: Command; interpretation(force)):: num { switch variant(code)::num case (INC) {argument + 1} case (DEC) {argument - 1} case (DOUBLE) {argument * 2} } main = function::int; entry { evaluate(4, DEC()) } )Code" ); man->analyse(); if (!man->isPassRegistered(PassId::InterpretationPass)){ InterpretationPass* pass = new InterpretationPass(man); pass->run(); } int (*main)() = (int (*)())man->run(); int result = main(); ASSERT_EQ(3, result); } TEST(Interpretation, SwitchVariant){ xreate::XreateManager* man = xreate::XreateManager::prepare( R"Code( OneArgument = type{x::int}. TWoArgument = type {x::int, y::int}. Command= type variant { ADD::TwoArguments, DEC:: OneArgument, DOUBLE::OneArgument }. main = function::int; entry{ program = ADD({x=2, y=3})::Command; interpretation(force). switch variant(program)::int case (ADD) {program["x"]+program["y"]} case (DEC) {1} case (DOUBLE) {2} } )Code" ); int (*main)() = (int (*)())man->run(); int result = main(); ASSERT_EQ(5, result); } TEST(Interpretation, SwitchVariantAlias){ xreate::XreateManager* man = xreate::XreateManager::prepare( R"Code( OneArgument = type{x::int}. TWoArgument = type {x::int, y::int}. Command= type variant { ADD::TwoArguments, DEC:: OneArgument, DOUBLE::OneArgument }. main = function::int; entry{ program = [ADD({x=2, y=3}), DEC({x=8})]::[Command]; interpretation(force). switch variant(program[0]->program::Command)::int case (ADD) {program["x"]+program["y"]} case (DEC) {1} case (DOUBLE) {2} } )Code" ); int (*main)() = (int (*)())man->run(); int result = main(); ASSERT_EQ(5, result); } TEST(Interpretation, Multiindex1){ std::string script2= R"Code( extract = function(program::unknType)::int; interpretation(force){ program["arguments"][1] } main = function::int; entry { x = {arguments = [10, 9, 8, 7]}:: unknType; interpretation(force). extract(x) } )Code"; std::unique_ptr man(XreateManager::prepare(std::move(script2))); int (*main)() = (int (*)())man->run(); int result = main(); ASSERT_EQ(9, result); } TEST(InterpretationExamples, Regexp1){ FILE* input = fopen("scripts/dsl/regexp.xreate","r"); assert(input != nullptr); std::unique_ptr man(XreateManager::prepare(input)); int (*main)() = (int (*)())man->run(); int result = main(); ASSERT_EQ(4, result); } TEST(Interpretation, Variant1){ std::string script= R"Code( Data = type {Num:: [int], String::string}. DataPacked = type variant { Var1:: Data, Var2:: Data }. extractInt = function(data::DataPacked):: int { resultWrong = 0 :: int. switch variant(data)::int case (Var1) {data["Num", 0]} case (Var2) {resultWrong} } main = function :: int; entry { dataActual = 10. dataPacked = Var1({Num = [dataActual], String = "whatever"}):: DataPacked. extractInt(dataPacked):: int; interpretation(force) } )Code"; std::unique_ptr man(XreateManager::prepare(std::move(script))); int (*main)() = (int (*)())man->run(); int result = main(); ASSERT_EQ(10, result); } //TOTEST call indirect recursion(w/o tags) //TASk implement and test Loop Inf (fix acc types in coco grammar) diff --git a/cpp/tests/latereasoning.cpp b/cpp/tests/latereasoning.cpp index 7f307c1..fbe8b45 100644 --- a/cpp/tests/latereasoning.cpp +++ b/cpp/tests/latereasoning.cpp @@ -1,215 +1,184 @@ /* 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 "transcendlayer.h" #include "pass/latereasoningpass.h" #include "aux/latereasoning.h" #include "pass/dfapass.h" #include #include "gtest/gtest.h" +using namespace std; using namespace xreate; using namespace xreate::latereasoning; -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() - typedef LateReasoningTranscendDecorator LRTranscend; - - Attachments::init(); - Attachments::init(); - std::unique_ptr transcend(new LRTranscend()); - - 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 = transcend->pack(symbA, "a"); - SymbolPacked symbpB = transcend->pack(symbB, "b"); - SymbolPacked symbpC = transcend->pack(symbC, "c"); - SymbolPacked symbpTarget = transcend->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 - transcend->addRawScript((formatLateAnnotation - % FORMATSYMBOL(symbpTarget) - % FORMATSYMBOL(symbpA) % FORMATSYMBOL(symbpB) % FORMATSYMBOL(symbpC) - % "guard1" % "guard1" % "guard1" - % "result(variant1)" - ). str()); - - //Add `result2` variant - transcend->addRawScript((formatLateAnnotation - % FORMATSYMBOL(symbpTarget) - % FORMATSYMBOL(symbpA) % FORMATSYMBOL(symbpB) % FORMATSYMBOL(symbpC) - % "guard2" % "guard2" % "guard2" - % "result(variant2)" - ). str()); - - transcend->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 - StaticModel answer = transcend->queryLate("result", symbpTarget); - ASSERT_EQ(1, answer.size()); - - std::tuple answerParsed = transcend->parse(answer.begin()->second); - - ASSERT_STREQ("variant2", std::get<0>(answerParsed).c_str()); -} - TEST(LateReasoning, Syntax1) { XreateManager* man = XreateManager::prepare(R"Code( test = function:: int { x = 0::int. y1= switch late (x)::int{0}. y2= switch late(x+y1->a::int)::int{1}. y1+y2 } )Code"); CodeScope* scope = man->root->findFunction("test")->getEntryScope(); Expression y1 = scope->getDefinition(scope->getSymbol("y1")); Expression y2 = scope->getDefinition(scope->getSymbol("y2")); ASSERT_EQ(1, y1.bindings.size()); ASSERT_STRCASEEQ("x", y1.bindings.at(0).c_str()); ASSERT_EQ(1, y2.bindings.size()); ASSERT_STRCASEEQ("a", y2.bindings.at(0).c_str()); } -TEST(LateReasoning, Compilation1){ - XreateManager* man = XreateManager::prepare(R"Code( -Color = type variant{RED, BLUE, GREEN}. - -test = function:: int; entry { - x = RED():: Color. - y1= switch late (x):: int - {0}. - y1 -} -)Code"); - - int (*program)() = (int (*)())man->run(); - int result = program(); - - ASSERT_EQ(0, result); -} - -TEST(LateReasoning, LateVariablesRecognition1){ +TEST(LateReasoning, Pass_DFAPassDec_1){ typedef LateReasoningTranscendDecorator LRTranscend; auto man = details::tier2::XreateManager::prepare(R"Code( Dom = type slave dom. test = function:: int; entry { LateIdent = 0:: Dom. 0:: int; ann1(LateIdent) } )Code"); CodeScope* scopeEntry = man->root->findFunction("test")->getEntryScope(); ScopedSymbol keyS = scopeEntry->getSymbol("LateIdent"); SymbolPacked keySP = man->transcend->pack(Symbol{keyS, scopeEntry}); std::shared_ptr scopeLateEntry(new LateReasoningScope(nullptr)); scopeLateEntry->addIdentifier("LateIdent", keySP); - //Pass information to the late scope typedef LateReasoningDFAPassDecorator LRDFAPass; LRDFAPass* dfaPass = new LRDFAPass(man); dfaPass->registerLateScope(scopeEntry, scopeLateEntry.get()); - //Pass information to the late model - Attachments::init(); man->transcend->addRawScript("dom(guard1; guard2).\n"); - Attachments::put(Symbol{keyS, scopeEntry}, Expression(Operator::CALL, {Atom("guard1")})); - + man->registerPass(dfaPass, PassId::DFAPass, nullptr); man->executePasses(); + + testing::internal::CaptureStdout(); man->analyse(); + std::string outputActual = testing::internal::GetCapturedStdout(); + cout << outputActual << endl; + + string outputExpected = "late(s(0,-2,0), (s(1,-2,0)), (LateIdent), ann1(LateIdent)):- dom(LateIdent)."; + ASSERT_NE(std::string::npos, outputActual.find(outputExpected)); +} - //Fetch late annotation - LRTranscend* transcend = dynamic_cast(man->transcend); - SymbolPacked targetSymP = transcend->pack(Symbol{ScopedSymbol::RetSymbol, scopeEntry}); - StaticModel solution = transcend->queryLate("ann1", targetSymP); - ASSERT_EQ(1, solution.size()); +TEST(LateReasoning, Transcend_LRTransDec_1) { + Attachments::init(); + typedef LateReasoningTranscendDecorator LRTranscend; + std::unique_ptr transcend(new LRTranscend()); + + 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 symbTarget1 = scope->addDefinition(Atom("target1"), Expression()); + Symbol symbTarget2 = scope->addDefinition(Atom("target2"), Expression()); - std::tuple solutionParsed = man->transcend->parse(solution.begin()->second); - ASSERT_STREQ("guard1", std::get<0>(solutionParsed).c_str()); -} + SymbolPacked symbpA = transcend->pack(symbA, "a"); + SymbolPacked symbpB = transcend->pack(symbB, "b"); + SymbolPacked symbpC = transcend->pack(symbC, "c"); + SymbolPacked symbTarget1P = transcend->pack(symbTarget1, "target1"); + SymbolPacked symbTarget2P = transcend->pack(symbTarget2, "target2"); -TEST(LateReasoning, Compilation2){ - auto man = details::tier1::XreateManager::prepare(R"Code( - DomLow = type variant {guard1, guard2}. - Dom = type slave dom. + boost::format formatSymb("s(%1%,%2%,%3%)"); + boost::format formatLateAnnotation1("late(%1%, (%2%, %3%, %4%), (%5%, %6%, %7%), %8%)."); + boost::format formatLateAnnotation2("late(%1%, (%2%, %3%), (%4%, %5%), %6%)."); + #define FORMATSYMBOL(s) (formatSymb % s.identifier % s.version % s.scope).str() - guard:: guard1 { - compute = function :: int - {0} - } + // Ann1, `variant1` + transcend->addRawScript((formatLateAnnotation1 + % FORMATSYMBOL(symbTarget1P) + % FORMATSYMBOL(symbpA) % FORMATSYMBOL(symbpB) % FORMATSYMBOL(symbpC) + % "guard1" % "guard1" % "guard1" + % "result(variant1)" + ). str()); - guard:: guard2 { - compute = function :: int - {1} + //Ann1 `result2` variant + transcend->addRawScript((formatLateAnnotation1 + % FORMATSYMBOL(symbTarget1P) + % FORMATSYMBOL(symbpA) % FORMATSYMBOL(symbpB) % FORMATSYMBOL(symbpC) + % "guard2" % "guard2" % "guard2" + % "result(variant2)" + ). str()); + + //Ann2 `result3` variant + transcend->addRawScript((formatLateAnnotation2 + % FORMATSYMBOL(symbTarget2P) + % FORMATSYMBOL(symbpA) % FORMATSYMBOL(symbpB) + % "guard3" % "guard3" + % "result(variant3)" + ). str()); + + transcend->run(); + LateAnnotationsGroup group = transcend->queryLate("result"); + ASSERT_EQ(2, group.annotations.size()); + + for(const auto& annEntry: group.annotations){ + annEntry.first.print(cout); + cout <(transcend->parse(targetWrapped)); + if (targetSP == symbTarget1P){ + LateAnnotation ann = annEntry.second; + ASSERT_EQ(2, ann.guardedContent.size()); + + Expression selector(Operator::CALL, {Atom("guard2")}); + auto answer = ann.select({selector, selector, selector}man->root, man->transcend); + ASSERT_TRUE(answer); + string answerS = get<0>(transcend->parse(*answer)); + ASSERT_STREQ("variant2", answerS.c_str()); + + } else if (targetSP == symbTarget2P) { + LateAnnotation ann = annEntry.second; + ASSERT_EQ(1, ann.guardedContent.size()); + + Expression selector(Operator::CALL, {Atom("guard3")}); + auto answer = ann.select({selector, selector, selector}); + ASSERT_TRUE(answer); + ASSERT_STREQ("variant3", get<0>(transcend->parse(*answer)).c_str()); + + } else { + ASSERT_TRUE(false); } + } +} + +TEST(LateReasoning, Compilation1){ + XreateManager* man = XreateManager::prepare(R"Code( +Color = type variant{RED, BLUE, GREEN}. + +test = function:: int; entry { + x = RED():: Color. + y1= switch late (x):: int + {0}. + y1 +} +)Code"); - test = function:: int; entry - { - xLate = guard2():: DomLow. - y1= switch late ((xLate::Dom):: Dom; alias(xLate)):: int - { - compute():: int; guardkey(xLate) - }. - y1 - } - )Code"); - - man->transcend->addRawScript(R"RAW( - dom(guard1; guard2). - late(Target, Key, Variant, dfa_callguard(Variant)):- - bind(Target, guardkey(Alias)); - bind(Key, alias(Alias)); - dom(Variant). - )RAW"); - man->analyse(); int (*program)() = (int (*)())man->run(); int result = program(); - ASSERT_EQ(1, result); + ASSERT_EQ(0, result); } + + diff --git a/cpp/tests/latex.cpp b/cpp/tests/latex.cpp index 4148fe8..54ceff8 100644 --- a/cpp/tests/latex.cpp +++ b/cpp/tests/latex.cpp @@ -1,201 +1,298 @@ /* Any copyright is dedicated to the Public Domain. * http://creativecommons.org/publicdomain/zero/1.0/ * * Author: pgess * Created on June 25, 2018, 5:42 PM * * \file latex.cpp * \brief Testing of latex */ #include "xreatemanager.h" #include "pass/compilepass.h" #include "transcendlayer.h" +#include "query/latex.h" #include "compilation/latex.h" #include "aux/xreatemanager-decorators.h" #include "compilation/scopedecorators.h" #include "llvmlayer.h" #include #include using namespace xreate::latex; +using namespace xreate::latereasoning; using namespace xreate::compilation; using namespace xreate; using namespace std; -TEST(Latex, Analysis1) { +TEST(Latex, Script_NestedScopePropagation_1) { + std::string program = + R"CODE( + import raw("scripts/cfa/context.lp"). + fn = function:: int; entry + { + context:: test1. + if(1==11)::int {2} else {3} + } + )CODE"; + + std::unique_ptr man(details::tier1::XreateManager::prepare(move(program))); + + CodeScope* blockTrue = man->root->findFunction("fn")->getEntryScope()->getBody().blocks.front(); + auto blockTrueP = man->transcend->pack(blockTrue); + boost::format formatAlias("alias(%1%, %2%)."); + man->transcend->addRawScript((formatAlias % blockTrueP % "block1").str()); + man->transcend->addRawScript( + R"SCRIPT( + success1:- bind_scope(Block1, test1, strong); alias(Block1, block1). + )SCRIPT"); + man->analyse(); + + ASSERT_EQ(1, man->transcend->query("success1").size()); +} + +TEST(Latex, Script_DemAndDecision_1) { std::string program = R"CODE( import raw("scripts/cfa/context.lp"). a = function:: int { context:: forC(a). c() } b = function:: int { context:: forC(b). c() } c = function:: int {0} main = function:: int; entry { a() + b() } )CODE"; std::unique_ptr man(details::tier1::XreateManager::prepare(move(program))); CodeScope* blockC = man->root->findFunction("c")->getEntryScope(); auto blockCP = man->transcend->pack(blockC); boost::format formatAlias("alias(%1%, %2%)."); man->transcend->addRawScript((formatAlias % blockCP % "blockC").str()); man->transcend->addRawScript( R"SCRIPT( latex_scope_demand(BlockC, forC):- alias(BlockC, blockC). latex_registered_subjects(forC, Variant):- bind_scope(_, Variant, strong); Variant = forC(_). )SCRIPT"); man->analyse(); ASSERT_EQ(1, man->transcend->query("latex_fn_demand").size()); ASSERT_EQ(2, man->transcend->query("latex_decision").size()); } -TEST(Latex, Compilation1) { +TEST(Latex, LatexQuery_getFnDemand_1){ std::string program = R"CODE( - - a = function:: int - {0} - + import raw("scripts/cfa/context.lp"). main = function:: int; entry { - a() + context:: alias(blockMain). + 0 } )CODE"; - - string script = + + std::unique_ptr man(details::tier1::XreateManager::prepare(move(program))); + man->transcend->addRawScript( R"SCRIPT( - latex_fn_demand(%1%, subject1). - latex_decision(%2%, subject1, 5). - latex_registered_subjects(subject1, 1). - latex_registered_subjects(subject1, 5). - )SCRIPT"; - - typedef LatexBruteFunctionDecorator FnImpl; - typedef LatexBruteScopeDecorator> ScopeImpl; + latex_scope_demand(BlockC, forC):- bind_scope(BlockC, alias(blockMain), strong). + latex_registered_subjects(forC, decisionSome). + )SCRIPT"); + + LatexQuery* query = new LatexQuery(); + man->transcend->registerQuery(query, QueryId::LatexQuery); + man->analyse(); + + Demand demand = query->getFnDemand("main"); + ASSERT_EQ(1, demand.size()); + ASSERT_STREQ("forC", demand.front().c_str()); +} +TEST(Latex, LatexQuery_getDecision_static_1){ + std::string program = + R"CODE( + import raw("scripts/cfa/context.lp"). + a = function:: int {context::decisionSome. c()} + b = function:: int {c()} + c = function:: int {context:: alias(blockC). 0} + )CODE"; + std::unique_ptr man(details::tier1::XreateManager::prepare(move(program))); - ScopePacked scopeMainP = man->transcend->pack(man->root->findFunction("main")->getEntryScope()); - boost::format format(script); - man->transcend->addRawScript((format % "a" % scopeMainP).str()); - man->transcend->registerQuery(new LatexQuery(), QueryId::LatexQuery); + man->transcend->addRawScript( + R"SCRIPT( + latex_scope_demand(BlockC, forC):- bind_scope(BlockC, alias(blockC), strong). + latex_registered_subjects(forC, decisionSome). + )SCRIPT"); + + LatexQuery* query = new LatexQuery(); + man->transcend->registerQuery(query, QueryId::LatexQuery); man->analyse(); - - std::unique_ptr compiler(new compilation::CompilePassCustomDecorators(man.get())); - compiler->run(); - man->llvm->print(); + + LateAnnotation decisionLA = query->getDecision("forC", man->root->findFunction("a")->getEntryScope()); + auto decisionGS = decisionLA.select({}, man->root, man->transcend); + ASSERT_TRUE(decisionGS); + + decisionGS->print(cout); + cout << endl; + auto decisionTuple = man->transcend->parse(*decisionGS); + string decision = get<2>(decisionTuple); + ASSERT_STREQ("decisionSome", decision.c_str()); } - -TEST(Latex, Full1) { + +TEST(Latex, Compilation_1) { std::string program = R"CODE( - import raw("scripts/cfa/context.lp"). - a = function:: int - { - context:: forC(a). - c() - } - - b = function:: int - { - context:: forC(b). - c() - } - - c = function:: int {0} + a = function:: int + {0} - main = function:: int; entry - { - a() + b() - } + main = function:: int; entry + { + a() + } )CODE"; string script = R"SCRIPT( - alias(%1%, scopeC). - latex_scope_demand(ScopeC, forC) :- alias(ScopeC, scopeC). - latex_registered_subjects(forC, forC(a)). - latex_registered_subjects(forC, forC(b)). + latex_fn_demand(%1%, subject1). + latex_decision(%2%, subject1, 5). + latex_registered_subjects(subject1, 1). + latex_registered_subjects(subject1, 5). )SCRIPT"; typedef LatexBruteFunctionDecorator FnImpl; typedef LatexBruteScopeDecorator> ScopeImpl; std::unique_ptr man(details::tier1::XreateManager::prepare(move(program))); ScopePacked scopeMainP = man->transcend->pack(man->root->findFunction("main")->getEntryScope()); - auto scopeCP = man->transcend->pack(man->root->findFunction("c")->getEntryScope()); boost::format format(script); - man->transcend->addRawScript((format %scopeCP).str()); + man->transcend->addRawScript((format % "a" % scopeMainP).str()); man->transcend->registerQuery(new LatexQuery(), QueryId::LatexQuery); man->analyse(); std::unique_ptr compiler(new compilation::CompilePassCustomDecorators(man.get())); compiler->run(); - man->llvm->print(); + man->llvm->initJit(); + int(*fnMain)() = (int(*)())man->llvm->getFunctionPointer(compiler->getEntryFunction()); + ASSERT_EQ(0, fnMain()); } -TEST(Latex, TransitFn1){ +// +//TEST(Latex, Full1) { +// std::string program = +// R"CODE( +// import raw("scripts/cfa/context.lp"). +// +// a = function:: int +// { +// context:: forC(a). +// c() +// } +// +// b = function:: int +// { +// context:: forC(b). +// c() +// } +// +// c = function:: int {0} +// +// main = function:: int; entry +// { +// a() + b() +// } +// )CODE"; +// +// string script = +// R"SCRIPT( +// alias(%1%, scopeC). +// latex_scope_demand(ScopeC, forC) :- alias(ScopeC, scopeC). +// latex_registered_subjects(forC, forC(a)). +// latex_registered_subjects(forC, forC(b)). +// )SCRIPT"; +// +// typedef LatexBruteFunctionDecorator FnImpl; +// typedef LatexBruteScopeDecorator> ScopeImpl; +// +// std::unique_ptr man(details::tier1::XreateManager::prepare(move(program))); +// ScopePacked scopeMainP = man->transcend->pack(man->root->findFunction("main")->getEntryScope()); +// auto scopeCP = man->transcend->pack(man->root->findFunction("c")->getEntryScope()); +// boost::format format(script); +// man->transcend->addRawScript((format %scopeCP).str()); +// man->transcend->registerQuery(new LatexQuery(), QueryId::LatexQuery); +// man->analyse(); +// +// std::unique_ptr compiler(new compilation::CompilePassCustomDecorators(man.get())); +// compiler->run(); +// man->llvm->print(); +//} +// +TEST(Latex, Compilation_TransitFn1){ std::string program = R"CODE( import raw("scripts/cfa/context.lp"). branchA = function:: int { - context:: sink(a). + context:: sink_a. fnTransit() } branchB = function:: int { - context:: sink(b). + context:: sink_b. fnTransit() } fnSink = function:: int {0} fnTransit = function:: int {fnSink()} main = function:: int; entry { branchA() + branchB() } )CODE"; string script = - R"SCRIPT( - alias(scopeSink, %1%). - latex_scope_demand(ScopeSink, sink):- alias(scopeSink, ScopeSink). - latex_registered_subjects(sink, sink(a)). - latex_registered_subjects(sink, sink(b)). - )SCRIPT"; +R"SCRIPT( + alias(scopeSink, %1%). + latex_scope_demand(ScopeSink, sink):- alias(scopeSink, ScopeSink). + latex_registered_subjects(sink, sink_a). + latex_registered_subjects(sink, sink_b). +)SCRIPT"; typedef LatexBruteFunctionDecorator FnImpl; typedef LatexBruteScopeDecorator> ScopeImpl; std::unique_ptr man(details::tier1::XreateManager::prepare(move(program))); - auto scopeSinkP = man->transcend->pack(man->root->findFunction("fnSink")->getEntryScope()); + CodeScope* scopeSink = man->root->findFunction("fnSink")->getEntryScope(); + auto scopeSinkP = man->transcend->pack(scopeSink); + ScopedSymbol argLatexSS{1, -1}; + Symbol argLatexS{argLatexSS, scopeSink}; + man->transcend->pack(argLatexS); boost::format format(script); man->transcend->addRawScript((format %scopeSinkP).str()); man->transcend->registerQuery(new LatexQuery(), QueryId::LatexQuery); man->analyse(); std::unique_ptr compiler(new compilation::CompilePassCustomDecorators(man.get())); compiler->run(); man->llvm->print(); + man->llvm->initJit(); + int(*fnMain)() = (int(*)()) man->llvm->getFunctionPointer(compiler->getEntryFunction()); + int valueActual = fnMain(); + ASSERT_EQ(0, valueActual); } \ No newline at end of file diff --git a/cpp/tests/polymorph.cpp b/cpp/tests/polymorph.cpp index 9dd13f5..d1b0b8c 100644 --- a/cpp/tests/polymorph.cpp +++ b/cpp/tests/polymorph.cpp @@ -1,108 +1,146 @@ /* Any copyright is dedicated to the Public Domain. * http://creativecommons.org/publicdomain/zero/1.0/ * * polymorph.cpp * * Author: pgess * Created on October 11, 2017, 8:37 PM */ #include "xreatemanager.h" #include "ast.h" #include "transcendlayer.h" #include "aux/latereasoning.h" #include #include "gtest/gtest.h" +#include "query/polymorph.h" using namespace xreate; using namespace xreate::latereasoning; +using namespace xreate::polymorph; using namespace std; TEST(Polymorphs, ast1) { xreate::XreateManager* man = xreate::XreateManager::prepare( -R"CODE( + R"CODE( guard:: a { test = function:: int {0} } guard:: b { test = function:: int {1} } main = function:: int; entry { test() } )CODE"); const std::list& specs = man->root->getFunctionSpecializations("test"); ASSERT_EQ(2, specs.size()); auto itSpecs = specs.begin(); ASSERT_EQ("a", (*itSpecs)->guard.getValueString()); itSpecs++; ASSERT_EQ("b", (*itSpecs)->guard.getValueString()); } -TEST(Polymorphs, StaticCall1) { +TEST(Polymorphs, PolymorphQuery_Static_1) { xreate::details::tier1::XreateManager* man = xreate::details::tier1::XreateManager::prepare( -R"CODE( + R"CODE( import raw("scripts/dfa/polymorphism.lp"). guard:: a { test = function:: int {0} } guard:: b { test = function:: int {1} } - main = function:: int; entry { test()::int; callguard(b);dfa_polym(ret)} + main = function:: int; entry { test()::int; callguard(b); dfa_polym(ret)} )CODE"); man->analyse(); - int (*main)() = (int (*)()) man->run(); - - ASSERT_EQ(1, main()); + PolymorphQuery* query = dynamic_cast (man->transcend->getQuery(QueryId::PolymorphQuery)); + + const Expression& bodyE = man->root->findFunction("main")->getEntryScope()->getBody(); + LateAnnotation decisionLA = query->get(bodyE); + ASSERT_EQ(1, decisionLA.guardedContent.size()); + + auto decisionOptSymb = decisionLA.select({}, man->root, man->transcend); + ASSERT_TRUE(decisionOptSymb); + + decisionOptSymb->print(cout); + cout << endl; + string guard = query->getValue(*decisionOptSymb).getValueString(); + ASSERT_STREQ("b", guard.c_str()); } -TEST(Polymorphs, LateCall1){ - Attachments::init(); - +TEST(Polymorphs, PolymorphQuery_Late_1){ xreate::details::tier1::XreateManager* man = xreate::details::tier1::XreateManager::prepare( R"CODE( - guard:: a { - test = function:: int {0} - } - - guard:: b { - test = function:: int {1} - } - - main = function:: int; entry{ - key = 0:: int; _guard. - if (key == 0)::int { - test()::int; dfa_polym(late) - } else {0} - } + main = function:: int; entry{key= 0:: int; test. key} )CODE"); man->transcend->addRawScript( R"RULE( - late(SymbRet, list(SymbGuard), list(a), dfa_callguard(a)):- - bind(SymbRet, dfa_polym(late)); - bind(SymbGuard, _guard). - - late(SymbRet, list(SymbGuard), list(b), dfa_callguard(b)):- - bind(SymbRet, dfa_polym(late)); - bind(SymbGuard, _guard). + late(S, S, a, dfa_callguard(S, a)):- + bind(S, test). + + late(S, S, b, dfa_callguard(S, b)):- + bind(S, test). )RULE"); man->analyse(); + PolymorphQuery* query = dynamic_cast (man->transcend->getQuery(QueryId::PolymorphQuery)); - CodeScope* scopeMainBody = man->root->findFunction("main")->getEntryScope(); - Symbol symbKey = Symbol{scopeMainBody->getSymbol("key"), scopeMainBody}; + CodeScope* scopeMain = man->root->findFunction("main")->getEntryScope(); + Symbol keyS = Symbol{scopeMain->getSymbol("key"), scopeMain}; - Attachments::put(symbKey, Expression(Operator::CALL, {Atom("b")})); - int (*main)() = (int (*)()) man->run(); - - ASSERT_EQ(1, main()); + Expression keyE = scopeMain->getDefinition(keyS); + latereasoning::LateAnnotation answerLA = query->get(keyE); + auto answerRaw = answerLA.select({Expression(Operator::CALL, {Atom("b")})}, man->root, man->transcend); + ASSERT_TRUE(answerRaw); + Expression answerE = query->getValue(*answerRaw); + ASSERT_STREQ("b", answerE.getValueString().c_str()); } + +TEST(Polymorphs, PSCU_1){ + auto man = details::tier1::XreateManager::prepare(R"Code( + DomLow = type variant {guard1, guard2}. + Dom = type slave dom. + + guard:: guard1 { + compute = function :: int + {0} + } + + guard:: guard2 { + compute = function :: int + {1} + } + + test = function:: int; entry + { + xLate = guard2():: DomLow. + y1= switch late ((xLate::Dom):: Dom; alias(xLate)):: int + { + compute():: int; guardkey(xLate) + }. + y1 + } + )Code"); + + man->transcend->addRawScript(R"RAW( + dom(guard1; guard2). + late(Target, Key, Variant, dfa_callguard(Target, Variant)):- + bind(Target, guardkey(Alias)); + bind(Key, alias(Alias)); + dom(Variant). + )RAW"); + man->analyse(); + int (*program)() = (int (*)())man->run(); + int result = program(); + + ASSERT_EQ(1, result); +} \ No newline at end of file diff --git a/cpp/tests/types.cpp b/cpp/tests/types.cpp index 5d3c9f5..d71319c 100644 --- a/cpp/tests/types.cpp +++ b/cpp/tests/types.cpp @@ -1,235 +1,236 @@ /* Any copyright is dedicated to the Public Domain. * http://creativecommons.org/publicdomain/zero/1.0/ * * types.cpp * * Created on: Jun 4, 2015 * Author: pgess */ #include "gtest/gtest.h" #include "xreatemanager.h" #include "llvmlayer.h" #include "main/Parser.h" #include "transcendlayer.h" #include "analysis/typeinference.h" +#include "analysis/interpretation.h" using namespace std; using namespace xreate; using namespace xreate::grammar::main; TEST(Types, DependantTypes1) { string&& code = "XmlNode = type {\n" - " tag:: string,\n" - " attrs:: [string], \n" - " content:: string\n" - "}.\n"; + " tag:: string,\n" + " attrs:: [string], \n" + " content:: string\n" + "}.\n"; std::unique_ptr program(XreateManager::prepare(move(code))); ExpandedType typeXmlNode = program->root->findType("XmlNode"); ASSERT_EQ(TypeOperator::LIST_NAMED, typeXmlNode->__operator); ASSERT_EQ(3, typeXmlNode->__operands.size()); ASSERT_EQ(TypePrimitive::String, typeXmlNode->__operands.at(0).__value); ASSERT_EQ(TypeOperator::LIST, typeXmlNode->__operands.at(1).__operator); ASSERT_EQ(TypePrimitive::String, typeXmlNode->__operands.at(2).__value); } TEST(Types, ast_ParameterizedTypes_FeatureTypeIndex_1) { string&& code = "XmlNode = type {\n" - " tag:: string,\n" - " attrs:: [string],\n" - " content:: string\n" - "}.\n" - "" - "Template = type(Leaf) {Leaf, [Leaf[content]]}." - "Concrete = type Template(XmlNode)."; + " tag:: string,\n" + " attrs:: [string],\n" + " content:: string\n" + "}.\n" + "" + "Template = type(Leaf) {Leaf, [Leaf[content]]}." + "Concrete = type Template(XmlNode)."; std::unique_ptr program(XreateManager::prepare(move(code))); ExpandedType typeConcrete = program->root->findType("Concrete"); ASSERT_EQ(TypeOperator::LIST_NAMED, typeConcrete->__operator); ASSERT_EQ(2, typeConcrete->__operands.size()); ASSERT_EQ(TypeOperator::LIST_NAMED, typeConcrete->__operands.at(0).__operator); ASSERT_EQ(TypeOperator::LIST, typeConcrete->__operands.at(1).__operator); ASSERT_EQ(TypePrimitive::String, typeConcrete->__operands.at(1).__operands.at(0).__value); } TEST(Types, TreeType1) { string&& code = "XmlNode = type {\n" - " tag:: string,\n" - " attrs:: [string],\n" - " content:: string\n" - "}.\n" - "" - "Tree = type(Leaf) {Leaf, [Tree(Leaf)]}." - "Concrete = type Tree(XmlNode)."; + " tag:: string,\n" + " attrs:: [string],\n" + " content:: string\n" + "}.\n" + "" + "Tree = type(Leaf) {Leaf, [Tree(Leaf)]}." + "Concrete = type Tree(XmlNode)."; std::unique_ptr program(XreateManager::prepare(move(code))); ExpandedType typeConcrete = program->root->findType("Concrete"); ASSERT_EQ(TypeOperator::LIST_NAMED, typeConcrete->__operator); ASSERT_EQ(2, typeConcrete->__operands.size()); ASSERT_EQ(TypeOperator::LIST_NAMED, typeConcrete->__operands.at(0).__operator); ASSERT_EQ(TypeOperator::LIST, typeConcrete->__operands.at(1).__operator); auto typeLink = typeConcrete->__operands.at(1).__operands.at(0); ASSERT_EQ(TypeOperator::LINK, typeLink.__operator); ASSERT_EQ(typeConcrete->conjuctionId, typeLink.conjuctionId); } TEST(Types, TreeType1LLvm) { string&& code = "XmlNode = type {\n" - " tag:: string,\n" - " /* attrs:: [string],*/\n" - " content:: string\n" - "}.\n" - "" - "Tree = type(Leaf) {Leaf, [Tree(Leaf)]}." - "Concrete = type Tree(XmlNode)."; + " tag:: string,\n" + " /* attrs:: [string],*/\n" + " content:: string\n" + "}.\n" + "" + "Tree = type(Leaf) {Leaf, [Tree(Leaf)]}." + "Concrete = type Tree(XmlNode)."; std::unique_ptr program(XreateManager::prepare(move(code))); ExpandedType typeConcrete = program->root->findType("Concrete"); llvm::Type* raw = program->llvm->toLLVMType(typeConcrete); } TEST(Types, ArrayOfExternal1) { FILE* input = fopen("scripts/containers/Containers_Implementation_LinkedList1.xreate", "r"); assert(input != nullptr); Scanner scanner(input); Parser parser(&scanner); parser.Parse(); AST* ast = parser.root->finalize(); CodeScope* body = ast->findFunction("test")->getEntryScope(); const ExpandedType& t2 = ast->getType(body->getDefinition(body->getSymbol("childrenRaw"))); EXPECT_EQ(t2->__operator, TypeOperator::LIST); } TEST(Types, ExternType1) { FILE* input = fopen("scripts/containers/Containers_Implementation_LinkedList1.xreate", "r"); assert(input != nullptr); Scanner scanner(input); Parser parser(&scanner); parser.Parse(); AST* ast = parser.root->finalize(); CodeScope* body = ast->findFunction("test")->getEntryScope(); const ExpandedType& t2 = ast->getType(body->getDefinition(body->getSymbol("tree"))); EXPECT_EQ(t2->__operator, TypeOperator::CUSTOM); } TEST(Types, ast_VariantType1) { string&& code = - " colors = type variant {RED, BLUE, GREEN}.\n" - " test = function:: colors; entry {GREEN()}"; + " colors = type variant {RED, BLUE, GREEN}.\n" + " test = function:: colors; entry {GREEN()}"; std::unique_ptr program(XreateManager::prepare(move(code))); ExpandedType typ = program->root->findType("colors"); EXPECT_EQ(TypeOperator::VARIANT, typ->__operator); Expression eRed = program->root->findFunction("test")->getEntryScope()->getBody(); EXPECT_EQ(Operator::VARIANT, eRed.op); const ExpandedType& typ2 = program->root->getType(eRed); EXPECT_EQ(TypeOperator::VARIANT, typ2->__operator); } TEST(Types, full_VariantType_Switch1) { string&& code = - "colors = type variant{RED, BLUE, GREEN}. \n" - " test = function:: colors {GREEN()} \n" + "colors = type variant{RED, BLUE, GREEN}. \n" + " test = function:: colors {GREEN()} \n" - "main = function:: int; entry { \n" - " switch(test()):: int \n" - " case (GREEN()) {0} \n" - " case default {1} \n" - "}"; + "main = function:: int; entry { \n" + " switch(test()):: int \n" + " case (GREEN()) {0} \n" + " case default {1} \n" + "}"; XreateManager* man = XreateManager::prepare(move(code)); int (*main)() = (int (*)()) man->run(); EXPECT_EQ(0, main()); } TEST(Types, ast_VariantType2) { std::string script = - R"Code( + R"Code( Annotation = type variant { Num:: int, String:: string, Func:: {name::string, arguments::[Expression]} }. )Code"; std::unique_ptr program(XreateManager::prepare(move(script))); ExpandedType typ = program->root->findType("Annotation"); ASSERT_EQ(3, typ.get().fields.size()); } TEST(Types, SlaveTypes_UnwrapSlaveType1) { auto man = details::tier1::XreateManager::prepare(R"Code( AtomNumT = type slave atomNumT. AtomStrT = type slave atomStrT. CmpndIntStrT = type slave cmpndIntStrT. VariantT = type slave variantT. VariantComplicatedT = type slave variantComplicatedT. )Code"); man->transcend->addRawScript(R"RAW( atomNumT(5). atomNumT(8). atomStrT("a"). atomStrT("b"). cmpndIntStrT(1, "a"). cmpndIntStrT(2, "b"). variantT(first). variantT(second). variantT(third). variantComplicatedT(first(1, "a")). variantComplicatedT(second("b")). )RAW"); man->analyse(); ExpandedType AtomNumT = man->root->findType("AtomNumT"); ASSERT_EQ(AtomNumT->__operator, TypeOperator::SLAVE); - ExpandedType ContentAtomNumT = typeinference::dereferenceSlaveType(AtomNumT, man->transcend); + ExpandedType ContentAtomNumT = interpretation::dereferenceSlaveType(AtomNumT, man->transcend); ASSERT_EQ(TypePrimitive::Num, ContentAtomNumT->__value); ExpandedType AtomStrT = man->root->findType("AtomStrT"); - ExpandedType ContentAtomStrT = typeinference::dereferenceSlaveType(AtomStrT, - man->transcend); + ExpandedType ContentAtomStrT = interpretation::dereferenceSlaveType(AtomStrT, + man->transcend); ASSERT_EQ(TypePrimitive::String, ContentAtomStrT->__value); ExpandedType CmpndIntStrT = man->root->findType("CmpndIntStrT"); - ExpandedType ContentCmpndIntStrT = typeinference::dereferenceSlaveType(CmpndIntStrT, - man->transcend); + ExpandedType ContentCmpndIntStrT = interpretation::dereferenceSlaveType(CmpndIntStrT, + man->transcend); ASSERT_EQ(TypeOperator::LIST_NAMED, ContentCmpndIntStrT->__operator); ASSERT_EQ(2, ContentCmpndIntStrT->__operands.size()); ExpandedType VariantT = man->root->findType("VariantT"); - ExpandedType ContentVariantT = typeinference::dereferenceSlaveType(VariantT, - man->transcend); + ExpandedType ContentVariantT = interpretation::dereferenceSlaveType(VariantT, + man->transcend); ASSERT_EQ(TypeOperator::VARIANT, ContentVariantT->__operator); ASSERT_EQ(3, ContentVariantT->fields.size()); ExpandedType VariantComplicatedT = man->root->findType("VariantComplicatedT"); - ExpandedType ContentVariantComplicatedT = typeinference::dereferenceSlaveType(VariantComplicatedT, - man->transcend); + ExpandedType ContentVariantComplicatedT = interpretation::dereferenceSlaveType(VariantComplicatedT, + man->transcend); ASSERT_EQ(TypeOperator::VARIANT, ContentVariantComplicatedT->__operator); ASSERT_EQ(2, ContentVariantComplicatedT->fields.size()); ASSERT_EQ(2, ContentVariantComplicatedT->__operands.at(0).__operands.size()); } \ No newline at end of file diff --git a/documentation-api/AST-correspondence.fods b/documentation-api/AST-correspondence.fods new file mode 100644 index 0000000..159b180 --- /dev/null +++ b/documentation-api/AST-correspondence.fods @@ -0,0 +1,558 @@ + + + + 2018-08-02T18:59:05.238218130LibreOffice/6.0.4.2$Linux_X86_64 LibreOffice_project/00m0$Build-22018-08-15T21:01:52.425281983PT4H11M37S4 + + + 0 + 0 + 38555 + 17596 + + + view1 + + + 1 + 21 + 0 + 0 + 0 + 0 + 2 + 0 + 0 + 0 + 0 + 0 + 100 + 60 + true + false + + + Sheet1 + 585 + 0 + 100 + 60 + false + true + true + true + 12632256 + true + true + true + true + false + false + false + 1270 + 1270 + 1 + 1 + true + false + + + + + 7 + true + false + false + 0 + true + sgH+/0xleG1hcmstWDY1NmRlAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQ1VQUzpMZXhtYXJrLVg2NTZkZQAAAAAAAAAAAAAAAAAWAAMA0wAAAAAAAAAIAFZUAAAkbQAASm9iRGF0YSAxCnByaW50ZXI9TGV4bWFyay1YNjU2ZGUKb3JpZW50YXRpb249UG9ydHJhaXQKY29waWVzPTEKY29sbGF0ZT1mYWxzZQptYXJnaW5kYWp1c3RtZW50PTAsMCwwLDAKY29sb3JkZXB0aD0yNApwc2xldmVsPTAKcGRmZGV2aWNlPTEKY29sb3JkZXZpY2U9MApQUERDb250ZXhEYXRhCklucHV0U2xvdDpUcmF5MQBEdXBsZXg6Tm9uZQBQYWdlU2l6ZTpMZXR0ZXIAABIAQ09NUEFUX0RVUExFWF9NT0RFDwBEdXBsZXhNb2RlOjpPZmY= + Lexmark-X656de + true + 3 + true + false + true + true + 12632256 + true + true + true + false + true + false + true + 1 + false + 1270 + 1270 + false + 1 + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ??? + + + + Page 1 + + + + + + + ???(???) + + + 00/00/0000, 00:00:00 + + + + + Page 1/ 99 + + + + + + + + + + + + + + + + AST + + + Current Transcend + + + Proposition 1 + + + Types + + + Tests + + + + + Expr + + + + + + op + + + + + + id + + + + + + state + + + + + + bindings + + + + + + operands + + + + + + type + + + + + + tags + + + bind(var, annotation) + + + + + + blocks + + + + + + value + + + + + + + + + CodeScope + + + scope(scopeId) + + + ast_scope(scopeId) + + + + + + bindings + + ast_scope_binding(scopeId, BindingId, ScopeBindName) + + + ast_scope_binding(scopeId, BindingId, ScopeBindName) + + + LIST + + + CFA.ASTCorrespondence_Scope_Bindings_1 + + + + + identifiers + + + + ast_scope_identifier(scopeId, Var) + + + LIST + + + + + + parent + + + cfa_parent(scopeCurrent, scope(scopeParent)) + + + ast_scope_parent(ScopeId, ScopeParentId) + + + SINGLE + + + + + + declarations + + + + LIST + + + + + + tags + + + bind_scope(scopeId, tag, strong/weak(..)) + + + + LIST + + + + + + contextRules + + + + + + + + + Function + + + + + + entry + + + cfa_parent(scopeEntry, functon(name)) + + + + SINGLE + + + + + + name + + + function(name) + + + + SINGLE + + + + + + guard + + + cfa_function_specializations(funcName, tag) + + + + SINGLE + + + + + + tags + + + bind_function(name, tag) + + + + LIST + + + + + + + + + Special Expressions + + + + + + CALL + + cfa_call(scopeFrom, functionTo)dfa_callfn(SymbRet, FnName)weak/dfa_callargs(SymbRet, argFormal, argActual)weak/dfa_alias(aliasFormal, Actual) + + + + + + + + + + OTHER + + + + + + + var: s(id, version, scope), a(Num) + + + + + + + v(var1) + + + + + + + dfa_fnret(fnName, symbRet) + + + + + + + + \ No newline at end of file diff --git a/documentation-api/interpretation.graphml b/documentation-api/interpretation.graphml new file mode 100644 index 0000000..4d43541 --- /dev/null +++ b/documentation-api/interpretation.graphml @@ -0,0 +1,502 @@ + + + + + + + + + + + + + + + + + + + + + + + I12n + Pass + Compilation/Interpretation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Function +Interpretation +Data + + + + + + + + + + + + + + + Function +Interpretation +Helper + + + + + + + + + + + + + + + I12n +Data + + + + + + + + + + + + + + + InterpretationOperator + + + + + + + + + + + + + + + InterpretationPass + + + + + + + + + + + + + + + I12n +Query + + + + + + + + + + + + + + + I12n +Resolution + + + + + + + + + + + + + + + IPass + + + + + + + + + + + + + + + I12n +Function + + + + + + + + + + + + + + + I12n +Scope + + + + + + + + + + + + + + + I12n +Scope +Decorator + + + + + + + + + + + + + + + Intrinsic +Query +Instruction + + + + + + + + + + + + + + + PIF +Signature + + + + + + + + + + + + + + + PI +Function + + + + + + + + + + + + + + + PI +FunctionUnit + + + + + + + + + + + + + + + TargetInterpretation + + + + + + + + + + + + + + + ICodeScope + + + + + + + + + + + + + + + Target + + + + + + + + + + + + + + + IFunctionUnit + + + + + + + + + + + + + + + + + Unfinished + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/documentation-api/latereasoning.graphml b/documentation-api/latereasoning.graphml index f4f3633..481aca0 100644 --- a/documentation-api/latereasoning.graphml +++ b/documentation-api/latereasoning.graphml @@ -1,521 +1,545 @@ - + - + - - - + + - - - + + + - Late Reasoning -Diagram + Late Reasonng Diagram + Pass + Interpretation + + - + Transcend + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + LateReasoning +Scope + fvffdfd + vdffldkjfd +fdfdfd + + + + + + + + + + + + + + + LateReasoning +DFAPass +Decorator + fvffdfd + vdffldkjfd +fdfdfd + + + registerLateScope +processAnnotations + + + + + + + + + + + + DFAPass + + + + + + + + + + + + + + + ICodeScope + + + + + + + + + + + + + + + LateSymbol +Recognized + + + + + + + + + + + + + + + DFAGraph + + + + + + + + + + + + + + + LateReasoning +Compiler + + + processSwitchLateStatement +compileAutoExpand + + + + + + + + + + + + + LateReasoning +Transcend +Decorator + + + findKeys + + + + + + + + + + + + Transcend +Layer + + + + + + + + + + + + + + + LateAnnotations +Group + + + select() + + + + + + + + + + + + Late +Annotation + + + + + + + + + + + + + + Transcend +program + + + + + + + + + + DFA +PassDec + + + + + + + + + + + + Interpretation +Scope + + + + + + + + + + + + + + LR +Trans +Dec + + + + + - + - - + + - LateReasoning -Scope - - - - - - - fvffdfd - - - - - - - vdffldkjfd -fdfdfd - - - - - - - - - + AST +getType + fvffdfd + vdffldkjfd +fdfdfd + + + - - - - - - - DFAPassDecorator - - - - - - - fvffdfd - - - - - - - vdffldkjfd -fdfdfd - - - - - - - - - - - - - - - - - - - - - DFAPass - - - - - - - - - - - - - - - - - - - - - ICodeScope - - - - - - - - - - - - - - - - - - - - - LateSymbol -Recognized - - - - - - - - - - - - - - - - - - - - - DFAGraph - - - - - - - - - - - - - - - - - - - - - LateReasoning -Compiler - - - - - - - - - - - - - - - - - - - - - CompilePass - - - - - - - - - - - - - - - - - - - - - LateReasoning -Transcend -Decorator - - - - - - - - - - - - - - - - - - - - - Transcend -Layer - - - - - - - - - - - - - - - - - - - - - LateAnnotations -Group - - - - - - - - - - - - - - - + - - + + - Late -Annotation - - - - - - - - - + dereferenceSlaveType + + + - - - - - - - - Polymorph -Query - - - - - - - - - - - - - - - - - - - - - LateBindingT - - - - - - - - - - - - - - - + + - - + + - - - - + - - + + - - + + - - + + - + - + - - + + - + - - + + - - + + + + + + + + + + + + + + + + + + + - - + + + + + + + + + + + + + + + + + + + + + + - - + + - - + + - + - - + + - - - + - - + + - + - - - + + + + - - + + - + - - - + + + + - - + + - + + + + + + + + + + + + + + + + diff --git a/documentation-api/latex.graphml b/documentation-api/latex.graphml new file mode 100644 index 0000000..7c0447f --- /dev/null +++ b/documentation-api/latex.graphml @@ -0,0 +1,834 @@ + + + + + + + + + + + + + + + + + + + + + + + Latex + Compilation + Transcend + Interpretation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ExtraArgs +FnInvocation + + + + + + + + + + + + + + + Latex +BruteScope +Dec + + + + + + + + + + + + + + + ICodeScopeUnit + + + + + + + + + + + + + + Latex +BruteFunction +Dec + + + + + + + + + + + + + + + IFunctionUnit + + + + + + + + + + + + + + + getSubjectDomain + + + + + + + + + + + + + + Latex +Query + + + + + + + + + + + + + + + IQuery + + + + + + + + + + + + + + + collapseColumn + + + + + + + + + + + + + + Latex +Query + + + + + + + + + + + represent +Trans +Expression + + + + + + + + + + + + + + + + + + + Latex script + + + + + + + + + + + Latex script + + + + + + + + + + + + + + + + + Latex + Output + Processing + Input + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Demand +upstream + + + + + + + + + + + + + + + + scope_demand + + + + + + + + + + + + + + + + + + latex_registered_subjects + + + + + + + + + + + + + + + + + + scope_demand(1) + + + + + + + + + + + + + + + + + + fn_demand + + + + + + + + + + + + + + + + + + decision + + + + + + + + + + + + + + + + + + scope_demand(2) + + + + + + + + + + + + + + + + + + late(decision) + + + + + + + + + + + + + + + + + + scope_fn + + + + + + + + + + + + + + + + + + fn_signature_size + + + + + + + + + + + + + + + + + + fn_demand_ordered + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/documentation-api/polymorphism.graphml b/documentation-api/polymorphism.graphml new file mode 100644 index 0000000..43eea1f --- /dev/null +++ b/documentation-api/polymorphism.graphml @@ -0,0 +1,309 @@ + + + + + + + + + + + + + + + + + + + + + + + Polymorphism + Compilation + Transcend + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Polymorph +Query + + + + + + + + + + + + + + + IQuery + + + + + + + + + + + + + + + Polymorph +CodeScopeUnit + + + findFunction + + + + + + + + + + + + ICodeScopeUnit + + + + + + + + + + + + + + Polymorph +FnInvocation + + + + + + + + + + + + + + P.Query + + + + + + + + + + + PSCU + + + + + + + + + + + + + + InterpretationScope + + + + + + + + + + + + + + + LateReasoningCompiler + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/grammar/xreate.ATG b/grammar/xreate.ATG index 4947344..a880168 100644 --- a/grammar/xreate.ATG +++ b/grammar/xreate.ATG @@ -1,676 +1,676 @@ //TODO add ListLiteral //TODO ExprTyped: assign default(none) type #include "ast.h" #include "ExternLayer.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". comma = ','. period = '.'. 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(); .) [lparen Ident tagcolon ExprAnnotations (. f->addBinding(Atom(argName), move(binding)); .) {comma Ident tagcolon ExprAnnotations (. f->addBinding(Atom (argName), move(binding));.) } rparen] [ 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 | TSlave | TypeTerm (. typ = typ3; .) | IF (checkIndex()) Ident lbrack Ident (. typ = TypeAnnotation(TypeOperator::ACCESS, {}); typ.__valueCustom = Atom(tid).get(); typ.fields.push_back(Atom(field).get()); .) {comma Ident (. typ.fields.push_back(Atom(field).get()); .) } rbrack | Ident (. typ = TypeAnnotation(TypeOperator::CUSTOM, {}); typ.__valueCustom = Atom(tid).get(); .) [lparen Type (. typ.__operator = TypeOperator::CALL; typ.__operands.push_back(typ2); .) {comma Type (. typ.__operands.push_back(typ2); .) } rparen] ) . TList = (. TypeAnnotation ty; .) lbrack Type rbrack (. 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()); .) {comma ( 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; .) +TVariant= (. TypeAnnotation t, typVoid; 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); .) {comma 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)); .) . TSlave= (. std::wstring identMaster; .) "slave" Ident (. typ = TypeAnnotation(TypeOperator::SLAVE, {}); typ.__valueCustom = Atom(identMaster).get(); .) . TDecl = (. TypeAnnotation t; std::wstring tname, arg; std::vector> args; .) Ident assign "type" [lparen Ident (. args.push_back(Atom(arg)); .) {comma Ident (. args.push_back(Atom(arg)); .) } rparen] Typeperiod (. 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 period | RuleContextDecl | ContextDeclperiod | 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" lparen Expr rparen (. 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" lparen Expr implic Ident (. e = Expression(Operator::MAP, {eIn}); .) tagcolon ExprAnnotations rparen tagcolon ExprAnnotations (. e.addBindings({Atom(varEl)}); block->addBinding(Atom(varEl), move(tagsEl)); .) BDecl<&*block> (. e.addBlock(block); .) |"fold" ("inf" lparen Expr implic Ident rparen (. e = Expression(Operator::FOLD_INF, {eAcc}); e.addBindings({Atom(varAcc)}); block->addBinding(Atom(varAcc), Expression()); .) tagcolon ExprAnnotations BDecl<&*block> (. e.addBlock(block); .) | lparen Expr implic Ident tagcolon ExprAnnotations ['|' Expr ] comma Expr implic Identrparen (. 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); .) ) ). // Switches SwitchDecl = (. TypeAnnotation typ; eSwitch = Expression(Operator::SWITCH, {}); Expression eCondition; Expression tag;.) "switch" ( SwitchVariantDecl - | SwitchLate + | SwitchLateDecl | 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)); .) {comma ExprTyped (. guard.addArg(Expression(condition)); .) } (. scope->setBody(guard); popContextScope(); .) . -SwitchLate = +SwitchLateDecl = (. std::wstring aliasCondition; Expression exprCondition, aliasAnns; expr = Expression(Operator::SWITCH_LATE, {}); ManagedScpPtr scope = root->add(new CodeScope(context.scope)); .) "late" lparen Expr [implic Ident] [tagcolon ExprAnnotations] rparen tagcolon ExprAnnotations BDecl<&*scope> (. expr.addArg(Expression(exprCondition)); expr.addBlock(scope); std::string alias; if(aliasCondition.empty()){ if(exprCondition.__state != Expression::IDENT){ SemErr(coco_string_create("An identifier expected in the short form")); return; } //Use exprCondition as identifier alias = exprCondition.getValueString(); } else { //Use aliasCondition - alias = Atom(move(aliasCondition)).get(); + alias = Atom(move(aliasCondition)).get(); } expr.addBindings({Atom(string(alias))}); scope->addBinding(Atom(move(alias)), move(aliasAnns)); .) . 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 period. InterfaceData<> = "interface" lparen ( "dfa" rparen InterfaceDFA | "extern-c" rparen InterfaceExternC | "cfa" rparen InterfaceCFA ). InterfaceExternC<> = (. ExternData data; .) lcurbrack {IncludeExternDecl | LibExternDecl } rcurbrack (. root->addExternData(move(data)); .) . LibExternDecl = (. std::wstring pkgname, libname; .) Ident assign "library" tagcolon "pkgconfig" lparen string (. pkgname = t->val; .) rparen period (. data.addLibrary(Atom(libname), Atom(pkgname)); .) . IncludeExternDecl = (. Expression inc; .) "include" StructLiteral period (. data.addIncludeDecl(move(inc)); .) . InterfaceDFA<> = lcurbrack { InstructDecl } rcurbrack . InstructDecl = (.Operator op; Expression tag; Expression scheme; std::vector& tags = scheme.operands; tags.push_back(Expression()); /* return value */ .) "operator" InstructAlias tagcolon lparen (.scheme.setOp(op); .) [ MetaSimpExpr (. tags.push_back(tag); .) { comma MetaSimpExpr (. tags.push_back(tag); .) } ] rparen [ implic MetaSimpExpr (. tags[0] = tag; .) ] (. root->addDFAData(move(scheme)); .) period. InstructAlias = ( "map" (. op = Operator::MAP; .) | "list_range" (. op = Operator::LIST_RANGE; .) | "list" (. op = Operator::LIST; .) | "fold" (. op = Operator::FOLD; .) | "index" (. op = Operator::INDEX; .) ). InterfaceCFA<> = lcurbrack { InstructCFADecl } rcurbrack . InstructCFADecl<> = (.Operator op; Expression tag; Expression scheme; std::vector& tags = scheme.operands; .) "operator" InstructAlias tagcolon (. scheme.setOp(op); .) [ MetaSimpExpr (. tags.push_back(tag); .) { comma MetaSimpExpr (. tags.push_back(tag); .) } ] period (. 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; .) lparen Ident tagcolon Domain (. args.add(arg, typ); .) {comma Ident tagcolon Domain (. args.add(arg, typ); .) } rparen ["case" RGuard {comma RGuard}] lcurbrack RBody rcurbrack . /* - TODO use RGuard for guards-*/ RuleContextDecl = (.Expression eHead, eGuards, eBody; .) "rule" "context" tagcolon MetaSimpExpr "case" lparen MetaSimpExpr rparen lcurbrack MetaSimpExpr rcurbrack (.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= ( lparen MetaExpr rparen | MetaSimpExpr ). MetaSimpExpr= (. std::wstring i1, infix; Expression e2; .) ( '-' MetaSimpExpr (. e = Expression(Operator::NEG, {e2}); .) | IF(checkParametersList()) Ident (. e = Expression(Operator::CALL, {Expression(Atom(i1))}); .) lparen [ MetaCalleeParams ] rparen | 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)); .) {comma 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); .) lparen [CalleeParams] rparen | VarIdent (. recognizeIdentifier(e); .) | ListLiteral (. /* tuple */.) | StructLiteral (. /* struct */.) | LoopDecl | IfDecl | SwitchDecl | 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}); .) | lparen ExprTyped rparen ). StructLiteral = (. std::wstring key; Expression val; std::list> keys; size_t keyCounter=0; .) lcurbrack (IF(checkTokenAfterIdent(_assign)) Ident assign Expr | Expr (. key = to_wstring(keyCounter++); .) ) (. keys.push_back(Atom(key)); e = Expression(Operator::LIST_NAMED, {val}); .) {comma (IF(checkTokenAfterIdent(_assign)) Ident assign 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; .) lbrack (. e.setOp(Operator::LIST); .) [ Expr (. e.addArg(Expression(eFrom)); .) ( ".." Expr (. e.addArg(Expression(eTo)); e.setOp(Operator::LIST_RANGE); .) |{comma Expr (. e.addArg(Expression(eFrom)); .) } ) ] rbrack. CalleeParams = (. Expression e2; .) ExprTyped (. e.addArg(Expression(e2)); .) {comma 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" lcurbrack {ANY} rcurbrack. END Xreate. diff --git a/scripts/cfa/context.lp b/scripts/cfa/context.lp index 9fd0394..eb6c9ef 100644 --- a/scripts/cfa/context.lp +++ b/scripts/cfa/context.lp @@ -1,82 +1,106 @@ % 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/. %% INPUT: %% - latex_scope_demand(Scope, Subject) %% Initial demand from clients %% %% - latex_registered_subjects(Subject, PossibleDecision) %% Clients register possible decisions for respective subjects %% +%% - latex_fn_signature +%% %% OUTPUT: %% - latex_fn_demand(Fn, Subject) %% Which functions demand hidden latex arguments %% %% - latex_decision(Scope, Subject, Decision) %% Provided decisions, values for hidden latex arguments +%% +%% SIGNATURES: +%% -Subject: string +%% % CONTEXT PROPAGATION %=========================================================== % nested scope propagation: -% test: CFA.Context1 bind_scope(Scope, Context, Info):- bind_scope(ScopeParent, Context, Info); cfa_parent(Scope, scope(ScopeParent)). % Strong or Uniform inter-function propagation: bind_scope(Scope, Context, Info):- bind_scope(ScopeParent, Context, Info): cfa_call(ScopeParent, FnCurrent); cfa_parent(Scope, function(FnCurrent)); cfa_call(_, FnCurrent); bind_scope(_, Context, Info); scope(Scope). % weak inter-function propagation bind_scope(Scope, Context, weak(ScopeParent)):- not bind_scope(Scope, Context, strong); bind_scope(ScopeParent, Context, strong); cfa_call(ScopeParent, FnCurrent); cfa_parent(Scope, function(FnCurrent)). % DEMAND -%Tests: CFA.Latex_SimpleFork1 %=========================================================== %demand propagations: scope level latex_scope_demand(Scope, Subject):- latex_scope_demand(ScopeChild, Subject); cfa_parent(ScopeChild, scope(Scope)). %propagation: fn level latex_fn_demand(Fn, Subject):- latex_scope_demand(ScopeFnBody, Subject); - cfa_parent(ScopeFnBody, function(Fn)). - + cfa_parent(ScopeFnBody, function(Fn)). + +latex_fn_demand_ordered(Fn, Subject, Id):- + Id= #sum{ 1, SubjLess : latex_fn_demand(Fn, SubjLess), SubjLess < Subject}; + latex_fn_demand(Fn, Subject). + %propagation: inter-fn level latex_scope_demand(Scope, Subject):- latex_fn_demand(FnCallee, Subject); not latex_decision(Scope, Subject, _); cfa_call(Scope, FnCallee). % DECISIONS -%Tests: CFA.Latex_SimpleFork1 %=========================================================== latex_decision(Scope, Subject, Decision):- latex_fn_demand(FnCallee, Subject); bind_scope(Scope, Decision, strong); cfa_call(Scope, FnCallee); latex_registered_subjects(Subject, Decision). +latex_fn_signature_size(Fn, IdMax + 1):- + IdMax = #max{ Id, Id : ast_scope_binding(FnBody, Id, _) }; + cfa_parent(FnBody, function(Fn)). + +latex_fn_signature_size(Fn, 0):- + not ast_scope_binding(FnBody, _, _); + cfa_parent(FnBody, function(Fn)). + %late decision -late(s(ScopeCaller, 0), (DecisionS), (AnyDecision), latex_decision(ScopeCaller, Subject, AnyDecision)):- +late((ScopeCaller, Subject), s(Size + SubjOrder+1, -2, FnCallerBody), (AnyDecision), latex_decision(ScopeCaller, Subject, AnyDecision)):- scope_fn(ScopeCaller, FnCaller); - latex_fn_signature(FnCaller, Subject, DecisionS); + cfa_parent(FnCallerBody, function(FnCaller)); + latex_fn_signature_size(FnCaller, Size); + latex_fn_demand_ordered(FnCaller, Subject, SubjOrder); cfa_call(ScopeCaller, FnCallee); latex_fn_demand(FnCallee, Subject); latex_registered_subjects(Subject, AnyDecision). +% IMPLEMENTATION +%=========================================================== + +scope_fn(Scope, Fn):-cfa_parent(Scope, function(Fn)). +scope_fn(Scope, Fn):- + scope_fn(ScopeParent, Fn); + cfa_parent(Scope, scope(ScopeParent)). diff --git a/scripts/cfa/control-context-v1.lp b/scripts/cfa/control-context-v1.lp deleted file mode 100644 index 220461a..0000000 --- a/scripts/cfa/control-context-v1.lp +++ /dev/null @@ -1,28 +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 propagation - -bind_scope_decision(Scope, Fn, Resolution):- cfa_call(Scope, Fn), cfa_function_specializations(Fn, Resolution), bind_scope(Scope, Resolution). -bind_scope_decision(Scope, Fn, Resolution):- cfa_call(Scope, FnChild), bind_function_demand(FnChild, Fn), cfa_function_specializations(Fn, Resolution), bind_scope(Scope, Resolution). - -bind_scope_demand(Scope, FnCallee):- cfa_call(Scope, FnCallee), cfa_function_specializations(FnCallee, _), not bind_scope_decision(Scope, FnCallee, _). - - %demand propagation -bind_scope_demand(Scope, Subject):- bind_scope_demand(ScopeChild, Subject), cfa_parent(ScopeChild, scope(Scope)). -bind_scope_demand(Scope, Subject):- cfa_call(Scope, FnChild), bind_function_demand(FnChild, Subject), not bind_scope_decision(Scope, Subject, _). -bind_function_demand(Fn, Subject):- bind_scope_demand(Scope, Subject), cfa_parent(Scope, function(Fn)). - -bind_scope(Scope, Context) :- bind_scope(ScopeParent, Context), cfa_parent(Scope, scope(ScopeParent)). -bind_scope(Scope, Context) :- bind_scope(ScopeParent, Context): cfa_call(ScopeParent, FnCurrent); cfa_call(_, FnCurrent) - , cfa_parent(Scope, function(FnCurrent)), bind_scope(_, Context), scope(Scope). - -% adhoc classes(unfinished): -%bind_func(Fn, adhoc_class(Context)) :- bind_func(Fn, adhoc(Context)), bind_scope(Scope, Context), cfa_parent(Scope, function(Fn)). - -%scope_parent(Scope, ScopeParent) :- cfa_parent(Scope, scope(ScopeParent)). -%scope_parent(Scope, ScopeParent2) :- cfa_parent(Scope, scope(ScopeParent)), scope_parent(ScopeParent, ScopeParent2). - -%scope_function(Scope, Fn) :- cfa_parent(Scope, function(Fn)). -%scope_function(Scope, Fn) :- cfa_parent(Scope, scope(ScopeParent)), scope_function(ScopeParent, Fn). diff --git a/scripts/cfa/control-context-v3.lp b/scripts/cfa/control-context-v3.lp deleted file mode 100644 index 03fe0d5..0000000 --- a/scripts/cfa/control-context-v3.lp +++ /dev/null @@ -1,70 +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/. - - %% SCHEMA: - %% specialization(Fn, Scope) - indicates query of exact Fn specialization to use in Scope. - %% resolution_dependency(Resolution, Dependency) - Dependency is necessary prerequisite for choosing Resolution. - %% - -true. - - %nested scope propagation: -bind_scope(Scope, Context, Info) :- bind_scope(ScopeParent, Context, Info), cfa_parent(Scope, scope(ScopeParent)). - - %strong/uniform inter-function propagation: -bind_scope(Scope, Context,Info) :- bind_scope(ScopeParent, Context, Info): cfa_call(ScopeParent, FnCurrent); - cfa_parent(Scope, function(FnCurrent)); cfa_call(_, FnCurrent); - bind_scope(_, Context, Info); scope(Scope). - - %weak inter-function propagation -bind_scope(Scope, Context, weak(ScopeParent)):- not bind_scope(Scope, Context, strong), bind_scope(ScopeParent, Context, strong), cfa_call(ScopeParent, FnCurrent), cfa_parent(Scope, function(FnCurrent)). -bind_scope(Scope, Context, weak(ScopeParent, Info)):- Info<>strong, not bind_scope(Scope, Context, Info), bind_scope(ScopeParent, Context, Info), cfa_call(ScopeParent, FnCurrent), cfa_parent(Scope, function(FnCurrent)). - - - %make decisions -%%%bind_scope_decision(Scope, loop(Subject), Scope):- cfa_contextloop(Scope, Subject), demand_dependency(loop(Subject), X), bind_scope(Scope, X, strong).* -%%%bind_scope_decision(Scope, loop(Subject), Scope):- cfa_call(Scope, FnChild), bind_function_demand(FnChild, loop(Subject)), demand_dependency(loop(Subject), X), bind_scope(Scope, X, strong). - - %on-site decision -% ASSERT: ON-SITE DECISION SHOULD BE FIRST CLASS (checks at least one specialization exists) -bind_scope_decision(Scope, Subject, Resolution):- - bind_scope(Scope, Resolution, strong), Subject = specialization(Fn, Scope); - cfa_call(Scope, Fn); - cfa_function_specializations(Fn, Resolution). - -bind_scope_decision(ScopeSource, Subject, Resolution):- - bind_scope(Scope, Resolution, weak(ScopeSource)); Subject = specialization(Fn, Scope); - cfa_call(Scope, Fn); cfa_function_specializations(Fn, Resolution). - -bind_scope_decision(ScopeSource, Subject, resolution_dependency(Resolution, Dependency)):- - bind_scope(Scope, Resolution, weak(ScopeSource, Dependency)); Subject = specialization(Fn, Scope); - cfa_call(Scope, Fn), cfa_function_specializations(Fn, Resolution). - - %dependent decisions -bind_scope_demand(Scope, dependency(Subject, Scope)) :- bind_scope_decision(Scope, Subject, resolution_dependency(_, Dependency)). -bind_scope_demand(ScopeSource, dependency(Subject, ScopeSource)) :- Dependency = weak(ScopeSource, DependencyTail), bind_scope_demand(Scope, dependency(Subject, Scope)), scope_dependencies(dependency(Subject, Scope), Dependency). - -bind_scope_decision(ScopeSource, dependency(Subject, Scope), Dependency) :- Dependency = weak(ScopeSource), bind_scope_demand(Scope, dependency(Subject, Scope)), scope_dependencies(dependency(Subject, Scope), Dependency). -bind_scope_decision(ScopeSource, dependency(Subject, Scope), resolution_dependency(Dependency, DependencyTail)) :- Dependency = weak(ScopeSource, DependencyTail), bind_scope_demand(Scope, dependency(Subject, Scope)), scope_dependencies(dependency(Subject, Scope), Dependency). - - - %dependent decision helpers: -scope_dependencies(dependency(Subject, Scope), Dependency) :- bind_scope_decision(Scope, Subject, resolution_dependency(_, Dependency)). -scope_dependencies(dependency(Subject, ScopeSource), DependencyTail) :- Dependency = weak(ScopeSource, DependencyTail), bind_scope_demand(Scope, dependency(Subject, Scope)), scope_dependencies(dependency(Subject, Scope), Dependency). - - %on-site demand -% ASSERT: ON-SITE DEMAND SHOULD BE dependent OF on-site decision (check there are no specializations AT ALL) -%%%bind_scope_demand(Scope, Subject):- cfa_contextloop(Scope, Subject), not bind_scope_decision(Scope, loop(Subject), _). -bind_scope_demand(Scope, Subject):- Subject = specialization(FnCallee, Scope), - cfa_call(Scope, FnCallee), - cfa_function_specializations(FnCallee, _), - not bind_scope_decision(Scope, Subject, _). - - %nested scope demand propagation -%ASSERT: NO DECISION CHECKS. because decisions linked to a leaf(function execution sites) scopes -bind_scope_demand(Scope, Subject):- bind_scope_demand(ScopeChild, Subject), cfa_parent(ScopeChild, scope(Scope)). -bind_function_demand(Fn, Subject):- bind_scope_demand(Scope, Subject), cfa_parent(Scope, function(Fn)). - - %inter-function propagation demand -bind_scope_demand(Scope, Subject):- cfa_call(Scope, FnChild), bind_function_demand(FnChild, Subject), not bind_scope_decision(Scope, Subject, _). diff --git a/scripts/cfa/control-context.lp b/scripts/cfa/control-context.lp deleted file mode 120000 index e2a1c99..0000000 --- a/scripts/cfa/control-context.lp +++ /dev/null @@ -1 +0,0 @@ -/private/prg/code/xreate/scripts/cfa/control-context-v3.lp \ No newline at end of file diff --git a/scripts/cfa/latex1.xreate b/scripts/cfa/latex1.xreate deleted file mode 100644 index de4486a..0000000 --- a/scripts/cfa/latex1.xreate +++ /dev/null @@ -1,39 +0,0 @@ -guard:: guardA { - fnGuarded = function :: int - {0} -} - -guard:: guardB { - fnGuarded = function :: int - {1} -} - -fnEntry= function:: int; entry -{ - fnA() + fnB() -} - -fnA = function:: int -{ - context:: guards(guardA). - fnInterim() -} - -fnInterim=function:: int -{ - fnMain() -} - -fnB = function:: int -{ - context:: guards(guardB). - fnMain() -} - -fnMain = function:: int -{ - switch late(argGuard):: int - { - fnGuarded() - } -} diff --git a/scripts/cfa/test2.assembly.lp b/scripts/cfa/test2.assembly.lp deleted file mode 100644 index 567c43e..0000000 --- a/scripts/cfa/test2.assembly.lp +++ /dev/null @@ -1,10 +0,0 @@ - -dfa_callguard(InstSymbRet, Guard):- %static local decision - bind_scope(Scope, callguard(Guard), strong); - bind(InstSymbRet, dfa_polym(cntxt)); - InstSymbRet = s(_, _, Scope). - -%Register manual demand -kleo_registered_subjects(Scope, spec(FnCallee), Guard):- - bind_scope(Scope, kleo_manual_demand(FnCallee), strong); - cfa_function_specializations(FnCallee, Guard). diff --git a/scripts/cfa/test2.xreate b/scripts/cfa/test2.xreate deleted file mode 100644 index 5eeb13b..0000000 --- a/scripts/cfa/test2.xreate +++ /dev/null @@ -1,101 +0,0 @@ -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()} - } -} diff --git a/scripts/latereasoning/context-v1.lp b/scripts/latereasoning/context-v1.lp deleted file mode 100644 index f0a7feb..0000000 --- a/scripts/latereasoning/context-v1.lp +++ /dev/null @@ -1,47 +0,0 @@ -%INPUT: -% kleo_registered_subjects(Scope, Option, Subject) - -%bind_scope_decision - scope has decision for demand of one of its subscopes. - -% CLIENTS -%=========================================================== -% clients defined downstream - -%Register fn argument demand -kleo_registered_subjects(ScopeCaller, kleo_arg(Subject), Guard):- - kleo_fn_demand(Fn, Subject); - cfa_parent(ScopeCallee, function(Fn)); - kleo_registered_subjects(ScopeCallee, Subject, Guard); - cfa_call(ScopeCaller, Fn). - -% DEMAND -%=========================================================== - -%local demand -kleo_scope_demand(Scope, Subject):- - not kleo_scope_decision(Scope, Subject, _); - kleo_registered_subjects(Scope, Subject, Decision). - -%demand propagation: scope -kleo_scope_demand(Scope, Subject):- - kleo_scope_demand(ScopeChild, Subject); - cfa_parent(ScopeChild, scope(Scope)). - -%propagation: interfn -kleo_fn_demand(Fn, Subject):- - kleo_scope_demand(ScopeFnBody, Subject); - cfa_parent(ScopeFnBody, function(Fn)). - - -% DECISIONS -%=========================================================== - -%local decision -kleo_scope_decision(Scope, Subject, Decision):- - bind_scope(Scope, Decision, strong); - kleo_registered_subjects(Scope, Subject, Decision). - -%interfn decision -%kleo_scope_decision(ScopeSource, parameter(Subject), Decision):- -% weak(bind_scope(Scope, Decision), ScopeSource); -% kleo_registered_subjects(Scope, Subject, Decision). diff --git a/scripts/latereasoning/test2.assembly.lp b/scripts/latereasoning/test2.assembly.lp deleted file mode 100644 index 567c43e..0000000 --- a/scripts/latereasoning/test2.assembly.lp +++ /dev/null @@ -1,10 +0,0 @@ - -dfa_callguard(InstSymbRet, Guard):- %static local decision - bind_scope(Scope, callguard(Guard), strong); - bind(InstSymbRet, dfa_polym(cntxt)); - InstSymbRet = s(_, _, Scope). - -%Register manual demand -kleo_registered_subjects(Scope, spec(FnCallee), Guard):- - bind_scope(Scope, kleo_manual_demand(FnCallee), strong); - cfa_function_specializations(FnCallee, Guard). diff --git a/scripts/latereasoning/test2.xreate b/scripts/latereasoning/test2.xreate deleted file mode 100644 index 5eeb13b..0000000 --- a/scripts/latereasoning/test2.xreate +++ /dev/null @@ -1,101 +0,0 @@ -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()} - } -}