diff --git a/config/default.json b/config/default.json index d5965dd..4f05447 100644 --- a/config/default.json +++ b/config/default.json @@ -1,73 +1,74 @@ { "containers": { "id": { "implementations": "impl_fulfill_cluster", "clusters": "var_cluster", "prototypes": "proto_cluster", "linkedlist": "linkedlist" }, "impl": { "solid": "solid", "onthefly": "on_the_fly" } }, "logging": { "id": "logging" }, "function-entry": "entry", "clasp": { "bindings" : { "variable": "bind", "function": "bind_func", "scope": "bind_scope", "function_demand" : "bind_function_demand", "scope_decision": "bind_scope_decision" }, "context" : { "decisions":{ "dependent": "resolution_dependency" } }, "nonevalue": "nonevalue", "ret": { "symbol": "retv", "tag": "ret" } }, "tests": { - "template": "default", + "template": "virtualization", "templates": { "current-fix":"*", - "default": "*-Adhoc.*:Containers.*:Compilation.full_IFStatementWithVariantType:Types.full_VariantType_Switch1:Context.full_LateContext:Context.pathDependentContext", + "default": "*-Adhoc.*:Containers.*:Compilation.full_IFStatementWithVariantType:Types.full_VariantType_Switch1:Context.full_LateContext:Context.pathDependentContext:Virtualization.test1", "ast": "AST.*", "adhocs": "Adhoc.*", "effects": "Effects.*", "basic": "Attachments.*", "context": "Context.*", "compilation": "Compilation.*-Compilation.full_IFStatementWithVariantType", "communication": "Communication.*", "cfa": "CFA.*", "containers": "Containers.*", "dfa": "DFA.*", "diagnostic": "Diagnostic.*", - "dsl": "Association.*:Interpretation.SwitchVariantAlias", + "dsl": "Association.*:Interpretation.*", "exploitation": "Exploitation.*", "ExpressionSerializer": "ExpressionSerializer.*", "externc": "InterfaceExternC.*", "loops": "Loop.*", "modules": "Modules.*", "polymorphs": "Polymorphs.call1", - "types": "Types.*", + "types": "Types.*", + "virtualization": "Virtualization.test2", "vendorsAPI/clang": "ClangAPI.*", "vendorsAPI/xml2": "libxml2*" } } } diff --git a/core/control-context.lp b/core/control-context.lp deleted file mode 120000 index f0191b9..0000000 --- a/core/control-context.lp +++ /dev/null @@ -1 +0,0 @@ -/private/prg/code/xreate/core/control-context-v3.lp \ No newline at end of file diff --git a/cpp/CMakeLists.txt b/cpp/CMakeLists.txt index 0f5feae..d1084db 100644 --- a/cpp/CMakeLists.txt +++ b/cpp/CMakeLists.txt @@ -1,35 +1,34 @@ project(Xreate) cmake_minimum_required(VERSION 2.8.11) -set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -g -Wall -fprofile-arcs -ftest-coverage -O0") +set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -Wall -fprofile-arcs -ftest-coverage -O0") set(CMAKE_BUILD_TYPE Debug) - # BUILD OPTIONS #====================== set(XREATE_DEFINITIONS -D_GNU_SOURCE -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS -DWITH_THREADS=1 ) add_definitions(${XREATE_DEFINITIONS}) add_compile_options(-Winvalid-pch -fPIC -std=c++14) # XREATE #====================== add_subdirectory(src) # XREATE-TESTS #====================== if (BUILD_XREATE_TESTS) message ("Building xreate tests") add_subdirectory(tests) endif () # XREATE-SERVER #====================== if (BUILD_XREATE_SERVER) message ("Building xreate server") add_subdirectory(../tools/execution-server execution-server) endif () diff --git a/cpp/src/CMakeLists.txt b/cpp/src/CMakeLists.txt index 6c98f92..22def64 100644 --- a/cpp/src/CMakeLists.txt +++ b/cpp/src/CMakeLists.txt @@ -1,230 +1,229 @@ cmake_minimum_required(VERSION 2.8.11) project(xreate) cmake_policy(SET CMP0022 NEW) message("MODULES" ${CMAKE_MODULE_PATH}) # LLVM #====================== FIND_PACKAGE (LLVM REQUIRED) set(LLVM_VERSION ${LLVM_VERSION_MAJOR}.${LLVM_VERSION_MINOR}) message(STATUS "Found LLVM ${LLVM_PACKAGE_VERSION}") message("LLVM LIB PATH:" ${LLVM_LIBRARY_DIRS}) message(STATUS "Using LLVMConfig.cmake in: ${LLVM_DIR}") INCLUDE_DIRECTORIES(${LLVM_INCLUDE_DIRS}) message(STATUS "INCLUDE DIR: ${LLVM_INCLUDE_DIRS}") add_definitions(${LLVM_DEFINITIONS}) message("LLVM DEFS: " ${LLVM_DEFINITIONS}) llvm_map_components_to_libnames(LLVM_LIBS core nativecodegen native executionengine mcjit support option) message("LLVM LIBS: " ${LLVM_LIBS}) # CLANG #====================== set(CLANG_LIBS clangCodeGen clangASTMatchers clangQuery clangTooling clangFrontend clangSerialization clangDriver clangParse clangSema clangAnalysis clangAST clangEdit clangLex clangBasic ) # POTASSCO #====================== set(POTASSCO_PATH "/opt/potassco/clingo" CACHE PATH "Path to potassco sources") set(POTASSCO_INCLUDE_PATH ${POTASSCO_PATH}/libgringo ${POTASSCO_PATH}/libclasp ${POTASSCO_PATH}/libclingo ${POTASSCO_PATH}/libprogram_opts ${POTASSCO_PATH}/liblp ) INCLUDE_DIRECTORIES(${POTASSCO_INCLUDE_PATH}) set(LIBCLASP_LIBS clingo clasp gringo program_opts reify lp ) message("CLASP LIBS: " ${LIBCLASP_LIBS}) # OTHER DEPENDENCIES #=========================== set(JEAYESON_INCLUDE_PATH ${CMAKE_HOME_DIRECTORY}/../vendors/jeayeson/include/ ) INCLUDE_DIRECTORIES(${JEAYESON_INCLUDE_PATH}) # COCO #=========================== set(COCO_EXECUTABLE "" CACHE PATH "Path to coco executable") set(COCO_FRAMES_PATH "" CACHE PATH "Path to coco frames") set(COCO_GRAMMAR_PATH ${CMAKE_HOME_DIRECTORY}/../grammar/) set(COCO_SOURCE_FILES_MAIN ${COCO_GRAMMAR_PATH}/main/Parser.cpp ${COCO_GRAMMAR_PATH}/main/Scanner.cpp ) set(COCO_SOURCE_FILES_MODULES ${COCO_GRAMMAR_PATH}/modules/Parser.cpp ${COCO_GRAMMAR_PATH}/modules/Scanner.cpp ) set(COCO_SOURCE_FILES ${COCO_SOURCE_FILES_MODULES} ${COCO_SOURCE_FILES_MAIN}) INCLUDE_DIRECTORIES(${COCO_GRAMMAR_PATH}) add_custom_command(OUTPUT ${COCO_SOURCE_FILES_MAIN} COMMAND ${COCO_GRAMMAR_PATH}/gen-grammar main ${COCO_EXECUTABLE} ${COCO_FRAMES_PATH} WORKING_DIRECTORY ${COCO_GRAMMAR_PATH} MAIN_DEPENDENCY ${COCO_GRAMMAR_PATH}/xreate.ATG ) add_custom_command(OUTPUT ${COCO_SOURCE_FILES_MODULES} COMMAND ${COCO_GRAMMAR_PATH}/gen-grammar modules ${COCO_EXECUTABLE} ${COCO_FRAMES_PATH} WORKING_DIRECTORY ${COCO_GRAMMAR_PATH} MAIN_DEPENDENCY ${COCO_GRAMMAR_PATH}/modules.ATG ) message(STATUS "COCO GRAMMAR BUILD STATUS:" ${COCO_OUTPUT}) # XREATE #====================== set(SOURCE_FILES query/polymorph.cpp analysis/dfagraph.cpp pass/dfapass.cpp compilation/targetinterpretation.cpp pass/interpretationpass.cpp ast.cpp xreatemanager.cpp analysis/typeinference.cpp aux/xreatemanager-decorators.cpp compilation/operators.cpp compilation/transformations.cpp compilation/transformersaturation.cpp pass/compilepass.cpp pass/versionspass.cpp attachments.cpp ExternLayer.cpp analysis/cfagraph.cpp analysis/aux.cpp compilation/containers.cpp compilation/advancedinstructions.cpp clasplayer.cpp - compilation/latecontextcompiler2.cpp query/context.cpp llvmlayer.cpp utils.cpp pass/abstractpass.cpp pass/cfapass.cpp pass/adhocpass.cpp contextrule.cpp query/containers.cpp analysis/DominatorsTreeAnalysisProvider.cpp aux/serialization/expressionserializer.cpp modules.cpp ) set(XREATE_INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/ ) INCLUDE_DIRECTORIES(${XREATE_INCLUDE_DIRS}) set(XREATE_PRIVATE_INCLUDE_DIRS ${XREATE_INCLUDE_DIRS} ${COCO_GRAMMAR_PATH} ${JEAYESON_INCLUDE_PATH} ${LLVM_INCLUDE_DIRS} ${POTASSCO_INCLUDE_PATH} ) add_library(${PROJECT_NAME} SHARED ${COCO_SOURCE_FILES} ${SOURCE_FILES}) target_link_libraries(${PROJECT_NAME}) target_include_directories(${PROJECT_NAME} INTERFACE ${XREATE_INCLUDE_DIRS} ${COCO_GRAMMAR_PATH} ${JEAYESON_INCLUDE_PATH} ${LLVM_INCLUDE_DIRS} ${POTASSCO_INCLUDE_PATH} ) get_directory_property(DEFINITIONS_ALL DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} COMPILE_DEFINITIONS) message("definitions all: " ${DEFINITIONS_ALL}) target_compile_definitions(${PROJECT_NAME} INTERFACE ${DEFINITIONS_ALL}) get_directory_property(COMPILATION_OPTIONS_ALL DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} COMPILE_OPTIONS) message("compilations all: " ${COMPILATION_OPTIONS_ALL}) target_compile_options(${PROJECT_NAME} INTERFACE ${COMPILATION_OPTIONS_ALL}) SET_PROPERTY(TARGET ${PROJECT_NAME} PROPERTY INTERFACE_LINK_LIBRARIES ${LIBCLASP_LIBS} ${CLANG_LIBS} ${LLVM_LIBS} tbb boost_system boost_filesystem ) #${CLANG_LIBS} #set (LINK_INTERFACE_LIBRARIES "") # FUNCTION(PREPEND var prefix) # SET(listVar "") # FOREACH(f ${ARGN}) # LIST(APPEND listVar "${prefix}/${f}") # ENDFOREACH(f) # SET(${var} "${listVar}" PARENT_SCOPE) # ENDFUNCTION(PREPEND) #set(COTIRE_UNITY_SOURCE_MAXIMUM_NUMBER_OF_INCLUDES "-j4") #cotire(xreate) # MACRO (ADD_PCH_RULE _header_filename _src_list) # SET(_gch_filename "${_header_filename}.gch") # LIST(APPEND ${_src_list} ${_gch_filename}) # SET (_args ${CMAKE_CXX_FLAGS}) # LIST(APPEND _args -c ${_header_filename} -o ${_gch_filename}) # GET_DIRECTORY_PROPERTY(DIRINC INCLUDE_DIRECTORIES) # foreach (_inc ${DIRINC}) # LIST(APPEND _args "-I" ${_inc}) # endforeach(_inc ${DIRINC}) # SEPARATE_ARGUMENTS(_args) # add_custom_command(OUTPUT ${_gch_filename} # COMMAND rm -f ${_gch_filename} # COMMAND ${CMAKE_CXX_COMPILER} ${CMAKE_CXX_COMPILER_ARG1} ${_args} # DEPENDS ${_header_filename}) # ENDMACRO(ADD_PCH_RULE _header_filename _src_list) # ADD_PCH_RULE (${CMAKE_HOME_DIRECTORY}/src/ast.h SOURCE_FILES) # ADD_PCH_RULE (${CMAKE_HOME_DIRECTORY}/src/llvmlayer.h SOURCE_FILES) # ADD_PCH_RULE (${CMAKE_HOME_DIRECTORY}/src/clasplayer.h SOURCE_FILES) # ADD_PCH_RULE (${CMAKE_HOME_DIRECTORY}/src/pass/abstractpass.h SOURCE_FILES) diff --git a/cpp/src/analysis/cfagraph.cpp b/cpp/src/analysis/cfagraph.cpp index 3ca5e39..f4b8292 100644 --- a/cpp/src/analysis/cfagraph.cpp +++ b/cpp/src/analysis/cfagraph.cpp @@ -1,204 +1,204 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * File: CFAGraph.cpp * Author: pgess * * Created on June 27, 2016, 2:09 PM */ /** * \file cfagraph.h * \brief Control Flow Analysis(CFA) graph data * */ #include "analysis/cfagraph.h" #include "analysis/aux.h" using namespace xreate::cfa; using namespace std; void CFAGraph::print(std::ostringstream& output) const { const std::string& atomBinding = Config::get("clasp.bindings.function"); const std::string& atomBindingScope = Config::get("clasp.bindings.scope"); //show function tags int counterTags = 0; std::ostringstream bufFunctionNames; boost::format formatFunction("function(%1%)."); boost::format formatBind(atomBinding + "(%1%, %2%)."); for (auto function: this->__nodesFunction.left) { const auto tags = this->__functionTags.equal_range(function.first); if (tags.first == tags.second) { //no tags bufFunctionNames << "; " << function.second ; continue; } output << formatFunction % (function.second) << std::endl; for (const auto& tag_: boost::make_iterator_range(tags)){ const Expression& tag = tag_.second; list tagRaw = xreate::analysis::compile(tag); assert(tagRaw.size() == 1); output << formatBind % (function.second) % (tagRaw.front()) << endl; ++counterTags; } } if (bufFunctionNames.tellp()){ output << formatFunction % (bufFunctionNames.str().substr(2)) << std::endl; } if (counterTags == 0) { output << "%no functtion tags at all" << endl; } //declare scopes boost::format formatScope("scope(0..%1%)."); output << formatScope % (__clasp->getScopesCount() - 1) << std::endl; //show context rules: for (auto rule: this->__contextRules) { output << ContextRule(rule.second).compile(rule.first) << std::endl; }; //show scope tags: counterTags = 0; boost::format formatScopeBind(atomBindingScope + "(%1%, %2%, strong)."); for (auto entry: this->__scopeTags) { ScopePacked scopeId = entry.first; const Expression& tag = entry.second; list tagRaw = xreate::analysis::compile(tag); assert(tagRaw.size() == 1); output << formatScopeBind % scopeId %(tagRaw.front()) << endl; ++counterTags; } if (counterTags == 0) { output << "%scope tags: no tags at all" << endl; } output << endl << "%\t\tStatic analysis: CFA" << endl; //parent connections //TOTEST CFG parent function boost::format formatFunctionParent("cfa_parent(%1%, function(%2%))."); for (const auto &relation: this->__parentFunctionRelations) { const string& function = this->__nodesFunction.left.at(relation.right); output << formatFunctionParent % relation.left % function << endl; } //TOTEST CFG parent scope boost::format formatScopeParent("cfa_parent(%1%, scope(%2%))."); for (const auto &relation: this->__parentScopeRelations) { output << formatScopeParent % relation.first % relation.second << endl; } //call connections boost::format formatCall("cfa_call(%1%, %2%)."); for (const auto &relation: this->__callRelations) { const ScopePacked scopeFrom = relation.left; const string& functionTo = this->__nodesFunction.left.at(relation.right); output << formatCall % (scopeFrom) % (functionTo) << endl; } //function specializations descrtiption //SECTIONTAG late-context cfa_function_specializations boost::format formatSpecializations("cfa_function_specializations(%1%, %2%)."); const list& functions = __clasp->ast->getAllFunctions(); for (auto f: functions){ - if (f->guardContext.isValid()){ - list guardRaw = xreate::analysis::compile(f->guardContext); + if (f->guard.isValid()){ + list guardRaw = xreate::analysis::compile(f->guard); assert(guardRaw.size() == 1); output << formatSpecializations % (f->getName()) % (guardRaw.front()) << endl; } } //Dependencies boost::format formatDependencies("cfa_scope_depends(%1%, %2%)."); for(const auto relation: __dependencyRelations){ output << formatDependencies % relation.first % relation.second << endl; } std::multimap __dependencyRelations; } void CFAGraph::addFunctionAnnotations(const std::string& function, const std::map& tags) { unsigned int fid = registerNodeFunction(function); for (auto& tag: tags){ __functionTags.emplace(fid, tag.second); } } void CFAGraph::addScopeAnnotations(const ScopePacked& scope, const std::vector& tags){ for (Expression tag: tags){ __scopeTags.emplace(scope, tag); } } void CFAGraph::addContextRules(const ScopePacked& scope, const std::vector& rules){ for (Expression rule: rules){ __contextRules.emplace(scope, rule); } } void CFAGraph::addCallConnection(const ScopePacked& scopeFrom, const std::string& functionTo) { unsigned int idFuncTo = registerNodeFunction(functionTo); __callRelations.insert(CALL_RELATIONS::value_type(scopeFrom, idFuncTo)); } void CFAGraph::addParentConnection(const ScopePacked& scope, const std::string& functionParent){ __parentFunctionRelations.insert(PARENT_FUNCTION_RELATIONS::value_type(scope, registerNodeFunction(functionParent))); } void CFAGraph::addParentConnection(const ScopePacked& scope, const ScopePacked& scopeParent){ __parentScopeRelations.emplace(scope, scopeParent); } unsigned int CFAGraph::registerNodeFunction(const std::string& fname){ auto pos = __nodesFunction.left.insert(make_pair(__nodesFunction.size(), fname)); return pos.first->first; } void CFAGraph::addDependency(const ScopePacked& scope, const ScopePacked& scopeDependency){ __dependencyRelations.emplace(scope, scopeDependency); } bool CFAGraph::isDependent(const ScopePacked& scope) const{ return __dependencyRelations.count(scope) > 0; } void CFAGraph::transmitDependencies(const ScopePacked& scopeTo, const ScopePacked& scopeFrom){ auto range = __dependencyRelations.equal_range(scopeFrom); std::list dependencies; for (auto pairI = range.first; pairI != range.second; ++pairI){ dependencies.push_back(pairI->second); } for(auto dep: dependencies){ __dependencyRelations.emplace(scopeTo, dep); } } diff --git a/cpp/src/ast.h b/cpp/src/ast.h index cdb0515..57a4c2a 100644 --- a/cpp/src/ast.h +++ b/cpp/src/ast.h @@ -1,734 +1,733 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * Author: pgess * File: ast.h */ #ifndef AST_H #define AST_H #include "attachments.h" #include #include #include #include #include #include #include #include "utils.h" #include namespace llvm { class Value; } namespace xreate { struct ScopedSymbol; struct Symbol; } namespace std { template<> struct hash { std::size_t operator()(xreate::ScopedSymbol const& s) const; }; template<> struct equal_to { bool operator()(const xreate::ScopedSymbol& __x, const xreate::ScopedSymbol& __y) const; }; template<> struct hash { size_t operator()(xreate::Symbol const& s) const; }; template<> struct equal_to { bool operator()(const xreate::Symbol& __x, const xreate::Symbol& __y) const; }; } namespace xreate { struct String_t { }; struct Identifier_t { }; struct Number_t { }; struct Type_t { }; template class Atom { }; //DEBT store line:col for all atoms/identifiers template<> class Atom { public: Atom(const std::wstring& value); Atom(std::string && name); const std::string& get() const; private: std::string __value; }; template<> class Atom { public: Atom(wchar_t* value); Atom(int value); double get()const; private: double __value; }; template<> class Atom { public: Atom(const std::wstring& value); Atom(std::string && name); const std::string& get() const; private: std::string __value; }; enum class TypePrimitive { Invalid, Bool, I8, I32, I64, Num, Int, Float, String }; enum class TypeOperator { NONE, CALL, CUSTOM, VARIANT, LIST, LIST_NAMED, ACCESS, LINK }; struct llvm_array_tag { }; struct struct_tag { }; const llvm_array_tag tag_array = llvm_array_tag(); const struct_tag tag_struct = struct_tag(); /** * \brief Represents type to support type system * * This class represents type in denormalized form, i.e. without arguments and aliases substitution * \sa AST::expandType() */ class TypeAnnotation { public: TypeAnnotation(); TypeAnnotation(const Atom& typ); TypeAnnotation(TypePrimitive typ); TypeAnnotation(llvm_array_tag, TypeAnnotation typ, int size); TypeAnnotation(TypeOperator op, std::initializer_list operands); TypeAnnotation(TypeOperator op, std::vector&& operands); void addBindings(std::vector>&& params); void addFields(std::vector>&& listFields); bool operator<(const TypeAnnotation& t) const; // TypeAnnotation (struct_tag, std::initializer_list); bool isValid() const; TypeOperator __operator = TypeOperator::NONE; std::vector __operands; TypePrimitive __value; std::string __valueCustom; int conjuctionId = -1; //conjunction point id (relevant for recursive types) uint64_t __size = 0; std::vector fields; std::vector bindings; private: }; enum class Operator { INVALID, UNDEF, ADD, SUB, MUL, DIV, EQU, NE, NEG, LSS, LSE, GTR, GTE, LIST, LIST_RANGE, LIST_NAMED, CALL, CALL_INTRINSIC, IMPL/* implication */, MAP, FOLD, FOLD_INF, LOOP_CONTEXT, INDEX, IF, SWITCH, SWITCH_ADHOC, SWITCH_VARIANT, CASE, CASE_DEFAULT, LOGIC_AND, ADHOC, CONTEXT_RULE, VARIANT, SEQUENCE }; class Function; class AST; class CodeScope; class MetaRuleAbstract; typedef ManagedPtr ManagedFnPtr; typedef ManagedPtr ManagedScpPtr; typedef ManagedPtr ManagedRulePtr; const ManagedScpPtr NO_SCOPE = ManagedScpPtr(UINT_MAX, 0); /** * \brief Represents every instruction in Xreate's syntax tree * \attention In case of any changes update xreate::ExpressionHints auxiliary helper as well * * Expression is generic building block of syntax tree able to hold node data * as well as child nodes as operands. Not only instructions use expression for representation in syntax tree * but annotation as well. * * Additionally, `types` as a special kind of annotations use Expression-like data structure TypeAnnotation * \sa xreate::AST, xreate::TypeAnnotation */ // struct Expression { friend class CodeScope; friend class ClaspLayer; friend class CFAPass; friend class ExpressionHints; Expression(const Operator &oprt, std::initializer_list params); Expression(const Atom& ident); Expression(const Atom& number); Expression(const Atom& a); Expression(); void setOp(Operator oprt); void addArg(Expression&& arg); void addBindings(std::initializer_list> params); void bindType(TypeAnnotation t); template void addBindings(InputIt paramsBegin, InputIt paramsEnd); void addTags(const std::list tags) const; void addBlock(ManagedScpPtr scope); const std::vector& getOperands() const; double getValueDouble() const; void setValueDouble(double value); const std::string& getValueString() const; void setValue(const Atom&& v); bool isValid() const; bool isDefined() const; bool operator==(const Expression& other) const; /** * \brief is it string, number, compound operation and so on */ enum { INVALID, COMPOUND, IDENT, NUMBER, STRING, BINDING } __state = INVALID; /** * \brief Valid for compound State. Holds type of compound operator */ Operator op; /** * \brief Unique id to identify expression within syntax tree */ unsigned int id; /** * \brief Exact meaning depends on particular instruction * \details As an example, named lists/structs hold field names in bindings */ std::vector bindings; std::map __indexBindings; /** * \brief Holds child instructions as arguments */ std::vector operands; /** * \brief Holds type of instruction's result */ TypeAnnotation type; /** * \brief Holds additional annotations */ mutable std::map tags; /** * \brief Child code blocks * \details For example, If statement holds TRUE-branch as first and FALSE-branch as second block here */ std::list blocks; private: std::string __valueS; double __valueD; static unsigned int nextVacantId; }; bool operator<(const Expression&, const Expression&); template void Expression::addBindings(InputIt paramsBegin, InputIt paramsEnd) { size_t index = bindings.size(); std::transform(paramsBegin, paramsEnd, std::inserter(bindings, bindings.end()), [&index, this] (const Atom atom) { std::string key = atom.get(); this->__indexBindings[key] = index++; return key; }); } typedef std::list ExpressionList; enum class TagModifier { NONE, ASSERT, REQUIRE }; enum class DomainAnnotation { FUNCTION, VARIABLE }; class RuleArguments : public std::vector> { public: void add(const Atom& name, DomainAnnotation typ); }; class RuleGuards : public std::vector { public: void add(Expression&& e); }; class ClaspLayer; class LLVMLayer; class MetaRuleAbstract { public: MetaRuleAbstract(RuleArguments&& args, RuleGuards&& guards); virtual ~MetaRuleAbstract(); virtual void compile(ClaspLayer& layer) = 0; protected: RuleArguments __args; RuleGuards __guards; }; class RuleWarning : public MetaRuleAbstract { friend class ClaspLayer; public: RuleWarning(RuleArguments&& args, RuleGuards&& guards, Expression&& condition, Atom&& message); virtual void compile(ClaspLayer& layer); ~RuleWarning(); private: std::string __message; Expression __condition; }; typedef unsigned int VNameId; namespace versions { typedef int VariableVersion; const VariableVersion VERSION_NONE = -2; const VariableVersion VERSION_INIT = 0; } template<> struct AttachmentsDict { typedef versions::VariableVersion Data; static const unsigned int key = 6; }; struct ScopedSymbol { VNameId id; versions::VariableVersion version; static const ScopedSymbol RetSymbol; }; struct Symbol { ScopedSymbol identifier; const CodeScope * scope; }; struct IdentifierSymbol{}; struct SymbolAlias{}; template<> struct AttachmentsDict { typedef Symbol Data; static const unsigned int key = 7; }; template<> struct AttachmentsDict { typedef Symbol Data; static const unsigned int key = 9; }; typedef std::pair Tag; bool operator<(const ScopedSymbol& s1, const ScopedSymbol& s2); bool operator==(const ScopedSymbol& s1, const ScopedSymbol& s2); bool operator<(const Symbol& s1, const Symbol& s2); bool operator==(const Symbol& s1, const Symbol& s2); /** * \brief Represents code block and single scope of visibility * * Holds single expression as a *body* and set of variable assignments(declarations) used in body's expression * \sa xreate::AST */ class CodeScope { friend class Function; friend class PassManager; public: CodeScope(CodeScope* parent = 0); ~CodeScope(); /** \brief Set expression as a body */ void setBody(const Expression& body); /** \brief Returns current code scope body */ const Expression& getBody() const; /** \brief Adds variable definition to be used in body as well as in other declarations */ Symbol addDefinition(Expression&& var, Expression&& body); /** \brief Returns symbols' definition */ static const Expression& getDefinition(const Symbol& symbol, bool flagAllowUndefined = false); const Expression& getDefinition(const ScopedSymbol& symbol, bool flagAllowUndefined = false) const; /** \brief Adds variable defined elsewhere */ void addBinding(Expression&& var, Expression&& argument); std::vector __bindings; std::map __identifiers; CodeScope* __parent; //TODO move __definitions to SymbolsAttachments data //NOTE: definition of return type has index 0 std::unordered_map __declarations; std::vector tags; std::vector contextRules; private: VNameId __vCounter = 1; ScopedSymbol registerIdentifier(const Expression& identifier); public: bool recognizeIdentifier(const Expression& identifier) const; ScopedSymbol getSymbol(const std::string& alias); }; /** * \brief Represents single function in Xreate's syntax tree * * Holds an entry code scope and `guardContext` required for function to operate * \sa xreate::AST */ class Function { friend class Expression; friend class CodeScope; friend class AST; public: Function(const Atom& name); /** * \brief Adds function arguments */ void addBinding(Atom && name, Expression&& argument); /** * \brief Adds additional function annotations */ void addTag(Expression&& tag, const TagModifier mod); const std::string& getName() const; const std::map& getTags() const; CodeScope* getEntryScope() const; CodeScope* __entry; std::string __name; bool isPrefunction = false; //SECTIONTAG adhoc Function::isPrefunction flag - Expression guardContext; Expression guard; private: std::map __tags; }; class ExternData; struct ExternEntry { std::string package; std::vector headers; }; typedef Expanded ExpandedType; struct TypeInferred{}; template<> struct AttachmentsDict { typedef ExpandedType Data; static const unsigned int key = 11; }; enum ASTInterface { CFA, DFA, Extern, Adhoc }; struct FunctionSpecialization { std::string guard; size_t id; }; struct FunctionSpecializationQuery { std::unordered_set context; }; template<> struct AttachmentsId{ static unsigned int getId(const Expression& expression){ return expression.id; } }; template<> struct AttachmentsId{ static unsigned int getId(const Symbol& s){ return s.scope->__declarations.at(s.identifier).id; } }; template<> struct AttachmentsId{ static unsigned int getId(const ManagedFnPtr& f){ const Symbol symbolFunction{ScopedSymbol::RetSymbol, f->getEntryScope()}; return AttachmentsId::getId(symbolFunction); } }; template<> struct AttachmentsId{ static unsigned int getId(const unsigned int id){ return id; } }; class TypesResolver; namespace details { namespace inconsistent { /** * \brief Syntax tree under construction in inconsistent form * * Represents Syntax Tree under construction(**inconsistent state**). * \attention Clients should use rather xreate::AST unless client's code explicitly works with Syntax Tree during construction. * * Typically instance only created by xreate::XreateManager and filled in by Parser * \sa xreate::XreateManager::prepare(std::string&&) */ class AST { friend class xreate::TypesResolver; public: AST(); /** * \brief Adds new function to AST * \param f Function to register */ void add(Function* f); /** * \brief Adds new declarative rule to AST * \param r Declarative Rule */ void add(MetaRuleAbstract* r); /** \brief Registers new code block */ ManagedScpPtr add(CodeScope* scope); /** * \brief Add new type to AST * @param t Type definition * @param alias Typer name */ void add(TypeAnnotation t, Atom alias); /** \brief Current module's name */ std::string getModuleName(); /** * \brief Looks for function with given name * \param name Function name to find * \note Requires that only one function exists under given name * \return Found function */ ManagedPtr findFunction(const std::string& name); /** \brief Returns all function in AST */ std::list getAllFunctions() const; /** * \brief Returns all specializations of a function with a given name * \param fnName function to find * \return list of found function specializations */ std::list getFunctionSpecializations(const std::string& fnName) const; /** * \return First element in Functions/Scopes/Rules list depending on template parameter * \tparam Target either Function or CodeScope or MetaRuleAbstract */ template ManagedPtr begin(); /** * \brief Performs all necessary steps after AST is built * * Performs all finzalisation steps and move AST into consistent state represented by xreate::AST * \sa xreate::AST * \return AST in consistent state */ xreate::AST* finalize(); typedef std::multimap FUNCTIONS_REGISTRY; std::vector __externdata; std::list __dfadata; //TODO move to more appropriate place std::list __rawImports; //TODO move to more appropriate place std::multimap __interfacesData; //TODO CFA data here. private: std::vector __rules; std::vector __functions; std::vector __scopes; FUNCTIONS_REGISTRY __indexFunctions; protected: std::map __indexTypeAliases; public: /** * \brief Stores DFA scheme for later use by DFA Pass * * Treats expression as a DFA scheme and feeds to a DFA Pass later * \paramn Expression DFA Scheme * \sa xreate::DFAPass */ void addDFAData(Expression&& data); /** \brief Stores data for later use by xreate::ExternLayer */ void addExternData(ExternData&& data); /** * \brief Generalized function to store particular data for later use by particular pass * \param interface Particular Interface * \param data Particular data */ void addInterfaceData(const ASTInterface& interface, Expression&& data); /**\name Symbols Recognition */ ///@{ public: //TODO revisit enums/variants, move to codescope /** * \brief Tries to find out whether expression is Variant constructor */ void recognizeVariantConstructor(Expression& function); Atom recognizeVariantConstructor(Atom ident); private: std::map> __dictVariants; public: std::set> bucketUnrecognizedIdentifiers; public: /** * \brief Postpones unrecognized identifier for future second round of recognition * \param scope Code block identifier is encountered * \param id Identifier */ void postponeIdentifier(CodeScope* scope, const Expression& id); /** \brief Second round of identifiers recognition done right after AST is fully constructed */ void recognizePostponedIdentifiers(); ///@} }; template<> ManagedPtr AST::begin(); template<> ManagedPtr AST::begin(); template<> ManagedPtr AST::begin(); } } // namespace details::incomplete /** * \brief Xreate's Syntax Tree in consistent state * * Syntax Tree has two mutually exclusive possible states: * - inconsistent state while AST is under construction. Represented by xreate::details::inconsistent::AST * - consistent state when AST is built and finalize() is done. * * This class represents consistent state and should be used everywhere unless client's code explicitly works with AST under construction. * Consistent AST enables access to additional functions(currently related to type management). * \sa xreate::details::inconsistent::AST */ class AST : public details::inconsistent::AST { public: AST() : details::inconsistent::AST() {} /** * \brief Computes fully expanded form of type by substituting all arguments and aliases * \param t Type to expand * \return Expdanded or normal form of type * \sa TypeAnnotation */ ExpandedType expandType(const TypeAnnotation &t) const; /** * Searches type by given name * \param name Typename to search * \return Expanded or normal form of desired type * \note if type name is not found returns new undefined type with this name */ ExpandedType findType(const std::string& name); /** * Invokes Type Inference Analysis to find out expanded(normal) form expressions's type * \sa typeinference.h * \param expression * \return Type of expression */ ExpandedType getType(const Expression& expression); }; } #endif // AST_H diff --git a/cpp/src/compilation/latecontextcompiler2.cpp b/cpp/src/compilation/latecontextcompiler2.cpp deleted file mode 100644 index 6715761..0000000 --- a/cpp/src/compilation/latecontextcompiler2.cpp +++ /dev/null @@ -1,201 +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/. - * - * LateContextCompiler2.cpp - * - * Created on: 02/10, 2016 - * Author: pgess - * - * \file latecontextcompiler2.h - * \brief Late context compilation. See more on [Late Context](/w/concepts/context#late-context) - */ - -//TOTEST default variants - do not enable specialization context in order to check default variant invocation - -#include "latecontextcompiler2.h" -#include "llvmlayer.h" -#include "pass/compilepass.h" -#include "query/context.h" -#include - -using namespace std; - -namespace xreate {namespace context{ - -const string topicSpecializationAtom = "specialization"; -const string topicDependencyAtom = "dependency"; - -typedef ExpressionSerialization::Code DomainId; -typedef ExpressionSerialization::Serializer Domain; - -//TODO implement variantDefault; -llvm::Value* compileDecisionSelector(llvm::IRBuilder<>& builder, llvm::Value* selector, std::vector vectorVariants, llvm::Value* variantDefault=nullptr){ - assert(vectorVariants.size()>0); - llvm::IntegerType* ty32 = llvm::Type::getInt32Ty(llvm::getGlobalContext()); - - llvm::Type* tyElement = vectorVariants[0]->getType(); - llvm::Type* tyVariants = llvm::VectorType::get(tyElement, vectorVariants.size()); - llvm::Value* vectorRaw = llvm::ConstantVector::getNullValue(tyVariants); - - - for(DomainId i=0; iqueryContext; - __sizeOfDemand = context->getFunctionDemand(function->function->getName()).size(); -} - -llvm::Value* -LateContextCompiler2::findFunction(const std::string& calleeName, llvm::Function* specializationDefault, ScopePacked scopeCaller){ - const string& functionName = function->function->getName(); - ContextQuery* context = pass->queryContext; - llvm::IRBuilder<>& builder = pass->man->llvm->builder; - - const FunctionDemand& demand = context->getFunctionDemand(functionName); - const std::list& specializations = pass->man->root->getFunctionSpecializations(calleeName); - - //independent decision: - Expression topic(Operator::CALL, {(Atom(string(topicSpecializationAtom))), - Expression(Operator::CALL, {Atom(string(calleeName))}), - Atom(scopeCaller)}); - assert(demand.right.count(topic) && "Can't determine specialization for the function"); - size_t topicId = demand.right.at(topic); - llvm::Value* topicDecisionRaw = builder.CreateExtractValue(this->rawContextArgument, llvm::ArrayRef{(unsigned) topicId}); - - const Domain& specializationsDomain= context->getTopicDomain(topic); - - std::vector vectorVariants; - vectorVariants.reserve(specializationsDomain.size()); - for (const ManagedFnPtr& f: specializations){ - if (!f->guardContext.isValid()) continue; - const auto& variantId = specializationsDomain.getIdOptional(f->guardContext); - if (variantId){ - if (vectorVariants.size() < *variantId + 1) { - vectorVariants.resize(*variantId + 1); - } - - vectorVariants[*variantId] = pass->getFunctionUnit(f)->compile(); - } - } - - return compileDecisionSelectorAsSwitch(topicDecisionRaw, vectorVariants, specializationDefault); -} - -llvm::Value* -LateContextCompiler2::compileContextArgument(const std::string& callee, ScopePacked scopeCaller){ - const std::string& atomDependentDecision = Config::get("clasp.context.decisions.dependent"); - llvm::IRBuilder<>& builder = pass->man->llvm->builder; - ContextQuery* context = pass->queryContext; - - const string& functionName = function->function->getName(); - const Decisions& dictStaticDecisions = context->getFinalDecisions(scopeCaller); - - const FunctionDemand& demandCallee = context->getFunctionDemand(callee); - const FunctionDemand& demandSelf = context->getFunctionDemand(functionName); - - llvm::IntegerType* ty32 = llvm::Type::getInt32Ty(llvm::getGlobalContext()); - llvm::Type* tyDemand = llvm::ArrayType::get(ty32, demandCallee.size()); - - //builder.CreateAlloca(tyDemand, llvm::ConstantInt::get(ty32, 1)); - llvm::Value* res = llvm::ConstantArray::getNullValue(tyDemand); - - for (size_t i=0, size = demandCallee.size(); irawContextArgument, llvm::ArrayRef{(unsigned) topicId}); - - } else if (dictStaticDecisions.count(topic)){ - //static final decision: - const Expression& decision = dictStaticDecisions.at(topic); - const Domain& domainOfTopic = context->getTopicDomain(topic); - const DomainId& decisionCode = domainOfTopic.getId(decision); - decisionRaw = llvm::ConstantInt::get(ty32, decisionCode); - - } else { - //dependent decision - decisionRaw = compileDependentDecision(topic, scopeCaller); - } - - res = builder.CreateInsertValue(res, decisionRaw, llvm::ArrayRef{(unsigned) i}); - } - - return res; -} - -llvm::Value* -LateContextCompiler2::compileDependentDecision(const Expression& topic, ScopePacked scopeCaller){ - const string& functionName = function->function->getName(); - ContextQuery* context = pass->queryContext; - llvm::IRBuilder<>& builder = pass->man->llvm->builder; - llvm::IntegerType* ty32 = llvm::Type::getInt32Ty(llvm::getGlobalContext()); - - const FunctionDemand& demandSelf = context->getFunctionDemand(functionName); - const Expression topicDependency = Expression(Operator::CALL, {Atom(string(topicDependencyAtom)), topic, Atom(scopeCaller)}); - - const Domain& demandOfTopic = context->getTopicDomain(topic); - const Domain& domainOfTopicDependency = context->getTopicDomain(topicDependency); - - //dependent decision - vector vectorDecisions(domainOfTopicDependency.size(), llvm::UndefValue::get(ty32)); - for (const std::pair& entry: context->getDependentDecision(scopeCaller,topic)){ - vectorDecisions[domainOfTopicDependency.getId(entry.first)]= llvm::ConstantInt::get(ty32, demandOfTopic.getId(entry.second)); - } - - size_t topicDependencyId = demandSelf.right.at(topicDependency); - llvm::Value* decisionRaw = builder.CreateExtractValue(this->rawContextArgument, llvm::ArrayRef{(unsigned) topicDependencyId}); - - auto result = compileDecisionSelector(pass->man->llvm->builder, decisionRaw, vectorDecisions); - - return result; -} - - - -llvm::Value* -LateContextCompiler2::compileDecisionSelectorAsSwitch(llvm::Value* selector, std::vector vectorVariants, llvm::Function* variantDefault){ - llvm::IRBuilder<>& builder = pass->man->llvm->builder; - llvm::IntegerType* ty32 = llvm::Type::getInt32Ty(llvm::getGlobalContext()); - - llvm::BasicBlock* blockDefault = llvm::BasicBlock::Create(llvm::getGlobalContext(), "caseDefault", this->function->raw); - llvm::BasicBlock *blockEpilog = llvm::BasicBlock::Create(llvm::getGlobalContext(), "VariantDeterminationEnd", this->function->raw); - - llvm::SwitchInst* instrSwitch = builder.CreateSwitch(selector, blockDefault, vectorVariants.size()); - - builder.SetInsertPoint(blockEpilog); - llvm::PHINode *result = builder.CreatePHI(variantDefault->getType(), vectorVariants.size(), "callee"); - - for (size_t i=0; ifunction->raw); - builder.SetInsertPoint(blockCase); - builder.CreateBr(blockEpilog); - result->addIncoming(vectorVariants[i], blockCase); - instrSwitch->addCase(llvm::ConstantInt::get(ty32, i), blockCase); - } - - builder.SetInsertPoint(blockDefault); - builder.CreateBr(blockEpilog); - result->addIncoming(variantDefault, blockDefault); - - builder.SetInsertPoint(blockEpilog); - return result; -} - -size_t -LateContextCompiler2::getFunctionDemandSize() const { - return __sizeOfDemand; -} - -}} /* namespace xreate::context */ diff --git a/cpp/src/compilation/latecontextcompiler2.h b/cpp/src/compilation/latecontextcompiler2.h deleted file mode 100644 index faa33b2..0000000 --- a/cpp/src/compilation/latecontextcompiler2.h +++ /dev/null @@ -1,60 +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/. - * - * LateContextCompiler2.h - * - * Created on: 02/10, 2016 - * Author: pgess - */ - -//TOTEST compile several context arguments -#ifndef LATECONTEXTCOMPILER2_H_ -#define LATECONTEXTCOMPILER2_H_ - -#include "serialization.h" - -namespace llvm { - class Value; - class Function; -} - -namespace xreate { - class CompilePass; - -namespace compilation { - class IFunctionUnit; -}} - -namespace xreate {namespace context{ - -typedef unsigned int ScopePacked; - -/** \brief Encapsulates compilation of Late Context - * \sa xreate::context::ContextQuery, xreate::compilation::BasicCodeScopeUnit - */ -class LateContextCompiler2 { -public: - llvm::Value* rawContextArgument = nullptr; - - LateContextCompiler2(compilation::IFunctionUnit* f, CompilePass* p); - - /** \brief Finds function with regard to late context*/ - llvm::Value* findFunction(const std::string& calleeName, llvm::Function* specializationDefault, ScopePacked scopeCaller); - llvm::Value* compileContextArgument(const std::string& callee, ScopePacked scopeCaller); - size_t getFunctionDemandSize() const; - -private: - //boost::bimap __decisions; - //std::vector __scheme; - - compilation::IFunctionUnit* function; - CompilePass* pass; - size_t __sizeOfDemand; - - llvm::Value* compileDependentDecision(const Expression& topic, ScopePacked scopeCaller); - llvm::Value* compileDecisionSelectorAsSwitch(llvm::Value* selector, std::vector vectorVariants, llvm::Function* variantDefault); -}; -}} /* namespace xreate::context */ - -#endif /* LATECONTEXTCOMPILER2_H_ */ diff --git a/cpp/src/compilation/polymorphcompiler.h b/cpp/src/compilation/polymorphcompiler.h index 1d61e1d..0d29cae 100644 --- a/cpp/src/compilation/polymorphcompiler.h +++ b/cpp/src/compilation/polymorphcompiler.h @@ -1,68 +1,63 @@ /* * 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" namespace xreate { namespace polymorph { typedef Expression Guard; template class PolymorphCodeScopeUnit: public Parent{ public: 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 const std::string& nameCallee = opCall.getValueString(); const std::list& specializations = Parent::pass->man->root->getFunctionSpecializations(nameCallee); //Extern function 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()) { return Parent::findFunction(opCall); } } - //TODO There are overlapping guards and contexts. For now, skip if context found. - if (specializations.front()->guardContext.isValid()){ - return Parent::findFunction(opCall); - } - //Several specializations assert(Attachments::exists(opCall) && "Guard required"); const Expression& guardSelected = Attachments::get(opCall); std::map indexSpecs; for(ManagedFnPtr specialization: specializations){ indexSpecs.emplace(specialization->guard, specialization); } assert(indexSpecs.count(guardSelected) && "Can't found appropriate guard"); return new compilation::CallStatementRaw(Parent::pass->getFunctionUnit(indexSpecs.at(guardSelected))->compile(), Parent::pass->man->llvm); } }; } } //end of xreate::polymorph #endif /* POLYMORPHCOMPILER_H */ diff --git a/cpp/src/compilation/scopedecorators.h b/cpp/src/compilation/scopedecorators.h index 3fbf541..adf7c72 100644 --- a/cpp/src/compilation/scopedecorators.h +++ b/cpp/src/compilation/scopedecorators.h @@ -1,151 +1,157 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * File: scopedecorators.h * Author: pgess * * Created on February 24, 2017, 11:35 AM */ /** * \file scopedecorators.h * \brief Basic code block compilation xreate::compilation::ICodeScopeUnit decorators */ #ifndef SCOPEDECORATORS_H #define SCOPEDECORATORS_H #include "ast.h" #include "compilation/targetinterpretation.h" #include "compilation/versions.h" #include "compilation/transformations.h" #include "compilation/polymorphcompiler.h" +#include namespace xreate { class CompilePass; namespace compilation { class ICodeScopeUnit; class IFunctionUnit; /**\brief Caching ability for code scope compilation * \extends xreate::compilation::ICodeScopeUnit */ template class CachedScopeDecorator: public Parent{ typedef CachedScopeDecorator SELF; public: CachedScopeDecorator(const CodeScope* const codeScope, IFunctionUnit* f, CompilePass* compilePass): Parent(codeScope, f, compilePass){} Symbol bindArg(llvm::Value* value, std::string&& alias) { //ensure existence of an alias assert(Parent::scope->__identifiers.count(alias)); //memorize new value for an alias ScopedSymbol id{Parent::scope->__identifiers.at(alias), versions::VERSION_NONE}; __rawVars[id] = value; return Symbol{id, Parent::scope}; } void bindArg(llvm::Value* value, const ScopedSymbol& s) { __rawVars[s] = value; } llvm::Value* compile(const std::string& hintBlockDecl="") override{ if (__rawVars.count(ScopedSymbol::RetSymbol)){ return __rawVars[ScopedSymbol::RetSymbol]; } return Parent::compile(hintBlockDecl); } llvm::Value* processSymbol(const Symbol& s, std::string hintRetVar) override{ const CodeScope* scope = s.scope; SELF* self = dynamic_cast(Parent::function->getScopeUnit(scope)); if (self->__rawVars.count(s.identifier)){ return self->__rawVars[s.identifier]; } //Declaration could be overriden /* Expression declaration = CodeScope::getDefinition(s, true); if (!declaration.isDefined()){ assert(__declarationsOverriden.count(s.identifier)); declaration = __declarationsOverriden[s.identifier]; } else { (false); //in case of binding there should be raws provided. } } */ llvm::Value* resultRaw = Parent::processSymbol(s, hintRetVar); self->__rawVars.emplace(s.identifier, resultRaw); return resultRaw; } void - overrideDeclaration(const Symbol binding, Expression&& declaration){ - SELF* self = dynamic_cast(Parent::function->getScopeUnit(binding.scope)); - - self->__declarationsOverriden.emplace(binding.identifier, std::move(declaration)); + overrideDeclarations(std::list> bindings){ + reset(); + + for (auto entry: bindings){ + SELF* self = dynamic_cast(Parent::function->getScopeUnit(entry.first.scope)); + assert(self == this); + + self->__declarationsOverriden.emplace(entry.first.identifier, entry.second); + } } void registerChildScope(std::shared_ptr scope){ __childScopes.push_back(scope); } void reset(){ __rawVars.clear(); __declarationsOverriden.clear(); __childScopes.clear(); } private: std::unordered_map __declarationsOverriden; std::unordered_map __rawVars; std::list> __childScopes; }; /**\brief Default code scope compilation functionality*/ typedef CachedScopeDecorator< polymorph::PolymorphCodeScopeUnit< ::xreate::compilation::TransformationsScopeDecorator< interpretation::InterpretationScopeDecorator< versions::VersionsScopeDecorator>>>> DefaultCodeScopeUnit; } //end of compilation namespace struct CachedScopeDecoratorTag; struct VersionsScopeDecoratorTag; template<> struct DecoratorsDict{ typedef compilation::CachedScopeDecorator< polymorph::PolymorphCodeScopeUnit< compilation::TransformationsScopeDecorator< interpretation::InterpretationScopeDecorator< versions::VersionsScopeDecorator>>>> result; }; template<> struct DecoratorsDict{ typedef versions::VersionsScopeDecorator< compilation::BasicCodeScopeUnit> result; }; } //end of xreate #endif /* SCOPEDECORATORS_H */ diff --git a/cpp/src/compilation/targetinterpretation.cpp b/cpp/src/compilation/targetinterpretation.cpp index 6b61305..ae9237f 100644 --- a/cpp/src/compilation/targetinterpretation.cpp +++ b/cpp/src/compilation/targetinterpretation.cpp @@ -1,595 +1,644 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * File: targetinterpretation.cpp * Author: pgess * * Created on June 29, 2016, 6:45 PM */ /** * \file targetinterpretation.h * \brief Interpretation support. See more [details on Interpretation](/w/concepts/dsl/) */ #include "compilation/targetinterpretation.h" #include "pass/interpretationpass.h" #include "analysis/typeinference.h" #include "llvmlayer.h" #include "compilation/scopedecorators.h" #include #include #include +#include using namespace std; using namespace xreate::compilation; namespace xreate{ namespace interpretation{ - const Expression EXPRESSION_FALSE = Expression(Atom(0)); const Expression EXPRESSION_TRUE = Expression(Atom(1)); Expression representAsAnnotation(const Gringo::Symbol& atom){ switch (atom.type()) { case Gringo::SymbolType::Num: { Expression result(Operator::VARIANT, {Expression(atom.num())}); result.setValueDouble(0); return result; } case Gringo::SymbolType::Str: { Expression result(Operator::VARIANT, {Expression(Atom(std::string(atom.string().c_str())))}); result.setValueDouble(1); return result; } - case Gringo::SymbolType::Fun: - { + case Gringo::SymbolType::Fun: { Expression fnDescription(Operator::LIST_NAMED, {}); std::list> bindings{Atom("name"), Atom("arguments")}; fnDescription.addBindings(bindings.begin(), bindings.end()); - fnDescription.addArg(Expression(Atom(std::string(atom.name().c_str())))); Expression args(Operator::LIST, {}); for (const Gringo::Symbol& arg : atom.args()) { args.addArg(representAsAnnotation(arg)); } fnDescription.addArg(std::move(args)); Expression result(Operator::VARIANT, {fnDescription}); result.setValueDouble(2); return result; } - default: - { + default: { assert(false); } } } CodeScope* InterpretationScope::processOperatorIf(const Expression& expression){ const Expression& exprCondition = process(expression.getOperands()[0]); if (exprCondition == EXPRESSION_TRUE){ return expression.blocks.front(); } return expression.blocks.back(); } CodeScope* InterpretationScope::processOperatorSwitch(const Expression& expression) { const Expression& exprCondition = process(expression.operands[0]); bool flagHasDefault = expression.operands[1].op == Operator::CASE_DEFAULT; //TODO check that one and only one case variant is appropriate for (size_t size = expression.operands.size(), i= flagHasDefault? 2: 1; igetScope((const CodeScope*) exprCase.blocks.front())->processScope() == exprCondition){ return exprCase.blocks.back(); } } if (flagHasDefault){ const Expression& exprCaseDefault = expression.operands[1]; return exprCaseDefault.blocks.front(); } assert(false && "Switch has no appropriate variant"); return nullptr; } CodeScope* InterpretationScope::processOperatorSwitchVariant(const Expression& expression){ const Expression& condition = process(expression.operands.at(0)); assert(condition.op == Operator::VARIANT); const string& identCondition = expression.bindings.front(); Expression opExpected(Atom(condition.getValueDouble())); auto itFoundValue = std::find(++expression.operands.begin(), expression.operands.end(), opExpected); assert(itFoundValue != expression.operands.end()); int indexBlock = itFoundValue - expression.operands.begin() -1; auto blockFound = expression.blocks.begin(); std::advance(blockFound, indexBlock); InterpretationScope* scopeI12n = function->getScope(*blockFound); - if (condition.operands.size()) { - const Expression& value = condition.operands.at(0); - scopeI12n->overrideBinding(value, identCondition); - } + 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->overrideDeclaration(symbCondition, Expression(valueCondition.operands.at(0))); + scopeCompilation->overrideDeclarations( + {{symbCondition, Expression(valueCondition.operands.at(0))}} + ); //set correct type for binding: TypeAnnotation typeVariant = typeinference::getType(condition, *function->man->ast); int conditionIndex = valueCondition.getValueDouble(); ScopedSymbol symbolInternal = scopeResult->getSymbol(identCondition); scopeResult->__declarations[symbolInternal].bindType(typeVariant.__operands.at(conditionIndex)); } llvm::Value* result = context.function->getScopeUnit(scopeResult)->compile(); return result; } case FOLD_INTERPRET_INPUT: { //initialization const Expression& exprInput = process(expression.getOperands()[0]); assert(exprInput.op == Operator::LIST); CodeScope* scopeBody = expression.blocks.front(); const string& nameEl = expression.bindings[0]; Symbol symbEl{ScopedSymbol{scopeBody->__identifiers.at(nameEl), versions::VERSION_NONE}, scopeBody}; const std::string& idAccum = expression.bindings[1]; llvm::Value* rawAccum = context.scope->process(expression.getOperands()[1]); InterpretationScope* intrBody = function->getScope(scopeBody); auto unitBody = Decorators::getInterface(context.function->getScopeUnit(scopeBody)); const std::vector elementsInput= exprInput.getOperands(); - for (size_t i=0; ireset(); - unitBody->reset(); + for(size_t i=0; ioverrideBindings({ + {exprElement, nameEl}}); + unitBody->overrideDeclarations({ + {symbEl, exprElement}}); //resets unitBody + unitBody->bindArg(rawAccum, string(idAccum)); - intrBody->overrideBinding(exprElement, nameEl); - unitBody->overrideDeclaration(symbEl, move(exprElement)); - unitBody->bindArg(rawAccum, string(idAccum)); - - rawAccum = unitBody->compile(); + rawAccum=unitBody->compile(); } return rawAccum; } /* case FOLD_INF_INTERPRET_INOUT{ } */ //TODO refactor as InterpretationCallStatement class case CALL_INTERPRET_PARTIAL: { const std::string &calleeName = expression.getValueString(); ICodeScopeUnit* scopeUnitSelf = context.scope; ManagedFnPtr callee = this->function->man->ast->findFunction(calleeName); const FunctionInterpretationData& calleeData = FunctionInterpretationHelper::getSignature(callee); std::vector argsActual; PIFSignature sig; sig.declaration = callee; for(size_t no=0, size = expression.operands.size(); no < size; ++no){ const Expression& op = expression.operands[no]; if (calleeData.signature.at(no) == INTR_ONLY){ sig.bindings.push_back(process(op)); continue; } argsActual.push_back(scopeUnitSelf->process(op)); } TargetInterpretation* man = dynamic_cast(this->function->man); PIFunction* pifunction = man->getFunction(move(sig)); llvm::Function* raw = pifunction->compile(); boost::scoped_ptr statement(new CallStatementRaw(raw, man->pass->man->llvm)); return (*statement)(move(argsActual)); } default: break; } assert(false&& "Unknown hybrid operator"); return nullptr; } llvm::Value* InterpretationScope::compile(const Expression& expression, const Context& context){ const InterpretationData& data = Attachments::get(expression); if (data.op != InterpretationOperator::NONE){ return compileHybrid(data.op, expression, context); } Expression result = process(expression); return context.scope->process(result); } Expression -InterpretationScope::process(const Expression& expression){ +InterpretationScope::process(const Expression& expression) { +#ifndef NDEBUG + if (expression.tags.count("bpoint")){ + std::raise(SIGINT); + } +#endif + + PassManager* man = (static_cast (function->man))->pass->man; + switch (expression.__state){ case Expression::INVALID: assert(false); case Expression::NUMBER: case Expression::STRING: return expression; case Expression::IDENT:{ Symbol s = Attachments::get(expression); return Parent::processSymbol(s); } case Expression::COMPOUND: break; default: assert(false); } switch (expression.op) { case Operator::EQU: { const Expression& left = process(expression.operands[0]); const Expression& right = process(expression.operands[1]); if (left == right) return EXPRESSION_TRUE; return EXPRESSION_FALSE; } case Operator::NE: { const Expression& left = process(expression.operands[0]); const Expression& right = process(expression.operands[1]); if (left == right) return EXPRESSION_FALSE; return EXPRESSION_TRUE; } case Operator::LOGIC_AND: { assert(expression.operands.size() == 1); return process (expression.operands[0]); } // case Operator::LOGIC_OR: case Operator::CALL: { const std::string &fnName = expression.getValueString(); ManagedFnPtr fnAst = this->function->man->ast->findFunction(fnName); InterpretationFunction* fnUnit = this->function->man->getFunction(fnAst); vector args; args.reserve(expression.getOperands().size()); for(size_t i=0, size = expression.getOperands().size(); iprocess(args); } case Operator::CALL_INTRINSIC: { std::string nameFunction = expression.getValueString(); if(nameFunction=="query"){ assert(expression.operands.size() == 1); assert(expression.operands.front().__state == Expression::STRING); std::string namePredicate = expression.operands.front().getValueString(); ClaspLayer::ModelFragment model = (static_cast(function->man))->pass->man->clasp->query(namePredicate); Expression result(Operator::LIST, {}); if(model) for (const auto& row: boost::make_iterator_range(model.get())) { result.addArg(representAsAnnotation(std::get<1>(row))); } - return result; + return result; + + } else if(nameFunction=="query_scope"){ + ScopePacked scopeId = man->clasp->pack(scope); + Expression result(Operator::VARIANT, {Expression(scopeId)}); + result.setValueDouble(0); + return result; } else { assert(false && "Unknown intrinsic"); } } case Operator::IF:{ CodeScope* scopeResult = processOperatorIf(expression); return function->getScope(scopeResult)->processScope(); } case Operator::SWITCH: { CodeScope* scopeResult = processOperatorSwitch(expression); return function->getScope(scopeResult)->processScope(); } case Operator::SWITCH_VARIANT: { CodeScope* scopeResult = processOperatorSwitchVariant(expression); return function->getScope(scopeResult)->processScope(); } + case Operator::VARIANT: { + if(!expression.operands.size()) return expression; + + Expression variantData = process(expression.operands[0]); + Expression result{Operator::VARIANT, {variantData}}; + result.setValueDouble(expression.getValueDouble()); + return result; + } + case Operator::INDEX: { Expression exprData = process(expression.operands[0]); for (size_t keyId=1; keyIdgetScope(expression.blocks.front()); Expression accum = exprInit; for(size_t size=exprInput.getOperands().size(), i=0; ioverrideBinding(exprInput.getOperands()[i], argEl); - body->overrideBinding(accum, argAccum); + body->overrideBindings({ + {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); - for(size_t i=0, size = args.size(); ioverrideBinding(args.at(i), string(body->scope->__bindings.at(i))); + 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{ + +class PIFunctionUnit : public PIFunctionUnitParent { public: PIFunctionUnit(ManagedFnPtr f, std::set&& arguments, size_t id, CompilePass* p) - : PIFunctionUnitParent(f, p), argumentsActual(move(arguments)), __id(id) - {} + : 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)) -{ +: InterpretationFunction(sig.declaration, target), signatureInstance(move(sig)) { const FunctionInterpretationData& functionData = FunctionInterpretationHelper::getSignature(signatureInstance.declaration); std::set argumentsActual; for (size_t no=0, size=functionData.signature.size(); no < size; ++no){ if (functionData.signature.at(no) != INTR_ONLY){ argumentsActual.insert(no); } } functionUnit = new PIFunctionUnit(signatureInstance.declaration, move(argumentsActual), id, target->pass); CodeScope* entry = signatureInstance.declaration->__entry; auto entryUnit = Decorators::getInterface<>(functionUnit->getEntry()); InterpretationScope* entryIntrp = InterpretationFunction::getScope(entry); - for(size_t no=0, sigNo=0, size = entry->__bindings.size(); no < size; ++no){ - if (functionData.signature.at(no) == INTR_ONLY){ - entryIntrp->overrideBinding(signatureInstance.bindings[sigNo], entry->__bindings[no]); + list> bindingsPartial; + list> declsPartial; - VNameId argId = entry->__identifiers.at(entry->__bindings[no]); - Symbol argSymbol{ScopedSymbol{argId, versions::VERSION_NONE}, entry}; - entryUnit->overrideDeclaration(argSymbol, Expression(signatureInstance.bindings[sigNo])); + for(size_t no=0, sigNo=0, size=entry->__bindings.size(); no__bindings[no]}); + + VNameId argId=entry->__identifiers.at(entry->__bindings[no]); + Symbol argSymbol{ScopedSymbol + {argId, versions::VERSION_NONE}, entry}; + declsPartial.push_back({argSymbol, signatureInstance.bindings[sigNo]}); ++sigNo; } } + + entryIntrp->overrideBindings(bindingsPartial); + entryUnit->overrideDeclarations(declsPartial); } llvm::Function* PIFunction::compile(){ llvm::Function* raw = functionUnit->compile(); return raw; } bool operator<(const PIFSignature& lhs, const PIFSignature& rhs){ if (lhs.declaration.id() != rhs.declaration.id()) { return lhs.declaration.id() < rhs.declaration.id(); } return lhs.bindings < rhs.bindings; } bool operator<(const PIFSignature& lhs, PIFunction* const rhs){ return lhs < rhs->signatureInstance; } bool operator<(PIFunction* const lhs, const PIFSignature& rhs){ return lhs->signatureInstance < rhs; } }} /** \class xreate::interpretation::InterpretationFunction * * Holds list of xreate::interpretation::InterpretationScope 's focused on interpretation of individual code scopes * * There is particulat subclass PIFunction intended to represent partially interpreted functions *\sa TargetInterpretation, [Interpretation Concept](/w/concepts/dfa) */ /** \class xreate::interpretation::TargetInterpretation * * Executed during compilation and intented to preprocess eligible parts of code. * Established on [Targets Infrastructure](\ref compilation::Target) * * Holds list of InterpretationFunction / PIFunction to represent interpretation process for individual functions * * In order to be activated during compilation process there is * InterpretationScopeDecorator implementation of ICodeScopeUnit * \sa InterpretationPass, compilation::Target, [Interpretation Concept](/w/concepts/dfa) * */ \ No newline at end of file diff --git a/cpp/src/compilation/targets.h b/cpp/src/compilation/targets.h index 1b86b31..dee23be 100644 --- a/cpp/src/compilation/targets.h +++ b/cpp/src/compilation/targets.h @@ -1,201 +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/. * * 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 "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; 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() { - if (raw) return *raw; - - raw = process(scope->getBody()); - return *raw; + 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 - overrideBinding(typename TargetInfo::Result arg, const std::string& name){ - assert(scope->__identifiers.count(name)); + overrideBindings(std::list::Result, std::string>> bindings){ + reset(); - ScopedSymbol id{scope->__identifiers.at(name), versions::VERSION_NONE}; - __bindings[id] = arg; - - //reset the result if any: - raw.reset(); + for (auto entry: bindings){ + assert(scope->__identifiers.count(entry.second)); + ScopedSymbol id{scope->__identifiers.at(entry.second), versions::VERSION_NONE}; + + __bindings[id] = entry.first; + } } void registerChildScope(std::shared_ptr scope){ __childScopes.push_back(scope); } void reset(){ __bindings.clear(); __childScopes.clear(); - raw.reset(); } protected: Function* function=0; std::map::Result> __bindings; std::list> __childScopes; - typename boost::optional::Result> raw; }; 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/contextrule.h b/cpp/src/contextrule.h index 2c70f8e..8d7227b 100644 --- a/cpp/src/contextrule.h +++ b/cpp/src/contextrule.h @@ -1,34 +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/. * * contextrule.h * * Created on: Jan 2, 2016 * Author: pgess */ #ifndef SRC_CONTEXTRULE_H_ #define SRC_CONTEXTRULE_H_ #include "ast.h" #include namespace xreate { typedef unsigned int ScopePacked; class ContextRule { - public: - ContextRule(const Expression& rule); - std::string compile(const ScopePacked& scopeId) const; - - private: - Expression head; - Expression guards; - Expression body; +public: + ContextRule(const Expression& rule); + std::string compile(const ScopePacked& scopeId) const; + +private: + Expression head; + Expression guards; + Expression body; }; } #endif /* SRC_CONTEXTRULE_H_ */ diff --git a/cpp/src/pass/compilepass.cpp b/cpp/src/pass/compilepass.cpp index 6c173ed..b66b7d5 100644 --- a/cpp/src/pass/compilepass.cpp +++ b/cpp/src/pass/compilepass.cpp @@ -1,873 +1,740 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * Author: pgess * * compilepass.cpp */ /** * \file compilepass.h * \brief Compilation pass */ #include "compilepass.h" #include "clasplayer.h" #include #include "llvmlayer.h" #include "query/containers.h" #include "query/context.h" #include "compilation/containers.h" -#include "compilation/latecontextcompiler2.h" #include "ExternLayer.h" #include "pass/adhocpass.h" #include "compilation/targetinterpretation.h" #include "pass/versionspass.h" #include "compilation/scopedecorators.h" #include "compilation/adhocfunctiondecorator.h" #include "compilation/operators.h" #include "analysis/typeinference.h" #include #include #include using namespace std; using namespace llvm; -//TODO use Scope - - //SECTIONTAG late-context FunctionDecorator - -namespace xreate{namespace context{ - -/** \brief Late Context enabled decorator for IFunctionUnit - * \extends IFunctionUnit - */ -template -class LateContextFunctionDecorator : public Parent { -public: - LateContextFunctionDecorator(ManagedFnPtr f, CompilePass* p) - : Parent(f, p), contextCompiler(this, p) { - } - -protected: - std::vector prepareArguments() { - std::vector&& arguments = Parent::prepareArguments(); - - size_t sizeLateContextDemand = contextCompiler.getFunctionDemandSize(); - if (sizeLateContextDemand) { - llvm::Type* ty32 = llvm::Type::getInt32Ty(llvm::getGlobalContext()); - llvm::Type* tyDemand = llvm::ArrayType::get(ty32, sizeLateContextDemand); - - arguments.push_back(tyDemand); - } - - return arguments; - } - - llvm::Function::arg_iterator prepareBindings() { - llvm::Function::arg_iterator fargsI = Parent::prepareBindings(); - - size_t sizeLateContextDemand = contextCompiler.getFunctionDemandSize(); - if (sizeLateContextDemand) { - fargsI->setName("latecontext"); - contextCompiler.rawContextArgument = &*fargsI; - ++fargsI; - } - - return fargsI; - } - -public: - context::LateContextCompiler2 contextCompiler; -}; - -}} //end of namespace xreate::context - namespace xreate { namespace compilation{ std::string BasicFunctionUnit::prepareName(){ AST* ast = IFunctionUnit::pass->man->root; string name = ast->getFunctionSpecializations(IFunctionUnit::function->__name).size() > 1 ? IFunctionUnit::function->__name + std::to_string(IFunctionUnit::function.id()) : IFunctionUnit::function->__name; return name; } std::vector BasicFunctionUnit::prepareArguments() { LLVMLayer* llvm = IFunctionUnit::pass->man->llvm; AST* ast = IFunctionUnit::pass->man->root; CodeScope* entry = IFunctionUnit::function->__entry; std::vector signature; std::transform(entry->__bindings.begin(), entry->__bindings.end(), std::inserter(signature, signature.end()), [llvm, ast, entry](const std::string & arg)->llvm::Type* { assert(entry->__identifiers.count(arg)); ScopedSymbol argid{entry->__identifiers.at(arg), versions::VERSION_NONE}; return llvm->toLLVMType(ast->expandType(entry->__declarations.at(argid).type)); }); return signature; } llvm::Type* BasicFunctionUnit::prepareResult() { LLVMLayer* llvm = IFunctionUnit::pass->man->llvm; AST* ast = IFunctionUnit::pass->man->root; CodeScope* entry = IFunctionUnit::function->__entry; return llvm->toLLVMType(ast->expandType(entry->__declarations.at(ScopedSymbol::RetSymbol).type)); } llvm::Function::arg_iterator BasicFunctionUnit::prepareBindings() { CodeScope* entry = IFunctionUnit::function->__entry; ICodeScopeUnit* entryCompilation = IFunctionUnit::getScopeUnit(entry); llvm::Function::arg_iterator fargsI = IFunctionUnit::raw->arg_begin(); for (std::string &arg : entry->__bindings) { ScopedSymbol argid{entry->__identifiers[arg], versions::VERSION_NONE}; entryCompilation->bindArg(&*fargsI, argid); fargsI->setName(arg); ++fargsI; } return fargsI; } //DEBT compiler rigidly depends on exact definition of DefaultFunctionUnit -typedef context::LateContextFunctionDecorator< - adhoc::AdhocFunctionDecorator< - BasicFunctionUnit>> DefaultFunctionUnit; +typedef adhoc::AdhocFunctionDecorator< + BasicFunctionUnit> DefaultFunctionUnit; ICodeScopeUnit::ICodeScopeUnit(const CodeScope* const codeScope, IFunctionUnit* f, CompilePass* compilePass) : pass(compilePass), function(f), scope(codeScope), currentBlockRaw(nullptr) { } llvm::Value* CallStatementRaw::operator()(std::vector&& args, const std::string& hintDecl) { llvm::Function* calleeInfo = dyn_cast(__callee); if (calleeInfo) { auto argsFormal = calleeInfo->args(); int pos = 0; //SECTIONTAG types/convert function ret value for (auto argFormal = argsFormal.begin(); argFormal != argsFormal.end(); ++argFormal, ++pos) { args[pos] = typeinference::doAutomaticTypeConversion(args[pos], argFormal->getType(), llvm->builder); } } //Do not name function call that returns Void. std::string nameStatement = hintDecl; if (calleeInfo->getReturnType()->isVoidTy()){ nameStatement.clear(); } return llvm->builder.CreateCall(__calleeTy, __callee, args, nameStatement); } //DESABLEDFEATURE implement inlining class CallStatementInline : public ICallStatement { public: CallStatementInline(IFunctionUnit* caller, IFunctionUnit* callee, LLVMLayer* l) : __caller(caller), __callee(callee), llvm(l) { } llvm::Value* operator()(std::vector&& args, const std::string& hintDecl) { //TOTEST inlining // CodeScopeUnit* entryCompilation = outer->getScopeUnit(function->__entry); // for(int i=0, size = args.size(); ibindArg(args.at(i), string(entryCompilation->scope->__bindings.at(i))); // } // // // return entryCompilation->compile(); return nullptr; } private: IFunctionUnit* __caller; IFunctionUnit* __callee; LLVMLayer* llvm; bool isInline() { // Symbol ret = Symbol{0, function->__entry}; // bool flagOnTheFly = SymbolAttachments::get(ret, false); //TODO consider inlining return false; } }; BasicCodeScopeUnit::BasicCodeScopeUnit(const CodeScope* const codeScope, IFunctionUnit* f, CompilePass* compilePass) : ICodeScopeUnit(codeScope, f, compilePass) { } llvm::Value* BasicCodeScopeUnit::processSymbol(const Symbol& s, std::string hintRetVar) { Expression declaration = CodeScope::getDefinition(s); const CodeScope* scope = s.scope; ICodeScopeUnit* scopeExternal = ICodeScopeUnit::function->getScopeUnit(scope); llvm::Value* resultRaw; if (scopeExternal == this){ resultRaw = process(declaration, hintRetVar); currentBlockRaw = pass->man->llvm->builder.GetInsertBlock(); } else { assert(scopeExternal->currentBlockRaw); llvm::BasicBlock* blockOwn = pass->man->llvm->builder.GetInsertBlock(); pass->man->llvm->builder.SetInsertPoint(scopeExternal->currentBlockRaw); resultRaw = scopeExternal->processSymbol(s, hintRetVar); pass->man->llvm->builder.SetInsertPoint(blockOwn); } return resultRaw; } -//TASK Isolate out context functionalty in decorator -//TOTEST static late context decisions -//TOTEST dynamic late context decisions ICallStatement* BasicCodeScopeUnit::findFunction(const Expression& opCall) { const std::string& calleeName = opCall.getValueString(); LLVMLayer* llvm = pass->man->llvm; - ClaspLayer* clasp = pass->man->clasp; - DefaultFunctionUnit* function = dynamic_cast (this->function); - context::ContextQuery* queryContext = pass->queryContext; - 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); } - //no decisions required - if (specializations.size() == 1) { - if (!specializations.front()->guardContext.isValid()) { - return new CallStatementRaw(pass->getFunctionUnit(specializations.front())->compile(), llvm); - } - } - - //TODO move dictSpecialization over to a separate function in order to perform cache, etc. - //prepare specializations dictionary - std::map dictSpecializations; - - boost::optional variantDefault; - boost::optional variant; - - for (const ManagedFnPtr& f : specializations) { - const Expression& guard = f->guardContext; - - //default case: - if (!guard.isValid()) { - variantDefault = f; - continue; - } - - assert(dictSpecializations.emplace(guard, f).second && "Found several identical specializations"); - } - - //check static context - ScopePacked scopeCaller = clasp->pack(this->scope); - const string atomSpecialization = "specialization"; - const Expression topicSpecialization(Operator::CALL,{(Atom(string(atomSpecialization))), - Expression(Operator::CALL, - {Atom(string(calleeName))}), - Atom(scopeCaller)}); - - const context::Decisions& decisions = queryContext->getFinalDecisions(scopeCaller); - if (decisions.count(topicSpecialization)) { - variant = dictSpecializations.at(decisions.at(topicSpecialization)); - } - - //TODO check only demand for this particular topic. - size_t sizeDemand = function->contextCompiler.getFunctionDemandSize(); - - //decision made if static context found or no late context exists(and there is default variant) - bool flagHasStaticDecision = variant || (variantDefault && !sizeDemand); - - //if no late context exists - if (flagHasStaticDecision) { - IFunctionUnit* calleeUnit = pass->getFunctionUnit(variant ? *variant : *variantDefault); - - //inlining possible based on static decision only - // if (calleeUnit->isInline()) { - // return new CallStatementInline(function, calleeUnit); - // } - - return new CallStatementRaw(calleeUnit->compile(), llvm); - } - - //require default variant if no static decision made - assert(variantDefault); - - llvm::Function* functionVariantDefault = this->pass->getFunctionUnit(*variantDefault)->compile(); - llvm::Value* resultFn = function->contextCompiler.findFunction(calleeName, functionVariantDefault, scopeCaller); - llvm::PointerType *resultPTy = cast(resultFn->getType()); - llvm::FunctionType *resultFTy = cast(resultPTy->getElementType()); - return new CallStatementRaw(resultFn, resultFTy, llvm); + //There should be only one specialization without any valid guards at this point + return new CallStatementRaw(pass->getFunctionUnit( + pass->man->root->findFunction(calleeName))->compile(), + llvm); } - - //DISABLEDFEATURE transformations // if (pass->transformations->isAcceptable(expr)){ // return pass->transformations->transform(expr, result, ctx); // } llvm::Value* BasicCodeScopeUnit::process(const Expression& expr, const std::string& hintVarDecl) { #define DEFAULT(x) (hintVarDecl.empty()? x: hintVarDecl) llvm::Value *left; llvm::Value *right; LLVMLayer& l = *pass->man->llvm; xreate::compilation::AdvancedInstructions instructions = xreate::compilation::AdvancedInstructions({this, function, pass}); switch (expr.op) { case Operator::SUB: case Operator::MUL: case Operator::DIV: case Operator::EQU: case Operator::LSS: case Operator::GTR: case Operator::NE: case Operator::LSE: case Operator::GTE: assert(expr.__state == Expression::COMPOUND); assert(expr.operands.size() == 2); left = process(expr.operands[0]); right = process(expr.operands[1]); //SECTIONTAG types/convert binary operation right = typeinference::doAutomaticTypeConversion(right, left->getType(), l.builder); break; default:; } switch (expr.op) { case Operator::ADD: { left = process(expr.operands[0]); Context context{this, function, pass}; llvm::Value* resultSU = StructUpdate::add(expr.operands[0], left, expr.operands[1], context, DEFAULT("tmp_add")); if (resultSU) return resultSU; right = process(expr.operands[1]); llvm::Value* resultAddPA = pointerarithmetic::PointerArithmetic::add(left, right, context, DEFAULT("tmp_add")); if (resultAddPA) { return resultAddPA; } return l.builder.CreateAdd(left, right, DEFAULT("tmp_add")); break; } case Operator::SUB: return l.builder.CreateSub(left, right, DEFAULT("tmp_sub")); break; case Operator::MUL: return l.builder.CreateMul(left, right, DEFAULT("tmp_mul")); break; case Operator::DIV: return l.builder.CreateSDiv(left, right, DEFAULT("tmp_div")); break; case Operator::EQU: if (left->getType()->isIntegerTy()) return l.builder.CreateICmpEQ(left, right, DEFAULT("tmp_equ")); if (left->getType()->isFloatingPointTy()) return l.builder.CreateFCmpOEQ(left, right, DEFAULT("tmp_equ")); break; case Operator::NE: return l.builder.CreateICmpNE(left, right, DEFAULT("tmp_ne")); break; case Operator::LSS: return l.builder.CreateICmpSLT(left, right, DEFAULT("tmp_lss")); break; case Operator::LSE: return l.builder.CreateICmpSLE(left, right, DEFAULT("tmp_lse")); break; case Operator::GTR: return l.builder.CreateICmpSGT(left, right, DEFAULT("tmp_gtr")); break; case Operator::GTE: return l.builder.CreateICmpSGE(left, right, DEFAULT("tmp_gte")); break; case Operator::NEG: left = process(expr.operands[0]); return l.builder.CreateNeg(left, DEFAULT("tmp_neg")); break; case Operator::CALL: { assert(expr.__state == Expression::COMPOUND); shared_ptr callee(findFunction(expr)); const std::string& nameCallee = expr.getValueString(); //prepare arguments std::vector args; args.reserve(expr.operands.size()); std::transform(expr.operands.begin(), expr.operands.end(), std::inserter(args, args.end()), [this](const Expression & operand) { return process(operand); } ); - ScopePacked outerScopeId = pass->man->clasp->pack(this->scope); - - //TASK a) refactor CALL/ADHOC/find function - //SECTIONTAG late-context propagation arg - size_t calleeDemandSize = pass->queryContext->getFunctionDemand(nameCallee).size(); - if (calleeDemandSize) { - DefaultFunctionUnit* function = dynamic_cast (this->function); - llvm::Value* argLateContext = function->contextCompiler.compileContextArgument(nameCallee, outerScopeId); - args.push_back(argLateContext); - } - return (*callee)(move(args), DEFAULT("res_" + nameCallee)); } case Operator::IF: { return instructions.compileIf(expr, DEFAULT("tmp_if")); } case Operator::SWITCH: { return instructions.compileSwitch(expr, DEFAULT("tmp_switch")); } case Operator::LOOP_CONTEXT: { assert(false); return nullptr; //return instructions.compileLoopContext(expr, DEFAULT("tmp_loop")); } case Operator::LOGIC_AND: { assert(expr.operands.size() == 1); return process(expr.operands[0]); } case Operator::LIST: { return instructions.compileListAsSolidArray(expr, DEFAULT("tmp_list")); }; case Operator::LIST_RANGE: { assert(false); //no compilation phase for a range list // return InstructionList(this).compileConstantArray(expr, l, hintRetVar); }; case Operator::LIST_NAMED: { typedef Expanded ExpandedType; ExpandedType tyStructLiteral = l.ast->getType(expr); const std::vector fieldsFormal = (tyStructLiteral.get().__operator == TypeOperator::CUSTOM) ? l.layerExtern->getStructFields(l.layerExtern->lookupType(tyStructLiteral.get().__valueCustom)) : tyStructLiteral.get().fields; std::map indexFields; for (size_t i = 0, size = fieldsFormal.size(); i < size; ++i) { indexFields.emplace(fieldsFormal[i], i); } llvm::StructType* tyLiteralRaw = llvm::cast(l.toLLVMType(tyStructLiteral)); llvm::Value* record = llvm::UndefValue::get(tyLiteralRaw); for (size_t i = 0; i < expr.operands.size(); ++i) { const Expression& operand = expr.operands.at(i); unsigned int fieldId = indexFields.at(expr.bindings.at(i)); llvm::Value* result = process(operand); assert(result); record = l.builder.CreateInsertValue(record, result, llvm::ArrayRef({fieldId})); } return record; }; case Operator::MAP: { assert(expr.blocks.size()); return instructions.compileMapSolidOutput(expr, DEFAULT("map")); }; case Operator::FOLD: { return instructions.compileFold(expr, DEFAULT("fold")); }; case Operator::FOLD_INF: { return instructions.compileFoldInf(expr, DEFAULT("fold")); }; case Operator::INDEX: { //TASK allow multiindex compilation assert(expr.operands.size() == 2); assert(expr.operands[0].__state == Expression::IDENT); const std::string& hintIdent = expr.operands[0].getValueString(); Symbol s = Attachments::get(expr.operands[0]); const ExpandedType& t2 = pass->man->root->getType(expr.operands[0]); llvm::Value* aggr = processSymbol(s, hintIdent); switch (t2.get().__operator) { case TypeOperator::LIST_NAMED: case TypeOperator::CUSTOM: { std::string idxField; const Expression& idx = expr.operands.at(1); switch (idx.__state) { //named struct field case Expression::STRING: idxField = idx.getValueString(); break; //anonymous struct field case Expression::NUMBER: idxField = to_string((int) idx.getValueDouble()); break; default: assert(false && "Wrong index for a struct"); } return instructions.compileStructIndex(aggr, t2, idxField); }; case TypeOperator::LIST: { std::vector indexes; std::transform(++expr.operands.begin(), expr.operands.end(), std::inserter(indexes, indexes.end()), [this] (const Expression & op) { return process(op); } ); return instructions.compileArrayIndex(aggr, indexes, DEFAULT(string("el_") + hintIdent)); }; default: assert(false); } }; //SECTIONTAG adhoc actual compilation //TODO a) make sure that it's correct: function->adhocImplementation built for Entry scope and used in another scope case Operator::ADHOC: { DefaultFunctionUnit* function = dynamic_cast (this->function); assert(function->adhocImplementation && "Adhoc implementation not found"); const Expression& comm = adhoc::AdhocExpression(expr).getCommand(); CodeScope* scope = function->adhocImplementation->getCommandImplementation(comm); ICodeScopeUnit* unitScope = function->getScopeUnit(scope); //SECTIONTAG types/convert ADHOC ret convertation llvm::Type* resultTy = l.toLLVMType(pass->man->root->expandType(function->adhocImplementation->getResultType())); return typeinference::doAutomaticTypeConversion(unitScope->compile(), resultTy, l.builder); }; case Operator::CALL_INTRINSIC: { const std::string op = expr.getValueString(); if (op == "copy") { llvm::Value* result = process(expr.getOperands().at(0)); auto decoratorVersions = Decorators::getInterface(this); llvm::Value* storage = decoratorVersions->processIntrinsicInit(result->getType()); decoratorVersions->processIntrinsicCopy(result, storage); return l.builder.CreateLoad(storage, hintVarDecl); } assert(false && "undefined intrinsic"); } case Operator::VARIANT: { const ExpandedType& typVariant = pass->man->root->getType(expr); llvm::Type* typVariantRaw = l.toLLVMType(typVariant); llvm::Type* typIdRaw = llvm::cast(typVariantRaw)->getElementType(0); uint64_t id = expr.getValueDouble(); llvm::Value* variantRaw = llvm::UndefValue::get(typVariantRaw); variantRaw = l.builder.CreateInsertValue(variantRaw, llvm::ConstantInt::get(typIdRaw, id), llvm::ArrayRef({0})); const bool flagDoReference = expr.operands.size(); if (flagDoReference){ const ExpandedType& subtyp = ExpandedType(typVariant->__operands.at(id)); llvm::Type* subtypRaw = l.toLLVMType(subtyp); Attachments::put(expr.operands.at(0), subtyp); llvm::Value* subtypValue = process(expr.operands.at(0)); llvm::Type* typStorageRaw = llvm::cast(typVariantRaw)->getElementType(1); llvm::Value* addrAsStorage = l.builder.CreateAlloca(typStorageRaw); llvm::Value* addrAsSubtyp = l.builder.CreateBitOrPointerCast(addrAsStorage, subtypRaw->getPointerTo()); l.builder.CreateStore(subtypValue, addrAsSubtyp); llvm::Value* storageRaw = l.builder.CreateLoad(typStorageRaw, addrAsStorage); variantRaw = l.builder.CreateInsertValue(variantRaw, storageRaw, llvm::ArrayRef({1})); } return variantRaw; } case Operator::SWITCH_VARIANT: { return instructions.compileSwitchVariant(expr, DEFAULT("tmpswitch")); } case Operator::SEQUENCE: { return instructions.compileSequence(expr); } case Operator::UNDEF: { llvm::Type* typExprUndef = l.toLLVMType(typeinference::getType(expr, *pass->man->root)); return llvm::UndefValue::get(typExprUndef); } case Operator::INVALID: assert(expr.__state != Expression::COMPOUND); switch (expr.__state) { case Expression::IDENT: { Symbol s = Attachments::get(expr); return processSymbol(s, expr.getValueString()); } case Expression::NUMBER: { llvm::Type* typConst = l.toLLVMType(typeinference::getType(expr, *pass->man->root)); int literal = expr.getValueDouble(); return llvm::ConstantInt::get(typConst, literal); } case Expression::STRING: { return instructions.compileConstantStringAsPChar(expr.getValueString(), DEFAULT("tmp_str")); }; default: { break; } }; break; default: break; } assert(false && "Can't compile expression"); return 0; } llvm::Value* BasicCodeScopeUnit::compile(const std::string& hintBlockDecl) { if (!hintBlockDecl.empty()) { llvm::BasicBlock *block = llvm::BasicBlock::Create(llvm::getGlobalContext(), hintBlockDecl, function->raw); pass->man->llvm->builder.SetInsertPoint(block); } currentBlockRaw = pass->man->llvm->builder.GetInsertBlock(); Symbol symbScope = Symbol{ScopedSymbol::RetSymbol, scope}; return processSymbol(symbScope); } ICodeScopeUnit::~ICodeScopeUnit() { } IFunctionUnit::~IFunctionUnit() { } llvm::Function* IFunctionUnit::compile() { if (raw != nullptr) return raw; LLVMLayer* llvm = pass->man->llvm; llvm::IRBuilder<>& builder = llvm->builder; string&& functionName = prepareName(); std::vector&& types = prepareArguments(); llvm::Type* expectedResultType = prepareResult(); llvm::FunctionType *ft = llvm::FunctionType::get(expectedResultType, types, false); raw = llvm::cast(llvm->module->getOrInsertFunction(functionName, ft)); prepareBindings(); const std::string&blockName = "entry"; llvm::BasicBlock* blockCurrent = builder.GetInsertBlock(); llvm::Value* result = getScopeUnit(function->__entry)->compile(blockName); assert(result); //SECTIONTAG types/convert function ret value builder.CreateRet(typeinference::doAutomaticTypeConversion(result, expectedResultType, llvm->builder)); if (blockCurrent) { builder.SetInsertPoint(blockCurrent); } llvm->moveToGarbage(ft); return raw; } ICodeScopeUnit* IFunctionUnit::getScopeUnit(const CodeScope * const scope) { if (__scopes.count(scope)) { auto result = __scopes.at(scope).lock(); if (result) { return result.get(); } } std::shared_ptr unit(pass->buildCodeScopeUnit(scope, this)); if (scope->__parent != nullptr) { auto parentUnit = Decorators::getInterface(getScopeUnit(scope->__parent)); parentUnit->registerChildScope(unit); } else { __orphanedScopes.push_back(unit); } if (!__scopes.emplace(scope, unit).second) { __scopes[scope] = unit; } return unit.get(); } ICodeScopeUnit* IFunctionUnit::getScopeUnit(ManagedScpPtr scope) { return getScopeUnit(&*scope); } ICodeScopeUnit* IFunctionUnit::getEntry() { return getScopeUnit(function->getEntryScope()); } template<> compilation::IFunctionUnit* CompilePassCustomDecorators::buildFunctionUnit(const ManagedFnPtr& function){ return new DefaultFunctionUnit(function, this); } template<> compilation::ICodeScopeUnit* CompilePassCustomDecorators::buildCodeScopeUnit(const CodeScope* const scope, IFunctionUnit* function){ return new DefaultCodeScopeUnit(scope, function, this); } } // emf of compilation IFunctionUnit* CompilePass::getFunctionUnit(const ManagedFnPtr& function) { unsigned int id = function.id(); if (!functions.count(id)) { IFunctionUnit* unit = buildFunctionUnit(function); functions.emplace(id, unit); return unit; } return functions.at(id); } void CompilePass::run() { managerTransformations = new TransformationsManager(); targetInterpretation = new interpretation::TargetInterpretation(this->man->root, this); queryContext = reinterpret_cast (man->clasp->getQuery(QueryId::ContextQuery)); //Find out main function; ClaspLayer::ModelFragment model = man->clasp->query(Config::get("function-entry")); assert(model && "Error: No entry function found"); assert(model->first != model->second && "Error: Ambiguous entry function"); string nameMain = std::get<0>(ClaspLayer::parse(model->first->second)); IFunctionUnit* unitMain = getFunctionUnit(man->root->findFunction(nameMain)); entry = unitMain->compile(); } llvm::Function* CompilePass::getEntryFunction() { assert(entry); return entry; } void CompilePass::prepareQueries(ClaspLayer* clasp) { clasp->registerQuery(new containers::Query(), QueryId::ContainersQuery); clasp->registerQuery(new context::ContextQuery(), QueryId::ContextQuery); Attachments::init(); clasp->registerQuery(new polymorph::PolymorphQuery(), QueryId::PolymorphQuery); } } //end of namespace xreate /** * \class xreate::CompilePass * \brief Encapsulates all compilation activities * * xreate::CompilePass iterates over xreate::AST tree and produces executable code fed by data(via xreate::Attachments) gathered by previous passes as well as data via queries(xreate::IQuery) from xreate:ClaspLayer reasoner. * Compilation's done using xreate::LLVMLayer(wrapper over LLVM toolchain) and based on following aspects: * - Containers support. See \ref compilation/containers.h * - Late Conext compilation. See xreate::context::LateContextCompiler2 * - Interpretation support. See xreate::interpretation::TargetInterpretation * - Loop saturation support. See xreate::compilation::TransformerSaturation * - External Code access. See xreate::ExternLayer(wrapper over Clang library) * * \section adaptability_sect Adaptability * xreate::CompilePass's architecture provides adaptability by employing: * - %Function Decorators to alter function-level compilation. See xreate::compilation::IFunctionUnit * - Code Block Decorators to alter code block level compilation. See xreate::compilation::ICodeScopeUnit * Default functionality defined by \ref xreate::compilation::DefaultCodeScopeUnit * - Targets to allow more versitile extensions. * Currently only xreate::interpretation::TargetInterpretation use Targets infrastructure. See xreate::compilation::Target * - %Altering Function invocation. xreate::compilation::ICallStatement * * Client able to construct compiler with desired decorators using xreate::compilation::CompilePassCustomDecorators. * As a handy alias, `CompilePassCustomDecorators` constructs default compiler * */ diff --git a/cpp/src/pass/dfapass.cpp b/cpp/src/pass/dfapass.cpp index 8958eb0..c1b34c0 100644 --- a/cpp/src/pass/dfapass.cpp +++ b/cpp/src/pass/dfapass.cpp @@ -1,242 +1,234 @@ /* 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 * * dfapass.cpp */ /** * \file dfapass.h * \brief Data Flow Analysis(DFA) */ //DEBT DFA represent VersionaPass in declarative form using applyDependencies // applyDependencies(expression, context, cache, decl); //DEBT DFA prepare static annotations and represent InterpretationPass in declarative form // applyStaticAnnotations(expression, context, cache, decl); //DEBT DFA Eliminate dfa schemes #include "pass/dfapass.h" #include "xreatemanager.h" #include "clasplayer.h" #include #include using namespace std; namespace xreate {namespace dfa { DFAPass::DFAPass(PassManager* manager) : AbstractPass(manager) , graph{new DFAGraph()} , clasp(manager->clasp) { } void DFAPass::processCallInstance(const Expression& expr, PassContext context, const SymbolNode& result) { const string &nameCalleeFunction=expr.getValueString(); //TODO implement processFnCall/Uncertain list variantsCalleeFunction=man->root->getFunctionSpecializations(nameCalleeFunction); vector operands; operands.reserve(expr.getOperands().size()); for(const Expression& arg : expr.getOperands()) { operands.push_back(process(arg, context)); } //Set calling relations: DFACallInstanceType type=variantsCalleeFunction.size()>1?WEAK:STRONG; for(ManagedFnPtr function : variantsCalleeFunction) { CodeScope *scopeRemote=function->getEntryScope(); DFACallInstance callInstance; callInstance.id=expr.id; callInstance.fnName=function->getName(); callInstance.type=type; std::vector::const_iterator nodeActual=operands.begin(); for(const std::string &identFormal : scopeRemote->__bindings) { const ScopedSymbol symbolFormal{scopeRemote->__identifiers.at(identFormal), versions::VERSION_NONE}; SymbolPacked symbolFormalPacked=clasp->pack(Symbol{symbolFormal, scopeRemote}, nameCalleeFunction+":"+identFormal); callInstance.args.push_back(std::make_pair(symbolFormalPacked, *nodeActual)); ++nodeActual; } callInstance.retActual=result; SymbolNode retFormal=SymbolNode(clasp->pack(Symbol{ScopedSymbol::RetSymbol, scopeRemote}, nameCalleeFunction+":[ret]")); graph->addCallInstance(std::move(callInstance)); } } void DFAPass::processDependencies(const SymbolNode& node, const Expression& expression, PassContext context, ProcessingCache& cache) { cache.operands.reserve(expression.getOperands().size()); for(const Expression &op : expression.getOperands()) { const SymbolNode& subnodeOperand=process(op, context); cache.operands.push_back(subnodeOperand); graph->addDependency(node, subnodeOperand); } cache.blocks.reserve(expression.blocks.size()); for(CodeScope* block : expression.blocks) { const SymbolNode& subnodeBlock=process(block, context); cache.blocks.push_back(subnodeBlock); graph->addDependency(node, subnodeBlock); } } SymbolNode DFAPass::process(const Expression& expression, PassContext context, const std::string& varDecl) { SymbolNode result; if(Attachments::exists(expression)){ Symbol varSymbol=Attachments::get(expression); result=clasp->pack(varSymbol, varDecl); } else if(expression.__state==Expression::IDENT&&expression.tags.size()==0){ Symbol varSymbol=Attachments::get(expression); result=clasp->pack(varSymbol, expression.getValueString()); } else { result=SymbolAnonymous{expression.id}; } graph->printInplaceAnnotations(result, expression); switch(expression.__state) { - case Expression::COMPOUND: - { + case Expression::COMPOUND: { switch(expression.op) { - case Operator::CALL: - { + case Operator::CALL: { processCallInstance(expression, context, result); break; } - case Operator::IF: - { + case Operator::IF: { const SymbolNode& scopeA=process(expression.blocks.front(), context, "ifTrue" + std::to_string(expression.id)); const SymbolNode& scopeB=process(expression.blocks.back(), context, "ifFalse" + std::to_string(expression.id)); const SymbolNode& condition=process(expression.operands.at(0), context); graph->addDependency(result, scopeA); graph->addDependency(result, scopeB); graph->addDependency(result, condition); graph->printWeakAlias(result, scopeA); graph->printWeakAlias(result, scopeB); break; } case Operator::SWITCH: - case Operator::SWITCH_VARIANT: - { + case Operator::SWITCH_VARIANT: { for(CodeScope* block : expression.blocks) { const SymbolNode& subnodeBlock=process(block, context, "case"+to_string(block->getBody().id)); graph->addDependency(result, subnodeBlock); graph->printWeakAlias(result, subnodeBlock); } const SymbolNode& condition=process(expression.operands.at(0), context); graph->addDependency(result, condition); break; } - default: - { + default: { ProcessingCache cache; processDependencies(result, expression, context, cache); break; } } break; } - case Expression::IDENT: - { + case Expression::IDENT: { SymbolNode symbIdent=AbstractPass::process(expression, context, varDecl); if(!(result==symbIdent)){ graph->addDependency(result, symbIdent); graph->printAlias(result, symbIdent); } break; } case Expression::NUMBER: - case Expression::STRING: - { + case Expression::STRING: { break; } case Expression::INVALID: - case Expression::BINDING: - { + case Expression::BINDING: { assert(false); break; } } return result; } SymbolNode DFAPass::process(CodeScope* scope, PassContext context, const std::string& hintBlockDecl) { if (!hintBlockDecl.empty()) { Symbol symbRet{ScopedSymbol::RetSymbol, scope}; clasp->pack(symbRet, hintBlockDecl + ":[ret]"); } for(const std::string& binding : scope->__bindings) { Symbol bindingSymbol{scope->getSymbol(binding), scope}; SymbolPacked bindingPacked=clasp->pack(bindingSymbol, binding); getSymbolCache().setCachedValue(bindingSymbol, SymbolNode(bindingPacked)); } return AbstractPass::process(scope, context, hintBlockDecl); } SymbolNode DFAPass::process(ManagedFnPtr function) { clasp->pack(Symbol{ScopedSymbol::RetSymbol, function->getEntryScope()}, function->getName()+to_string(function.id())+":[ret]"); SymbolNode result=AbstractPass::process(function); graph->printFunctionRet(function, result); return result; } void DFAPass::finish() { clasp->registerReport(graph); //Declare symbols: graph->printSymbols(clasp); AbstractPass::finish(); } } //end of namespace dfa template<> dfa::SymbolNode defaultValue() { assert(false); } -} //xreate namespace +} //end of xreate namespace /** * \class xreate::dfa::DFAPass * \details Provides DFA, important analysis for reasoning. Iterates over AST and stores collected data in DFAGraph */ diff --git a/cpp/src/pass/interpretationpass.cpp b/cpp/src/pass/interpretationpass.cpp index 89bf2fc..5e75aea 100644 --- a/cpp/src/pass/interpretationpass.cpp +++ b/cpp/src/pass/interpretationpass.cpp @@ -1,522 +1,525 @@ /* 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 clasp //DEBT represent InterpretationPass as general type inference using namespace std; namespace xreate { template<> interpretation::InterpretationResolution defaultValue() { return interpretation::CMPL_ONLY; } namespace interpretation { enum InterpretationQuery { QUERY_INTR_ONLY, QUERY_CMPL_ONLY }; 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 careless of signature + //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()}; + 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; } } - InterpretationResolution resolutionExpected= - Attachments::get(expression,{ANY, NONE}).resolution; + InterpretationData dataExpected= + Attachments::get(expression,{ANY, NONE}); - resolution=unify(resolution, resolutionExpected); - if(resolution!=resolutionExpected&&(op!=NONE||resolution==INTR_ONLY)){ + 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) */ \ No newline at end of file diff --git a/cpp/tests/CMakeLists.txt b/cpp/tests/CMakeLists.txt index b8605c3..fae4c99 100644 --- a/cpp/tests/CMakeLists.txt +++ b/cpp/tests/CMakeLists.txt @@ -1,55 +1,54 @@ cmake_minimum_required(VERSION 2.8.11) project(xreate-tests) find_package(GTest REQUIRED) INCLUDE_DIRECTORIES(${GTEST_INCLUDE_DIRS}) INCLUDE_DIRECTORIES("/usr/include/libxml2") INCLUDE_DIRECTORIES($) # TESTS #========================= FIND_PACKAGE (LLVM REQUIRED) message("LLVM_LIBRARY_DIRS: " ${LLVM_LIBRARY_DIRS}) link_directories(${LLVM_LIBRARY_DIRS}) set (LIBCLASP_PATH ${POTASSCO_PATH}/build/debug) link_directories(${LIBCLASP_PATH}) #aux_source_directory(. TEST_FILES) set(TEST_FILES + virtualization.cpp exploitation.cpp communication.cpp polymorph.cpp association.cpp main.cpp modules.cpp adhoc.cpp attachments.cpp ast.cpp cfa.cpp dfa.cpp compilation.cpp ExpressionSerializer.cpp externc.cpp - context.cpp types.cpp vendorAPI/clangAPI.cpp vendorAPI/xml2.cpp vendorAPI/json.cpp containers.cpp - context.cpp interpretation.cpp loops.cpp #supplemental/versions-algorithm-data_dependency.cpp effects-versions.cpp ) add_executable(${PROJECT_NAME} ${TEST_FILES}) target_link_libraries(${PROJECT_NAME} xreate ${GTEST_LIBRARIES} pthread xml2 gcov) add_custom_target (coverage COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/src/code-coverage.sh WORKING_DIRECTORY ${CMAKE_BINARY_DIR}) diff --git a/cpp/tests/adhoc.cpp b/cpp/tests/adhoc.cpp index 72a565f..8e9578b 100644 --- a/cpp/tests/adhoc.cpp +++ b/cpp/tests/adhoc.cpp @@ -1,196 +1,196 @@ /* Any copyright is dedicated to the Public Domain. * http://creativecommons.org/publicdomain/zero/1.0/ * * adhoc-exceptions.cpp * * Created on: Nov 19, 2015 * Author: pgess */ class Adhoc_pass_Adhoc1_Test; #define FRIENDS_ADHOC \ friend class ::Adhoc_pass_Adhoc1_Test; #include "ast.h" #include "xreatemanager.h" #include "gtest/gtest.h" #include #include #include #include #include "pass/adhocpass.h" #include "pass/compilepass.h" #include "llvmlayer.h" using namespace xreate; using namespace xreate::adhoc; using namespace std; TEST(Adhoc, ast_operatorAdhoc1){ XreateManager* man = XreateManager::prepare ( "test = function:: int {\n" " ad hoc exception(nonImplemented)\n" "}"); const Expression& subject = man->root->findFunction("test")->getEntryScope()->getBody(); ASSERT_EQ(Operator::ADHOC, subject.op); Expression exception = AdhocExpression(subject).getCommand(); ASSERT_EQ("exception", exception.getValueString()); } TEST(Adhoc, ast_schemeAdhoc1){ XreateManager* man = XreateManager::prepare ( "interface(adhoc){\n" " pre function expectNoErrors:: bool {\n" " case (Error) {false}\n" " case (Success) {true}\n" " }\n" " }"); assert(man->root->__interfacesData.count(ASTInterface::Adhoc)); Expression adhocData = man->root->__interfacesData.find(ASTInterface::Adhoc)->second; ASSERT_EQ(Operator::SWITCH, adhocData.operands[0].op); } TEST(Adhoc, pass_Adhoc1){ details::tier1::XreateManager* man = details::tier1::XreateManager::prepare ( "interface(adhoc){\n" " pre function expectNoErrors:: bool {\n" " case (Error) {false}\n" " case (Success) {true}\n" " }\n" "}\n" "main = function::int; entry {0} \n" ); man->analyse(); AdhocPass* pass = reinterpret_cast(man->getPassById(PassId::AdhocPass)); EXPECT_TRUE(pass->__schemes.size() > 0); AdhocScheme* scheme = pass->__schemes.begin()->second; EXPECT_EQ("expectNoErrors", scheme->getName()); } TEST(Adhoc, full_1){ XreateManager* man = XreateManager::prepare ( " import raw (\"core/control-context.lp\").\n" " interface(adhoc){\n" " pre function expectNoErrors:: bool {\n" " case (error) {false}\n" " case (success) {true}\n" " }\n" " }\n" " test1 = pre function {\n" " context:: expectNoErrors." " ad hoc success\n" " }" "main = function::bool;entry {\n" " test1()\n" " }"); bool (*main)() = (bool (*)()) man->run(); bool result = main(); ASSERT_EQ(true, result); } TEST(Adhoc, full_2){ XreateManager* man = XreateManager::prepare ( " import raw (\"core/control-context.lp\").\n" " interface(adhoc){\n" " pre function expectNoErrors:: bool {\n" " case (error) {false}\n" " case (success) {true}\n" " }\n" " pre function expectErrors:: bool {\n" " case (error) {true}\n" " case (success) {false}\n" " }\n" " }\n" " test1 = pre function {\n" " context:: expectNoErrors." " ad hoc success\n" " }\n" " test2 = pre function {\n" " context:: expectErrors." " ad hoc success\n" " }" "main = function::bool;entry {\n" " test1() != test2()\n" "}"); bool (*main)() = (bool (*)()) man->run(); bool result = main(); ASSERT_EQ(true, result); } //TODO adhoc type. FDecl sets wrong type in prefunc case(invalid type)) TEST(Adhoc, full_contextExpectNoErrrors){ XreateManager* man = XreateManager::prepare ( "import raw (\"core/control-context.lp\").\n" "interface(extern-c){\n" " xml2 = library:: pkgconfig(\"libxml-2.0\").\n" " \n" " include {\n" " xml2 = [\"stdlib.h\"]\n" " }.\n" "}" "interface(adhoc){\n" " pre function expectNoErrors:: bool {\n" " case (error) {false}\n" " case (success) {true}\n" " }\n" "}\n" "expectErrorCode = pre function(x::int){\n" - " if (x==0)::undef {ad hoc success}\n" + " if (x==0)::unknType {ad hoc success}\n" " else {ad hoc error}\n" "}\n" "main = function::bool; entry {\n" " context:: expectNoErrors." " expectErrorCode(system(\"ls -la\"))\n" "}" ); int (*main)() = (int (*)()) man->run(); ASSERT_EQ(1, main()); } //DEBT Implement compilation of switch adhoc TEST(Adhoc, ast_switchAdhoc1){ XreateManager* man = XreateManager::prepare ( "test1 = function:: bool {\n" " x = 0. \n" " switch ad hoc (x:: errors)\n" " case (error) {0}\n" " case (success) {1}\n" "\n" "}" ); const Expression& eSwitch = man->root->findFunction("test1")->getEntryScope()->getBody(); EXPECT_EQ(Operator::SWITCH_ADHOC, eSwitch.op); EXPECT_EQ(3, eSwitch.operands.size()); EXPECT_EQ(1, eSwitch.tags.size()); EXPECT_EQ("errors", eSwitch.tags.begin()->first); Expression eCondition = eSwitch.getOperands()[0]; EXPECT_EQ("x", eCondition.getValueString()); } diff --git a/cpp/tests/association.cpp b/cpp/tests/association.cpp index b243f67..4b9ed90 100644 --- a/cpp/tests/association.cpp +++ b/cpp/tests/association.cpp @@ -1,100 +1,129 @@ /* Any copyright is dedicated to the Public Domain. * http://creativecommons.org/publicdomain/zero/1.0/ * * association.cpp * * Author: pgess * Created on August 12, 2017, 9:28 PM */ #include "xreatemanager.h" #include "clasplayer.h" #include using namespace xreate; using namespace std; TEST(Association, test1){ std::string controller= R"Code( program(add). )Code"; std::string script= R"Code( Annotation = type variant { Num:: int, String:: string, Func:: {name::string, arguments::[Annotation]} }. extractCmd = function(program::Annotation):: Annotation; interpretation(force){ switch variant(program)::Annotation case (Num){String("wrong expression")} case (String){String("wrong expression")} case (Func){program["arguments"][0]} } main= function:: int; entry{ x= 5::int. y = 6::int. program = intrinsic query("program")[0]::Annotation. cmd = extractCmd(program)::Annotation; interpretation(force). answer = switch variant(cmd)::int case (Num) {0} case (String){0} case (Func){ switch(cmd["name"])::int case("add"){x + y} case default {0} }. answer } )Code"; std::unique_ptr man(XreateManager::prepare(std::move(script))); man->clasp->addRawScript(move(controller)); int (*main)() = (int (*)())man->run(); int result = main(); ASSERT_EQ(11, result); } +TEST(Association, QueryScope1){ +std::string script = R"Code( + Annotation = type variant { + Num:: int, + String:: string, + Func:: {name::string, arguments::[Annotation]} + }. + + func = function::int{10} //aux func in order to have few scopes + + main = function:: int; entry { + scope = intrinsic query_scope()::Annotation. + + answer = switch variant(scope):: int + case (Num) {scope} + case (String){-1} + case (Func){-1}. + + answer + } + +)Code"; + + std::unique_ptr man(XreateManager::prepare(std::move(script))); + int (*main)() = (int (*)())man->run(); + int result = main(); + + ASSERT_EQ(1, result); +} //std::string script= //R"Code( // //case context:: test1 { //test= function::bool; registerTest { // x = 8:: int. // // x == 8 //}} // //case context:: test2{ //test= function::bool{ // x = 3::int. // y = 12::int., // // (x+y) <> 25 //}} // //runTests= function::bool{ // tests = intrinsic query (registeredTests)::[Expression]. // // loop fold(tests->test::Expression, true->result):: bool { // shot = { // context:: make context (test) // test() // } // // result and shot // } //} // //main= function:: int; entry{ // runTests() //} //)Code"; diff --git a/cpp/tests/context.cpp b/cpp/tests/context.cpp deleted file mode 100644 index 3581303..0000000 --- a/cpp/tests/context.cpp +++ /dev/null @@ -1,497 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - * http://creativecommons.org/publicdomain/zero/1.0/ - * - * frame-context.cpp - * - * Created on: Dec 3, 2015 - * Author: pgess - */ - -#include "xreatemanager.h" -#include "query/context.h" - -#include "gtest/gtest.h" -#include -#include - -using namespace xreate; -using namespace xreate::context; - -TEST(Context, frame_Context1){ - details::tier1::XreateManager* man = details::tier1::XreateManager::prepare( - " import raw (\"core/control-context.lp\").\n" - " compute = function::int {\n" - " 0\n" - " }\n" - - " computeFast = function:: int {\n" - " context:: computation(fast).\n" - - " compute()\n" - " }\n" - - " computePrecisely = function:: int {\n" - " context:: computation(precise). \n" - - " compute()\n" - " }\n" - - "test = function(cmnd:: int):: int; entry {\n" - " context:: arithmetic(iee754). \n" - - " if (cmnd > 0)::int {computePrecisely()} else {computeFast()} \n" - "}\n" - ); - - ContextQuery* query = (ContextQuery*) man->clasp->registerQuery(new ContextQuery(), QueryId::ContextQuery); - man->analyse(); - - CodeScope* scopeTestC = man->root->findFunction("compute")->getEntryScope(); - const Domain& context = query->getContext(man->clasp->pack(scopeTestC)); - - int contextSize = context.size(); - EXPECT_EQ(1, contextSize); -} - -TEST(Context, contextAsRequirementSuccessful1){ - XreateManager* man = XreateManager::prepare( - " import raw (\"core/control-context.lp\").\n" - - " case context::safe {\n" - " funcSensitive = function::int {\n" - " 0\n" - " }}\n" - - " test = function:: int; entry {\n" - " context:: safe; test.\n" - - " funcSensitive()\n" - " }\n" - ); - - int (*main)() = (int (*)()) man->run(); - ASSERT_EQ(0, main()); -} - -TEST(Context, contextAsRequirementFailed){ - XreateManager* man = XreateManager::prepare( - " import raw (\"core/control-context.lp\").\n" - - " case context::safe {\n" - " funcSensitive = function::int {\n" - " 0\n" - " }}\n" - - " test = function:: int; entry {\n" - " context:: non_safe; test.\n" - - " funcSensitive()\n" - " }\n" - ); - - ASSERT_DEATH(man->run(), "findFunction"); -} - -TEST(Context, ContextPropagationNested){ - XreateManager* man = XreateManager::prepare( - " import raw (\"core/control-context.lp\").\n" - - " case context::safe {\n" - " square = function(x:: int) ::int {\n" - " x * x\n" - " }}\n" - - " test = function:: int; entry {\n" - " context:: safe; test.\n" - - " range = [1..10]:: [int]. \n" - " loop fold(range->x::int, 0->acc):: int { \n" - " acc + square(x) \n" - " } \n" - " }\n" - ); - - int (*main)() = (int (*)()) man->run(); - ASSERT_EQ(385, main()); -} - -TEST(Context, ContextPropagationNestedInterfunction){ - - XreateManager* man = XreateManager::prepare( - " import raw (\"core/control-context.lp\").\n" - " case context::toMillimeters {\n" - " convertConcrete = function(source:: num)::num {\n" - " 10 * source \n" - " }\n" - " }\n" - - " case context::toInches {\n" - " convertConcrete = function(source:: num)::num {\n" - " 2 * source \n" - " }\n" - " }\n" - - "convert= function(source:: num):: num { \n" - "convertConcrete(source) \n" - "} \n" - - "test = function(source:: num):: num; entry {\n" - " context:: toMillimeters.\n" - " convert(1)\n" - "}\n" ); - - int (*main)(int) = (int (*)(int)) man->run(); - ASSERT_EQ(10, main(1)); -} - -TEST(Context, full_ContextBasedFunctionSpecialization){ - - XreateManager* man = XreateManager::prepare( - " import raw (\"core/control-context.lp\").\n" - " case context::toMillimeters {\n" - " convert = function(source:: num)::num {\n" - " 10 * source \n" - " }\n" - " }\n" - - " case context::toInches {\n" - " convert = function(source:: num)::num {\n" - " 2 * source \n" - " }\n" - " }\n" - - "test = function(vrnt:: int)::int; entry {\n" - " switch(vrnt):: int\n" - " case (0) {\n" - " context:: toMillimeters.\n" - " convert(1)\n" - " }\n" - "\n" - " case (1) {\n" - " context:: toInches.\n" - " convert(1)\n" - " }\n" - " case default {0}\n" - " }" ); - - int (*main)(int) = (int (*)(int)) man->run(); - ASSERT_EQ(10, main(0)); - ASSERT_EQ(2, main(1)); -} - -TEST(Context, full_RuleContext){ - /* - "rule context:: childs(Child)\n" - " case artefact(Item)\n" - " {\n" - " artefact_depends(Item, Child)\n" - " }"; - */ - - XreateManager* man = XreateManager::prepare( - " import raw (\"core/control-context.lp\").\n" - " case context:: toMilli {\n" - " convert = function(length::int)::int{\n" - " 10 * length\n" - " }\n" - " }\n" - "\n" - " case context:: toCenti {\n" - " convert = function(length::int)::int{\n" - " length\n" - " }\n" - " }\n" - "\n" - " main=function::int; entry {\n" - " context:: output(milli).\n" - "\n" - " rule context::toMilli\n" - " case (output(milli)) {truth}\n" - "\n" - " convert(1)\n" - " }" ); - - man->clasp->addRawScript("truth."); - int (*entry)() = (int (*)()) man->run(); - ASSERT_EQ(10, entry()); -} - -TEST(Context, full_InheritedRuleContext){ - XreateManager* man = XreateManager::prepare( -" import raw (\"core/control-context.lp\"). \n" - -" case context:: toMilli {\n" -" convert = function(length::int)::int{\n" -" 10 * length\n" -" }\n" -" }\n" - -" case context:: toCenti {\n" -" convert = function(length::int)::int{\n" -" length\n" -" }\n" -" }\n" -"\n" - -"main = function(comm:: num)::num; entry{\n" -" rule context::X case (output(X)) {truth}\n" -"\n" -" switch (comm)::num \n" -" case (0) {\n" -" context:: output(toMilli).\n" -" convert(1)\n" -" }\n" -" case default {\n" -" context:: output(toCenti).\n" -" convert(1)\n" -" }\n" -" }"); - - man->clasp->addRawScript("truth."); - int (*entry)(int) = (int (*)(int)) man->run(); - ASSERT_EQ(10, entry(0)); - ASSERT_EQ(1, entry(1)); -} - - - -TEST(Context, full_LateContext){ - details::tier1::XreateManager* man = details::tier1::XreateManager::prepare( - "import raw (\"core/control-context.lp\").\n" - - " convert = function(length:: num)::num{\n" - " 0\n" - " }\n" - - "case context:: milli {\n" - " convert = function(length:: num)::num{\n" - " 1000 * length\n" - " }\n" - "}\n" - "\n" - "case context:: centi {\n" - " convert = function(length:: num)::num{\n" - " 100 * length\n" - " }\n" - "}\n" - "\n" - "calculate = function(length:: num)::num {\n" - " convert(length)\n" - "}\n" - "\n" - "main = function(com:: num):: num; entry {\n" - " switch (com):: num \n" - " case (0) {\n" - " context:: milli.\n" - " calculate(1)\n" - " }\n" - "\n" - " case default{\n" - " context:: centi. \n" - " calculate(1)\n" - " }\n" - "}"); - - man->analyse(); - ContextQuery* queryContext = reinterpret_cast(man->clasp->getQuery(QueryId::ContextQuery)); - const Expression& exprSwitch = man->root->findFunction("main")->__entry->getBody(); - const CodeScope* blockDefault = man->root->findFunction("main")->__entry->getBody().operands.at(1).blocks.front(); - ScopePacked blockDefaultId = man->clasp->pack(blockDefault); - const Domain& domDefault = queryContext->getContext(blockDefaultId); - ASSERT_EQ(1, domDefault.count(Expression(Atom("centi")))); - - std::list variants = man->root->getFunctionSpecializations("convert"); - for (ManagedFnPtr f: variants){ - const Expression guard = f->guardContext; - bool result = (guard.getValueString() == "centi" || guard.getValueString() == "milli" || !guard.isValid()); - ASSERT_TRUE(result); - } - - const FunctionDemand& demMain = queryContext->getFunctionDemand("main"); - ASSERT_EQ(0, demMain.size()); - - const FunctionDemand& demCalculate = queryContext->getFunctionDemand("calculate"); - ASSERT_EQ(1, demCalculate.size()); - - int (*entry)(int) = (int (*)(int)) man->run(); - ASSERT_EQ(1000, entry(0)); - ASSERT_EQ(100, entry(1)); -} - -TEST(Context, loopContextExists){ - XreateManager* man = XreateManager::prepare ( - "import raw (\"core/control-context.lp\").\n" - - "interface(cfa){\n" - " operator fold:: annotation1.\n" - "}\n" - "\n" - "main = function:: int; entry {\n" - " x = [1..10]:: [int].\n" - " sum = loop fold (x->el:: int, 0->sum):: int {\n" - " el + sum + f1()\n" - " }. \n" - " sum\n" - "}" - "case context:: annotation1 {" - " f1 = function::int {\n" - " x = 0:: int. " - " x\n" - " }" - "}" - ); - - man->run(); -} - -TEST(Context, pathDependentContext){ - std::string program = -R"CODE( -import raw("core/control-context.lp"). - -convert = function(length:: num) :: num { - 0 -} - -case context:: convert(milli, meters) { - convert = function(length:: num) :: num { - 1000 * length - } -} - -case context:: convert(centi, meters) { - convert = function(length:: num) :: num { - 100 * length - } -} - -case context:: convert(centi, kilo) { - convert = function(length:: num) :: num { - 100000 * length - } -} - -case context:: convert(milli, kilo) { - convert = function(length:: num) :: num { - 1000000 * length - } -} - -main = function(value::num, unitsInput::num, unitsOutput::num)::num; entry{ - switch (unitsInput)::num - case (0) { - test_fromMilli(value, unitsOutput) - } - case (1) { - test_fromCenti(value, unitsOutput) - } - - case default {0} -} - -test_fromCenti = function(value::num, output::num)::num{ - context:: input(centi). - - switch(output):: num - case (0) { - toMeters(value) - } - - case (1) { - toKilo(value) - } - - case default {0} -} - -test_fromMilli = function(value::num, output::num)::num{ - context:: input(milli). - - switch(output):: num - case (0) { - toMeters(value) - } - - case (1) { - toKilo(value) - } - - case default {0} -} - -toMeters = function(value::num)::num { - rule context:: convert(X, meters) case (input(X)) {truth} - - doConvert(value) -} - -toKilo = function(value::num)::num { - rule context:: convert(X, kilo) case (input(X)) {truth} - - doConvert(value) -} - -doConvert = function(value::num)::num{ - convert(value) -})CODE"; - - boost::scoped_ptr man(details::tier1::XreateManager::prepare(move(program))); - man->clasp->addRawScript("truth."); - man->analyse(); - - int (*test)(int, int, int) = (int (*)(int, int, int))man->run(); - - enum {INPUT_MILLI, INPUT_CENTI}; - enum {OUTPUT_METERS, OUTPUT_KILO}; - - ASSERT_EQ(1000000, test(1, INPUT_MILLI, OUTPUT_KILO)); - ASSERT_EQ(200, test(2, INPUT_CENTI, OUTPUT_METERS)); -} - -//TODO recover context loop and enable the test -TEST(Context, DISABLED_full_LoopContext){ - XreateManager* man = XreateManager::prepare( - " import raw (\"core/control-context.lp\")\n" - " case context:: a {\n" - " print = function:: string {\n" - " \"a\"\n" - " }}\n" - "\n" - " case context:: b {\n" - " print = function:: string {\n" - " \"b\"\n" - " }}\n" - "\n" - " case context:: c {\n" - " print = function:: string {\n" - " \"c\"\n" - " }}\n" - "\n" - " case context:: d {\n" - " print = function:: string {\n" - " \"d\"\n" - " }}\n" - "\n" - " start = function(command::int)::string; entry {\n" - " switch (command) :: string \n" - " case (0) {\n" - " context:: print(a); print(b); print(d).\n" - "\n" - " loop context (\"print\") {\n" - " print()\n" - " }\n" - " }\n" - "\n" - " case default {\n" - " context:: print(c).\n" - " loop context (\"print\") {\n" - " print()\n" - " }\n" - " }\n" - " }"); - - - char* (*main)(int) =(char* (*)(int)) man->run(); - ASSERT_STREQ("c", main(1)); - ASSERT_STREQ("a", main(0)); -} diff --git a/cpp/tests/interpretation.cpp b/cpp/tests/interpretation.cpp index a017579..336f58d 100644 --- a/cpp/tests/interpretation.cpp +++ b/cpp/tests/interpretation.cpp @@ -1,468 +1,531 @@ /* 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 "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/virtualization.cpp b/cpp/tests/virtualization.cpp index 2191504..eccbd29 100644 --- a/cpp/tests/virtualization.cpp +++ b/cpp/tests/virtualization.cpp @@ -1,27 +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/. = * virtualization.cpp * * Author: pgess * Created on February 24, 2018, 4:30 PM */ #include "xreatemanager.h" #include "gtest/gtest.h" - using namespace xreate; TEST(Virtualization, test1){ FILE* input = fopen("scripts/virtualization/test1.xreate","r"); assert(input != nullptr); std::unique_ptr man(XreateManager::prepare(input)); int (*main)() = (int (*)())man->run(); int result = main(); ASSERT_EQ(1, result); +} + +TEST(Virtualization, test2){ + FILE* input = fopen("scripts/virtualization/test2.xreate","r"); + assert(input != nullptr); + + std::unique_ptr man(XreateManager::prepare(input)); + + int (*main)() = (int (*)())man->run(); + int result = main(); + + ASSERT_EQ(3, result); } \ No newline at end of file diff --git a/grammar/xreate.ATG b/grammar/xreate.ATG index 86b8dc1..408c907 100644 --- a/grammar/xreate.ATG +++ b/grammar/xreate.ATG @@ -1,665 +1,663 @@ //TODO add ListLiteral //TODO ExprTyped: assign default(none) type #include "ast.h" #include "ExternLayer.h" #include "pass/adhocpass.h" #include #include #define wprintf(format, ...) \ char __buffer[100]; \ wcstombs(__buffer, format, 100); \ fprintf(stderr, __buffer, __VA_ARGS__) using namespace std; COMPILER Xreate details::inconsistent::AST* root = nullptr; // current program unit void ensureInitalizedAST(){ if (root == nullptr) root = new details::inconsistent::AST(); } struct { std::stack scopesOld; CodeScope* scope = nullptr; } context; void pushContextScope(CodeScope* scope){ context.scopesOld.push(context.scope); context.scope = scope; } void popContextScope(){ context.scope = context.scopesOld.top(); context.scopesOld.pop(); } int nextToken() { scanner->ResetPeek(); return scanner->Peek()->kind; } bool checkTokenAfterIdent(int key){ if (la->kind != _ident) return false; return nextToken() == key; } bool checkParametersList() { return la->kind == _ident && nextToken() == _lparen; } bool checkInfix() { return la->kind == _ident && nextToken() == _ident; } bool checkIndex() { return la->kind == _ident && nextToken() == _lbrack; } bool checkFuncDecl() { if (la->kind != _ident) return false; int token2 = nextToken(); int token3 = scanner->Peek()->kind; return token2 == _assign && (token3 == _function || token3 == _pre); } bool checkAssignment() { if (la->kind != _ident) return false; scanner->ResetPeek(); int token2 = scanner->Peek()->kind; if (token2 == _lcurbrack) { scanner->Peek(); int token3 = scanner->Peek()->kind; if (token3 != _rcurbrack) return false; int token4 = scanner->Peek()->kind; return token4 == _assign; } return token2 == _assign; } void recognizeIdentifier(Expression& i){ if (!context.scope->recognizeIdentifier(i)){ root->postponeIdentifier(context.scope, i); } } enum SwitchKind{SWITCH_NORMAL, SWITCH_META}; CHARACTERS letter = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz". any = ANY - '"'. digit = "0123456789". cr = '\r'. lf = '\n'. tab = '\t'. TOKENS ident = (letter | '_') {letter | digit | '_'}. number = (digit | '-' digit) {digit}. string = '"' { any } '"'. function = "function". pre = "pre". lparen = '('. rparen = ')'. lbrack = '['. rbrack = ']'. lcurbrack = '{'. rcurbrack = '}'. equal = "==". assign = '='. implic = '-' '>'. colon = ':'. context = "context". tagcolon = "::". lse = "<=". lss = "<". gte = ">=". gtr = ">". ne1 = "!=". ne2= "<>". COMMENTS FROM "/*" TO "*/" NESTED COMMENTS FROM "//" TO lf IGNORE cr + lf + tab PRODUCTIONS Xreate = (. Function* function; ensureInitalizedAST(); .) {( RuleDecl - | InterfaceData | Imprt | ContextSection | GuardSection + | InterfaceData | Imprt | GuardSection | IF(checkFuncDecl()) FDecl (. root->add(function); .) | TDecl | SkipModulesSection )} (. .) . Ident = ident (. name = t->val; .). VarIdent = ident (. e = Expression(Atom(t->val)); .) [ lcurbrack ( ident (. SemErr(coco_string_create("var version as ident is not implemented yet")); .) | number (. Attachments::put(e, Atom(t->val).get()); .) ) rcurbrack ] . FDecl = (. std::wstring fname; std::wstring argName; TypeAnnotation typIn; TypeAnnotation typOut; bool flagIsPrefunct = false; Expression binding; .) Ident assign [pre (. flagIsPrefunct = true; .)] function (. f = new Function(fname); f->isPrefunction = flagIsPrefunct; CodeScope* entry = f->getEntryScope(); .) ['(' Ident tagcolon ExprAnnotations (. f->addBinding(Atom(argName), move(binding)); .) {',' Ident tagcolon ExprAnnotations (. f->addBinding(Atom (argName), move(binding));.) } ')'] [ tagcolon ( IF(flagIsPrefunct) FnTag | Type ) {';' FnTag }] BDecl (. const_cast(entry->getBody()).bindType(move(typOut));.) . -ContextSection<>= (. Expression context; Function* f; .) - "case" "context" tagcolon MetaSimpExpr - lcurbrack { FDecl (. f->guardContext = context; root->add(f); .) - } rcurbrack. - GuardSection<>= (. Expression guard; Function* f; .) "guard" tagcolon MetaSimpExpr - lcurbrack { FDecl (. f->guard = guard; root->add(f); .) + lcurbrack { FDecl (. f->guard = guard; root->add(f); .) } rcurbrack. + /** * TYPES * */ TypeTerm = (. std::wstring tid; .) ("string" (. typ = TypePrimitive::String;.) | "num" (. typ = TypePrimitive::Num;.) | "int" (. typ = TypePrimitive::Int;.) | "float" (. typ = TypePrimitive::Float;.) | "bool" (. typ = TypePrimitive::Bool; .) | "i8" (. typ = TypePrimitive::I8; .) | "i32" (. typ = TypePrimitive::I32; .) | "i64" (. typ = TypePrimitive::I64; .) ). Type = (. TypeAnnotation typ2; TypePrimitive typ3; std::wstring tid, field; .) ( TList | TStruct | TVariant | TypeTerm (. typ = typ3; .) | IF (checkIndex()) Ident lbrack Ident (. typ = TypeAnnotation(TypeOperator::ACCESS, {}); typ.__valueCustom = Atom(tid).get(); typ.fields.push_back(Atom(field).get()); .) {',' Ident (. typ.fields.push_back(Atom(field).get()); .) } rbrack | Ident (. typ = TypeAnnotation(TypeOperator::CUSTOM, {}); typ.__valueCustom = Atom(tid).get(); .) ['(' Type (. typ.__operator = TypeOperator::CALL; typ.__operands.push_back(typ2); .) {',' Type (. typ.__operands.push_back(typ2); .) } ')'] ) . TList = (. TypeAnnotation ty; .) '[' Type ']' (. typ = TypeAnnotation(TypeOperator::LIST, {ty}); .) . TStruct = (. TypeAnnotation t; std::wstring key; size_t keyCounter=0; .) lcurbrack ( IF(checkTokenAfterIdent(_tagcolon)) Ident tagcolon Type | Type (. key = to_wstring(keyCounter++); .) ) (. typ = TypeAnnotation(TypeOperator::LIST_NAMED, {t}); typ.fields.push_back(Atom(key).get()); .) {',' ( IF(checkTokenAfterIdent(_tagcolon)) Ident tagcolon Type | Type (. key = to_wstring(keyCounter++); .) ) (. typ.__operands.push_back(t); typ.fields.push_back(Atom(key).get()); .) } rcurbrack. TVariant= (. TypeAnnotation t, typVoid(TypeOperator::LIST_NAMED, {}); std::vector operands; std::vector> keys; std::wstring variant; .) "variant" lcurbrack Ident (. t=typVoid; .) [tagcolon Type] (. keys.push_back(Atom(variant)); operands.push_back(t); .) {',' Ident (. t=typVoid; .) [tagcolon Type] (. keys.push_back(Atom(variant)); operands.push_back(t); .) } rcurbrack (. typ = TypeAnnotation(TypeOperator::VARIANT, {}); typ.__operands = operands; typ.addFields(std::move(keys)); .) . TDecl = (. TypeAnnotation t; std::wstring tname, arg; std::vector> args; .) Ident assign "type" ['(' Ident (. args.push_back(Atom(arg)); .) {',' Ident (. args.push_back(Atom(arg)); .) } ')'] Type'.' (. t.addBindings(move(args)); root->add(move(t), Atom(tname)); .) . ContextDecl = (. Expression tag; .) context tagcolon MetaSimpExpr (. scope->tags.push_back(tag); .) {';' MetaSimpExpr (. scope->tags.push_back(tag); .) }. VDecl = (. std::wstring vname; Expression var, value;.) VarIdent assign ExprTyped (. Symbol identSymbol = f->addDefinition(move(var), move(value)); Attachments::put(value, identSymbol); .) . BDecl = lcurbrack (. Expression body; pushContextScope(scope); .) {(IF(checkAssignment()) VDecl '.' | RuleContextDecl | ContextDecl'.' | ExprTyped (. scope->setBody(body); Attachments::put(body, Symbol{ScopedSymbol::RetSymbol, scope});.) )} rcurbrack (. popContextScope(); .) . IfDecl = (. Expression cond; ManagedScpPtr blockTrue = root->add(new CodeScope(context.scope)); ManagedScpPtr blockFalse = root->add(new CodeScope(context.scope)); .) "if" '(' Expr ')' (. e = Expression(Operator::IF, {cond}); .) tagcolon ExprAnnotations BDecl<&*blockTrue> "else" BDecl<&*blockFalse> (. e.addBlock(blockTrue); e.addBlock(blockFalse); .) . LoopDecl = (. Expression eIn, eAcc, eFilters; std::wstring varEl, varAcc, contextClass; Expression tagsEl; ManagedScpPtr block = root->add(new CodeScope(context.scope)); .) "loop" ("map" '(' Expr implic Ident (. e = Expression(Operator::MAP, {eIn}); .) tagcolon ExprAnnotations ')' tagcolon ExprAnnotations (. e.addBindings({Atom(varEl)}); block->addBinding(Atom(varEl), move(tagsEl)); .) BDecl<&*block> (. e.addBlock(block); .) |"fold" ("inf" '(' Expr implic Ident ')' (. e = Expression(Operator::FOLD_INF, {eAcc}); e.addBindings({Atom(varAcc)}); block->addBinding(Atom(varAcc), Expression()); .) tagcolon ExprAnnotations BDecl<&*block> (. e.addBlock(block); .) | '(' Expr implic Ident tagcolon ExprAnnotations ['|' Expr ] ',' Expr implic Ident')' (. e = Expression(Operator::FOLD, {eIn, eAcc}); e.addBindings({Atom(varEl), Atom(varAcc)}); .) tagcolon ExprAnnotations (. block->addBinding(Atom(varEl), move(tagsEl)); block->addBinding(Atom(varAcc), Expression()); .) BDecl<&*block> (. e.addBlock(block); .) ) | "context" '(' string (. contextClass = t->val; .) ')' BDecl<&*block> (. e = Expression(Operator::LOOP_CONTEXT, {Expression(Atom(std::move(contextClass)))}); e.addBlock(block); .) ). // Switches SwitchDecl = (. TypeAnnotation typ; eSwitch = Expression(Operator::SWITCH, {}); Expression eCondition; Expression tag;.) "switch" ( SwitchVariantDecl | lparen ExprTyped rparen tagcolon ExprAnnotations (. eSwitch.operands.push_back(eCondition);.) CaseDecl {CaseDecl} ) . CaseDecl = (. ManagedScpPtr scope = root->add(new CodeScope(context.scope)); Expression condition; .) "case" ( IF(flagSwitchKind == SWITCH_META) lparen MetaSimpExpr rparen BDecl<&*scope> (. Expression exprCase(Operator::CASE, {}); exprCase.addTags({condition}); exprCase.addBlock(scope); outer.addArg(move(exprCase));.) | "default" BDecl<&*scope> (. Expression exprCase(Operator::CASE_DEFAULT, {}); exprCase.addBlock(scope); outer.operands.insert(++outer.operands.begin(), exprCase); .) | lparen CaseParams<&*scope> rparen (. ManagedScpPtr scopeBody = root->add(new CodeScope(&*scope)); Expression exprCase(Operator::CASE, {}); .) BDecl<&*scopeBody> (. exprCase.addBlock(scope); exprCase.addBlock(scopeBody); outer.addArg(move(exprCase)); .) ). CaseParams = (. Expression condition; Expression guard(Operator::LOGIC_AND, {}); pushContextScope(scope); .) ExprTyped (. guard.addArg(Expression(condition)); .) {',' ExprTyped (. guard.addArg(Expression(condition)); .) } (. scope->setBody(guard); popContextScope(); .) . SwitchVariantDecl = (. Expression varTested; std::wstring varAlias; bool flagAliasFound = false; expr = Expression(Operator::SWITCH_VARIANT, {}); .) "variant" lparen Expr [implic Ident (. flagAliasFound = true; .) ] [tagcolon ExprAnnotations] rparen tagcolon ExprAnnotations (. expr.addArg(std::move(varTested)); if (flagAliasFound) { expr.addBindings({Atom(varAlias)}); } else { if(varTested.__state == Expression::IDENT){ expr.addBindings({Atom(string(varTested.getValueString()))}); } } .) CaseVariantDecl {CaseVariantDecl} . CaseVariantDecl = (. ManagedScpPtr scope = root->add(new CodeScope(context.scope)); std::wstring key; scope->addBinding(Atom(string(expr.bindings.front())), Expression()); .) "case" lparen Ident rparen (. expr.addArg(root->recognizeVariantConstructor(Atom(std::move(key)))); .) BDecl<&*scope> (. expr.addBlock(scope); .) . IntrinsicDecl= (. std::wstring name; .) "intrinsic" Ident< name> (. outer = Expression(Operator::CALL_INTRINSIC, {}); outer.setValue(Atom(name)); .) lparen [CalleeParams] rparen . SequenceDecl = (. sequence = Expression(); sequence.setOp(Operator::SEQUENCE); ManagedScpPtr scope = root->add(new CodeScope(context.scope)); .) "seq" BDecl<&*scope> (. sequence.blocks.push_back(&*scope); scope = root->add(new CodeScope(&*scope)); .) { (. scope = root->add(new CodeScope(&*scope)); .) BDecl<&*scope> (. sequence.blocks.push_back(&*scope); .) }. /*============================ INTERFACES ===============================*/ Imprt<> = "import" "raw" lparen string (. root->__rawImports.push_back(Atom(t->val).get()); .) rparen '.'. InterfaceData<> = "interface" '(' ( "dfa" ')' InterfaceDFA | "extern-c" ')' InterfaceExternC | "cfa" ')' InterfaceCFA | "adhoc" ')' InterfaceAdhoc ). InterfaceAdhoc<> = '{' { PrefunctionSchemeDecl } '}'. PrefunctionSchemeDecl<> = (. TypeAnnotation typReturn; std::wstring prefName; Expression exprCases; .) pre function Ident tagcolon Type lcurbrack SwitchDecl rcurbrack (. Expression prefData(Operator::CALL, {Atom(prefName), exprCases}); prefData.bindType(typReturn); root->addInterfaceData(Adhoc, move(prefData)); .). InterfaceExternC<> = (. ExternData data; .) '{' {IncludeExternDecl | LibExternDecl } '}' (. root->addExternData(move(data)); .) . LibExternDecl = (. std::wstring pkgname, libname; .) Ident assign "library" tagcolon "pkgconfig" '(' string (. pkgname = t->val; .) ')' '.' (. data.addLibrary(Atom(libname), Atom(pkgname)); .) . IncludeExternDecl = (. Expression inc; .) "include" StructLiteral '.' (. data.addIncludeDecl(move(inc)); .) . InterfaceDFA<> = '{' { InstructDecl } '}' . InstructDecl = (.Operator op; Expression tag; Expression scheme; std::vector& tags = scheme.operands; tags.push_back(Expression()); /* return value */ .) "operator" InstructAlias tagcolon '(' (.scheme.setOp(op); .) [ MetaSimpExpr (. tags.push_back(tag); .) { ',' MetaSimpExpr (. tags.push_back(tag); .) } ] ')' [ implic MetaSimpExpr (. tags[0] = tag; .) ] (. root->addDFAData(move(scheme)); .) '.'. InstructAlias = ( "map" (. op = Operator::MAP; .) | "list_range" (. op = Operator::LIST_RANGE; .) | "list" (. op = Operator::LIST; .) | "fold" (. op = Operator::FOLD; .) | "index" (. op = Operator::INDEX; .) ). InterfaceCFA<> = '{' { InstructCFADecl } '}' . InstructCFADecl<> = (.Operator op; Expression tag; Expression scheme; std::vector& tags = scheme.operands; .) "operator" InstructAlias tagcolon (. scheme.setOp(op); .) [ MetaSimpExpr (. tags.push_back(tag); .) { ',' MetaSimpExpr (. tags.push_back(tag); .) } ] '.' (. root->addInterfaceData(CFA, move(scheme)); .). /*============================ METAPROGRAMMING ===============================*/ // TagsDecl = (. Expression tag; TagModifier mod = TagModifier::NONE; .) // ':' { MetaSimpExpr (. /*f.addTag(std::move(tag), mod); */ .) // }. FnTag = (. Expression tag; TagModifier mod = TagModifier::NONE; .) MetaSimpExpr ['-' TagMod] (. f->addTag(std::move(tag), mod); .). TagMod = ( "assert" (. mod = TagModifier::ASSERT; .) | "require" (. mod = TagModifier::REQUIRE; .) ). RuleDecl<> = "rule" tagcolon (. RuleArguments args; RuleGuards guards; DomainAnnotation typ; std::wstring arg; .) '(' Ident tagcolon Domain (. args.add(arg, typ); .) {',' Ident tagcolon Domain (. args.add(arg, typ); .) } ')' ["case" RGuard {',' RGuard}] '{' RBody '}' . /* - TODO use RGuard for guards-*/ RuleContextDecl = (.Expression eHead, eGuards, eBody; .) "rule" "context" tagcolon MetaSimpExpr "case" lparen MetaSimpExpr rparen '{' MetaSimpExpr '}' (.scope->contextRules.push_back(Expression(Operator::CONTEXT_RULE, {eHead, eGuards, eBody})); .). Domain = ( "function" (. dom = DomainAnnotation::FUNCTION; .) | "variable" (. dom = DomainAnnotation::VARIABLE; .) ). RGuard= (. Expression e; .) MetaExpr (. guards.add(std::move(e)); .). MetaExpr= (.Operator op; Expression e2; .) MetaExpr2 [MetaOp MetaExpr2 (. e = Expression(op, {e, e2}); .) ]. MetaExpr2= ( '(' MetaExpr ')' | MetaSimpExpr ). MetaSimpExpr= (. std::wstring i1, infix; Expression e2; .) ( '-' MetaSimpExpr (. e = Expression(Operator::NEG, {e2}); .) | IF(checkParametersList()) Ident (. e = Expression(Operator::CALL, {Expression(Atom(i1))}); .) '(' [ MetaCalleeParams ] ')' | IF(checkInfix()) Ident Ident MetaSimpExpr (. e = Expression(Operator::CALL, {Expression(Atom(infix))}); e.addArg(Expression(Atom(i1))); e.addArg(std::move(e2)); .) | Ident (. e = Expression(Operator::CALL, {Atom(i1)}); .) ). MetaCalleeParams = (. Expression e2; .) MetaSimpExpr (. e.addArg(Expression(e2)); .) {',' MetaSimpExpr (. e.addArg(Expression(e2)); .) }. RBody = (. Expression e; std::wstring msg; .) "warning" MetaExpr ["message" string (. msg = t->val; .) ] (. root->add(new RuleWarning(RuleArguments(args), RuleGuards(guards), std::move(e), Atom(msg))); .) . MetaOp< Operator& op> = implic (. op = Operator::IMPL; .) . /*============================ Expressions ===============================*/ ExprAnnotations = (. TypeAnnotation typ; std::list tags; Expression tag; e.tags.clear();.) Type (. e.bindType(move(typ)); .) {';' MetaSimpExpr (. tags.push_back(tag); .) } (. e.addTags(tags); .) . ExprTyped = Expr [tagcolon ExprAnnotations]. Expr< Expression& e> (. Operator op; Expression e2; .) = ExprArithmAdd [ RelOp ExprArithmAdd (. e = Expression(op, {e, e2}); .) ]. ExprArithmAdd< Expression& e>= (. Operator op; Expression e2; .) ExprArithmMul< e> [ AddOp< op> ExprArithmAdd< e2> (. e = Expression(op, {e, e2});.) ]. ExprArithmMul< Expression& e> (. Operator op; Expression e2; .) = ExprPostfix< e> [ MulOp< op> ExprArithmMul< e2> (. e = Expression(op, {e, e2}); .) ]. ExprPostfix = Term [ (. e = Expression(Operator::INDEX, {e}); .) {lbrack CalleeParams rbrack } ]. Term< Expression& e> (. std::wstring name; e = Expression(); .) = (IF (checkParametersList()) Ident< name> (. e = Expression(Operator::CALL, {Atom(name)}); root->recognizeVariantConstructor(e); .) '(' [CalleeParams] ')' | VarIdent (. recognizeIdentifier(e); .) | ListLiteral (. /* tuple */.) | StructLiteral (. /* struct */.) | LoopDecl | IfDecl | SwitchDecl | AdhocDecl | IntrinsicDecl | SequenceDecl | number (. e = Expression(Atom(t->val)); .) | string (. e = Expression(Atom(t->val)); .) | "true" (. e = Expression(Atom(1)); e.bindType(TypePrimitive::Bool); .) | "false" (. e = Expression(Atom(0)); e.bindType(TypePrimitive::Bool); .) | "undef" (. e = Expression(Operator::UNDEF, {}); .) | '-' Term (. e = Expression(Operator::NEG, {e}); .) | '(' ExprTyped ')' ). StructLiteral = (. std::wstring key; Expression val; std::list> keys; size_t keyCounter=0; .) lcurbrack (IF(checkTokenAfterIdent(_assign)) Ident '=' Expr | Expr (. key = to_wstring(keyCounter++); .) ) (. keys.push_back(Atom(key)); e = Expression(Operator::LIST_NAMED, {val}); .) {',' (IF(checkTokenAfterIdent(_assign)) Ident '=' Expr | Expr (. key = to_wstring(keyCounter++); .) ) (. e.addArg(Expression(val)); keys.push_back(Atom(key)); .) } rcurbrack (. e.addBindings(keys.begin(), keys.end()); .) . ListLiteral = (. Expression eFrom, eTo; .) -'[' -[ Expr (. e.addArg(Expression(eFrom)); .) -(".." Expr (. e.addArg(Expression(eTo)); e.setOp(Operator::LIST_RANGE); .) - |{',' Expr (. e.addArg(Expression(eFrom)); .) -} (. e.setOp(Operator::LIST); .) -) ] ']'. +'[' (. e.setOp(Operator::LIST); .) + [ Expr (. e.addArg(Expression(eFrom)); .) + ( ".." Expr (. e.addArg(Expression(eTo)); e.setOp(Operator::LIST_RANGE); .) + |{',' Expr (. e.addArg(Expression(eFrom)); .) + } + ) + ] +']'. AdhocDecl = (. Expression command; .) "ad" "hoc" MetaSimpExpr (. adhoc::AdhocExpression exprAdhoc; exprAdhoc.setCommand(command); e = exprAdhoc; .). CalleeParams = (. Expression e2; .) ExprTyped (. e.addArg(Expression(e2)); .) {',' ExprTyped (. e.addArg(Expression(e2)); .) }. AddOp< Operator& op> = (. op = Operator::ADD; .) ( '+' | '-' (. op = Operator::SUB; .) ). MulOp< Operator& op> = (. op = Operator::MUL; .) ( '*' | '/' (. op = Operator::DIV; .) ). RelOp< Operator& op> = (. op = Operator::EQU; .) ( equal | (ne1 | ne2) (. op = Operator::NE; .) | lse (. op = Operator::LSE; .) | lss (. op = Operator::LSS; .) | gte (. op = Operator::GTE; .) | gtr (. op = Operator::GTR; .) ). SkipModulesSection = "module" '{' {ANY} '}'. END Xreate. diff --git a/core/control-context-v1.lp b/scripts/cfa/control-context-v1.lp similarity index 100% rename from core/control-context-v1.lp rename to scripts/cfa/control-context-v1.lp diff --git a/core/control-context-v3.lp b/scripts/cfa/control-context-v3.lp similarity index 86% rename from core/control-context-v3.lp rename to scripts/cfa/control-context-v3.lp index ab4cfe3..03fe0d5 100644 --- a/core/control-context-v3.lp +++ b/scripts/cfa/control-context-v3.lp @@ -1,64 +1,70 @@ % 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). +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 new file mode 120000 index 0000000..e2a1c99 --- /dev/null +++ b/scripts/cfa/control-context.lp @@ -0,0 +1 @@ +/private/prg/code/xreate/scripts/cfa/control-context-v3.lp \ No newline at end of file diff --git a/core/containers.lp b/scripts/containers/containers.lp similarity index 100% rename from core/containers.lp rename to scripts/containers/containers.lp diff --git a/scripts/virtualization/context-v1.lp b/scripts/virtualization/context-v1.lp new file mode 100644 index 0000000..f0a7feb --- /dev/null +++ b/scripts/virtualization/context-v1.lp @@ -0,0 +1,47 @@ +%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/virtualization/test1.assembly.lp b/scripts/virtualization/test1.assembly.lp new file mode 100644 index 0000000..3762dae --- /dev/null +++ b/scripts/virtualization/test1.assembly.lp @@ -0,0 +1,2 @@ +virtDomain(domainA). +virtDomain(domainB). diff --git a/scripts/virtualization/test1.xreate b/scripts/virtualization/test1.xreate new file mode 100644 index 0000000..35c05b1 --- /dev/null +++ b/scripts/virtualization/test1.xreate @@ -0,0 +1,72 @@ +interface(extern-c){ + externalLibs = library:: pkgconfig("libxml-2.0"). + + include { + externalLibs = ["stdio.h"] + }. +} + +import raw ("scripts/virtualization/test1.assembly.lp"). +import raw ("scripts/virtualization/virtualization.lp"). + +Annotation = type variant { + Num:: int, + String:: string, + Func:: {name::string, arguments::[Annotation]} +}. + +DictEntry = type {Annotation, Id}. + +extractDictEntry = function(entry:: Annotation):: DictEntry; interpretation(force){ + resultWrong = { String("wrong"), 0 }:: DictEntry. + + switch variant (entry):: DictEntry + case (Num) { resultWrong } + case (String) { resultWrong } + case (Func){ + domAnn = entry["arguments"][0]:: Annotation. + + switch variant ( entry["arguments"][1]->id ):: Annotation + case (Num) { {domAnn, id} } + case (String) { resultWrong } + case (Func) { resultWrong } + } +} + +encodeDomain = function(key::Annotation):: int; interpretation(force){ + dict = intrinsic query("virtDictDomains")::[Annotation]. + + id = loop fold(dict->entryAnn::Annotation, 0->id):: int { + entry = extractDictEntry(entryAnn):: DictEntry. + + if(entry[0] == key):: int { entry[1] } else { id } + }. + + id + + /* + buf = "000000000"::string. + seq + { sprintf(buf, "%d", id).} + { buf} + */ +} + + +main = function:: int; entry { + encodeDomain(Func({"domainB", []})) +} + +/* +openfile = function(fileName::string, prefixPackedAnn:: Annotation) { + prefixStr = encodeDomain(prefixPackedAnn):: string. + + fopen(prefixStr + fileName) +} + +main = function:: entry ( + seq + { context::virtualization(domainA). openFile("test1", intrinsic query("openFileAdditionalArgsDomA")[0]) } + { context::virtualization(domainB). openFile("test1", intrinsic query("openFileAdditionalArgsDomB")[0]) } +) +*/ diff --git a/scripts/virtualization/test2.assembly.lp b/scripts/virtualization/test2.assembly.lp new file mode 100644 index 0000000..a3845ac --- /dev/null +++ b/scripts/virtualization/test2.assembly.lp @@ -0,0 +1,12 @@ + +dfa_callguard(Instance, Guard):- %static local decision + bind_scope(Scope, callguard(Guard), strong); + bind(InstSymbRet, dfa_polym(cntxt)); + dfa_callinstance(Instance, FnCallee); + dfa_callret(Instance, InstSymbRet); + 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/virtualization/test2.xreate b/scripts/virtualization/test2.xreate new file mode 100644 index 0000000..12942f9 --- /dev/null +++ b/scripts/virtualization/test2.xreate @@ -0,0 +1,101 @@ +import raw ("scripts/virtualization/context-v1.lp"). +import raw ("scripts/virtualization/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/virtualization/virtualization.lp b/scripts/virtualization/virtualization.lp new file mode 100644 index 0000000..9aa3f5a --- /dev/null +++ b/scripts/virtualization/virtualization.lp @@ -0,0 +1,6 @@ +% INPUT: +% virtDomain() - different virtualization domains + +virtDictDomains(Dom, Id):- Id = #sum{1, DomLess : virtDomain(DomLess), DomLess < Dom}; + virtDomain(Dom). +