diff --git a/config/default.json b/config/default.json index d52c52a..5ee2fb5 100644 --- a/config/default.json +++ b/config/default.json @@ -1,74 +1,74 @@ { "containers": { "id": { "implementations": "containers_impl", "linkedlist": "linkedlist" }, "impl": { "solid": "solid", "onthefly": "onthefly" } }, "logging": { "id": "logging" }, "function-entry": "entry", "transcend": { "bindings" : { "variable": "bind", "function": "bind_func", "scope": "bind_scope", "function_demand" : "bind_function_demand", "scope_decision": "bind_scope_decision" }, "context" : { "decisions":{ "dependent": "resolution_dependency" } }, "nonevalue": "nonevalue", "ret": { "symbol": "retv", "tag": "ret" } }, "tests": { "template": "default", "templates": { "troubleshooting":"*", "documentation":"Modules.Doc_*:Modules_API.Doc_*:Interpretation.Doc_*:AST.Doc_*:Loop.Doc_*:LateReasoning.Doc_*:Latex.Doc_*:Polymorphs.Doc_*:Transcend.Doc_*:ASTCorrespondence.Doc_*:Virtualization.Doc_*:Exploitation.Doc_*:Communication.Doc_*:Introduction.*", - "default": "*", + "default": "*-Effects.compilation_versions_1:Effects.compilation_versions_versionNext1", "ast": "AST.*", "effects": "Effects.*", "basic": "Attachments.*", "compilation": "Compilation.*", "communication": "Communication.*", "cfa": "CFA.*", "containers": "Containers.*", "dfa": "DFA.*", "diagnostic": "Diagnostic.*", "dsl": "Association.*:Interpretation.*", "exploitation": "Exploitation.*", "ExpressionSerializer": "ExpressionSerializer.*", "externc": "InterfaceExternC.*", "loops": "Loop.*", "latereasoning": "LateReasoning.*", "latex": "Latex.*", "modules": "Modules.*", "polymorphs": "Polymorphs.*", "intrinsic-query": "Types.SlaveTypes*:Association.TypedQuery*", "types": "Types.*", "virtualization": "Virtualization.*", "vendorsAPI/clang": "ClangAPI.*", "vendorsAPI/xml2": "libxml2.*" } } } diff --git a/cpp/src/CMakeLists.txt b/cpp/src/CMakeLists.txt index 44d1d1c..9dad86e 100644 --- a/cpp/src/CMakeLists.txt +++ b/cpp/src/CMakeLists.txt @@ -1,238 +1,223 @@ cmake_minimum_required(VERSION 2.8.11) project(xreate) cmake_policy(SET CMP0022 NEW) message("MODULES" ${CMAKE_MODULE_PATH}) # LLVM #====================== FIND_PACKAGE (LLVM REQUIRED) set(LLVM_VERSION ${LLVM_VERSION_MAJOR}.${LLVM_VERSION_MINOR}) message(STATUS "Found LLVM ${LLVM_PACKAGE_VERSION}") message("LLVM LIB PATH:" ${LLVM_LIBRARY_DIRS}) message(STATUS "Using LLVMConfig.cmake in: ${LLVM_DIR}") INCLUDE_DIRECTORIES(${LLVM_INCLUDE_DIRS}) message(STATUS "INCLUDE DIR: ${LLVM_INCLUDE_DIRS}") add_definitions(${LLVM_DEFINITIONS}) message(STATUS "LLVM DEFS: " ${LLVM_DEFINITIONS}) execute_process( COMMAND llvm-config --libs OUTPUT_VARIABLE LLVM_LIBS OUTPUT_STRIP_TRAILING_WHITESPACE) message(STATUS "LLVM LIBS: " ${LLVM_LIBS}) # CLANG #====================== set(CLANG_LIBS - clangCodeGen - clangASTMatchers - clangQuery - clangTooling - clangFrontend - clangSerialization - clangDriver - clangParse - clangSema - clangAnalysis - clangAST - clangEdit - clangLex - clangBasic + clang ) # POTASSCO #====================== set(CLINGO_PATH "/opt/potassco/clingo" CACHE PATH "Path to potassco sources") set(POTASSCO_INCLUDE_PATH - ${CLINGO_PATH}/libgringo - ${CLINGO_PATH}/libclasp - ${CLINGO_PATH}/libclingo - ${CLINGO_PATH}/libprogram_opts - ${CLINGO_PATH}/liblp + ${CLINGO_PATH}/libgringo + ${CLINGO_PATH}/libclingo + ${CLINGO_PATH}/build/clasp + ${CLINGO_PATH}/clasp + ${CLINGO_PATH}/clasp/libpotassco ) INCLUDE_DIRECTORIES(${POTASSCO_INCLUDE_PATH}) set(LIBCLASP_LIBS clingo clasp + potassco 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 analysis/temporalseqgraph.cpp pass/cfatemporalseqpass.cpp analysis/cfagraph.cpp pass/cfapass.cpp modules.cpp compilation/interpretation-instructions.cpp ExternLayer.cpp analysis/cfagraph.cpp compilation/latetranscend.cpp analysis/interpretation.cpp query/latex.cpp query/polymorph.cpp compilation/polymorph.cpp aux/latereasoning.cpp compilation/latex.cpp analysis/typeinference.cpp xreatemanager.cpp transcendlayer.cpp analysis/dfagraph.cpp llvmlayer.cpp pass/compilepass.cpp analysis/utils.cpp pass/dfapass.cpp compilation/targetinterpretation.cpp pass/interpretationpass.cpp ast.cpp aux/xreatemanager-decorators.cpp compilation/operators.cpp compilation/transformations.cpp compilation/transformersaturation.cpp pass/versionspass.cpp attachments.cpp compilation/containers.cpp compilation/advancedinstructions.cpp utils.cpp pass/abstractpass.cpp contextrule.cpp query/containers.cpp aux/serialization/expressionserializer.cpp ) set(XREATE_INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/ ) INCLUDE_DIRECTORIES(${XREATE_INCLUDE_DIRS}) set(XREATE_PRIVATE_INCLUDE_DIRS ${XREATE_INCLUDE_DIRS} ${COCO_GRAMMAR_PATH} ${JEAYESON_INCLUDE_PATH} ${LLVM_INCLUDE_DIRS} ${POTASSCO_INCLUDE_PATH} ) add_library(${PROJECT_NAME} SHARED ${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/ExternLayer.cpp b/cpp/src/ExternLayer.cpp index 03afa74..592462c 100644 --- a/cpp/src/ExternLayer.cpp +++ b/cpp/src/ExternLayer.cpp @@ -1,334 +1,334 @@ /* 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/. * * ExternLayer.cpp * * Created on: 4/21/15 * Author: pgess */ #include "ExternLayer.h" #include "clang/Tooling/Tooling.h" #include "clang/Frontend/ASTUnit.h" -#include "clang/Frontend/CodeGenOptions.h" +#include "clang/Basic/CodeGenOptions.h" #include "clang/ASTMatchers/ASTMatchers.h" #include "clang/ASTMatchers/ASTMatchFinder.h" #include "clang/Basic/TargetInfo.h" #include "clang/CodeGen/ModuleBuilder.h" #include "clang/CodeGen/CodeGenABITypes.h" #include #include #include #include #include #include using namespace std; using namespace clang; using namespace clang::driver; using namespace clang::tooling; using namespace clang::ast_matchers; using namespace llvm; namespace xreate{ class FinderCallbackTypeDecl : public MatchFinder::MatchCallback{ public: QualType typeResult; virtual void run(const MatchFinder::MatchResult &Result) { if (const TypedefDecl * decl = Result.Nodes.getNodeAs("typename")) { typeResult = decl->getUnderlyingType(); } } } ; class FinderCallbackFunction : public MatchFinder::MatchCallback{ public: QualType typeResult; virtual void run(const MatchFinder::MatchResult &Result) { if (const FunctionDecl * decl = Result.Nodes.getNodeAs("function")) { typeResult = decl->getType(); } } } ; void ExternData::addLibrary(Atom&& name, Atom&& package) { __dictLibraries.emplace(name.get(), package.get()); } void ExternData::addIncludeDecl(Expression&& e) { assert(e.op == Operator::LIST); //TODO ?? implement Expression parsing(Array of Expr as vector); for(size_t i = 0, size = e.operands.size(); i < size; ++i) { std::string library = e.bindings.at(i); assert(__dictLibraries.count(library)); std::string package = __dictLibraries.at(library); Expression listHeaders = e.operands.at(i); assert(listHeaders.op == Operator::LIST); std::vector headers; std::transform(listHeaders.operands.begin(), listHeaders.operands.end(), std::inserter(headers, headers.end()), [](const Expression & o) { assert(o.__state == Expression::STRING); return o.getValueString(); }); entries.emplace_back(ExternEntry{package, std::move(headers)}); } } void ExternLayer::addExternalData(const std::vector& data) { entries.insert(entries.end(), data.begin(), data.end()); } ExternLayer::ExternLayer(LLVMLayer *llvm) : __llvm(llvm) { } std::vector ExternLayer::fetchPackageFlags(const ExternEntry& entry) { std::vector args; FILE* flags = popen((string("pkg-config --cflags ") + entry.package).c_str(), "r"); size_t linesize = 0; char* linebuf = 0; ssize_t linelen = 0; while ((linelen = getdelim(&linebuf, &linesize, ' ', flags)) > 0) { if (linebuf[0] == '\n') continue; if (linelen == 1 && linebuf[0] == ' ') continue; //cut unwanted symbols at the end char symbLast = linebuf[linelen - 1 ]; if (symbLast == ' ' || symbLast == '\n') linebuf[linelen - 1] = 0; //print header for debug purposes llvm::outs() << '<' << linebuf << "> "; args.push_back(linebuf); free(linebuf); linebuf = 0; } pclose(flags); return (args); } std::vector ExternLayer::fetchPackageLibs(const ExternEntry& entry) { std::vector libs; FILE* flags = popen((string("pkg-config --libs ") + entry.package).c_str(), "r"); size_t linesize = 0; char* linebuf = 0; ssize_t linelen = 0; while ((linelen = getdelim(&linebuf, &linesize, ' ', flags)) > 0) { if (linebuf[0] == '\n') continue; if (linelen == 1 && linebuf[0] == ' ') continue; //cut unwanted symbols at the end char symbLast = linebuf[linelen - 1 ]; if (symbLast == ' ' || symbLast == '\n') linebuf[linelen - 1] = 0; //cut unwanted symbols at the beginning if (linelen > 1 && linebuf[0] == '-' && linebuf[1] == 'l') { libs.push_back(linebuf + 2); } else { libs.push_back(linebuf); } //print lib name for debug purposes llvm::outs() << '<' << linebuf << "> "; free(linebuf); linebuf = 0; } pclose(flags); return (libs); } void ExternLayer::loadLibraries(vector&& libs) { string msgErr; for (const string& lib : libs) { const string& libName = string("lib") + lib + ".so"; if (!llvm::sys::DynamicLibrary::LoadLibraryPermanently(libName.c_str(), &msgErr)) { llvm::errs() << "\n" << "Loading library " << lib << ". " << msgErr << "\n"; } } } void ExternLayer::init(const AST* root) { addExternalData(root->__externdata); // TODO -EXTERN01.DIP, use default include path from 'clang -xc++ -E' list code; std::vector args{ "-I/usr/include" , "-I/usr/local/include" , "-I/usr/lib64/clang/5.0.1/include" // ,"-I/usr/lib/gcc/x86_64-linux-gnu/4.9/include" // ,"-I/usr/include/x86_64-linux-gnu" }; std::vector libs; boost::format formatInclude("#include \"%1%\""); for(const ExternEntry& entry : entries) { llvm::outs() << "[ExternC] Processing package: " << entry.package << "\n"; llvm::outs() << "[ExternC] args: "; vector&& args2 = fetchPackageFlags(entry); args.insert(args.end(), args2.begin(), args2.end()); for(const string arg : args2) { llvm::outs() << "<" << arg << "> "; } llvm::outs() << "\n[ExternC] libs: "; args2 = fetchPackageLibs(entry); for(const string arg : args2) { llvm::outs() << "<" << arg << "> "; } libs.insert(libs.end(), args2.begin(), args2.end()); llvm::outs() << "\n[ExternC] headers: "; std::transform(entry.headers.begin(), entry.headers.end(), std::inserter(code, code.begin()), [&formatInclude](const string header ) { string line = boost::str(formatInclude % header); llvm::outs() << "<" << line << "> "; return line; }); llvm::outs() << '\n'; } loadLibraries(move(libs)); ast = buildASTFromCodeWithArgs(boost::algorithm::join(code, "\n"), args); __llvm->module->setDataLayout(ast->getASTContext().getTargetInfo().getDataLayout()); __clang.reset(new CompilerInstance()); __clang->createDiagnostics(); __codegen.reset(CreateLLVMCodeGen( __clang->getDiagnostics(), __llvm->module->getName(), __clang->getHeaderSearchOpts(), __clang->getPreprocessorOpts(), clang::CodeGenOptions(), __llvm->llvmContext )); __codegen->Initialize(ast->getASTContext()); }; bool ExternLayer::isPointer(const clang::QualType &t) { const clang::Type * tInfo = t.getTypePtr(); assert(tInfo); return tInfo->isAnyPointerType(); } llvm::Type* ExternLayer::toLLVMType(const clang::QualType& t) { return CodeGen::convertTypeForMemory( __codegen->CGM(), t); } std::vector ExternLayer::getStructFields(const clang::QualType& ty) { clang::QualType t = ty; if (isPointer(ty)) { const clang::PointerType* tPtr = ty->getAs(); t = tPtr->getPointeeType(); } assert(t.getTypePtr()->isRecordType()); const RecordType *record = t->getAsStructureType(); assert(record); std::vector result; //FieldDecl* field: record->getDecl()->fields() for (auto i = record->getDecl()->field_begin(); i != record->getDecl()->field_end(); ++i) { result.push_back(i->getName()); } return result; } bool ExternLayer::isArrayType(const std::string& type){ clang::QualType typeRaw = lookupType(type); if (isPointer(typeRaw)) { const clang::PointerType* typePtr = typeRaw->getAs(); typeRaw = typePtr->getPointeeType(); } return typeRaw->isArrayType(); } bool ExternLayer::isRecordType(const std::string& type){ clang::QualType typeRaw = lookupType(type); if (isPointer(typeRaw)) { const clang::PointerType* typePtr = typeRaw->getAs(); typeRaw = typePtr->getPointeeType(); } return typeRaw->isRecordType(); } clang::QualType ExternLayer::lookupType(const std::string& id) { MatchFinder finder; FinderCallbackTypeDecl callbackTypeDecl; auto matcherTypeDecl = typedefDecl(hasName(id)).bind("typename"); finder.addMatcher(matcherTypeDecl, &callbackTypeDecl); finder.matchAST(ast->getASTContext()); assert(! callbackTypeDecl.typeResult.isNull()); return callbackTypeDecl.typeResult; } llvm::Function* ExternLayer::lookupFunction(const std::string& name) { if (__functions.count(name)) { return __functions.at(name); } MatchFinder finder; FinderCallbackFunction callback; auto matcher = functionDecl(hasName(name)).bind("function"); finder.addMatcher(matcher, &callback); finder.matchAST(ast->getASTContext()); if (callback.typeResult.isNull()) { cout << "[External Layer] " << "Unknown function: " << name << endl; assert(false && "Unknown external function"); } const QualType& tyFuncQual = callback.typeResult; llvm::Type *tyRaw = CodeGen::convertTypeForMemory(__codegen->CGM(), tyFuncQual); llvm::FunctionType* tyRawFunc = llvm::dyn_cast(tyRaw); llvm::Function* function = llvm::Function::Create( tyRawFunc, llvm::GlobalValue::ExternalLinkage, name, __llvm->module.get()); __functions.emplace(name, function); return function; } }//end of xreate namespace diff --git a/cpp/src/ExternLayer.h b/cpp/src/ExternLayer.h index 0bae75e..4617a6f 100644 --- a/cpp/src/ExternLayer.h +++ b/cpp/src/ExternLayer.h @@ -1,72 +1,71 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * ExternLayer.h * * Created on: 4/21/15 * Author: pgess */ /** * \file ExternLayer.h * \brief An external C code interaction support */ #ifndef XREATE_EXTERNLAYER_H #define XREATE_EXTERNLAYER_H #include "llvmlayer.h" #include #include #include #include "ast.h" #include "clang/AST/ASTContext.h" #include "clang/Frontend/ASTUnit.h" -#include "clang/Frontend/CodeGenOptions.h" #include "clang/CodeGen/CodeGenABITypes.h" #include "clang/Lex/PreprocessorOptions.h" namespace clang{ class CodeGenerator; } namespace xreate{ struct ExternData{ void addLibrary(Atom&& name, Atom&& package); void addIncludeDecl(Expression&& e); std::vector entries; std::map __dictLibraries; }; /** \brief A wrapper over Clang */ class ExternLayer{ public: ExternLayer(LLVMLayer* llvm); void init(const AST* root); llvm::Function* lookupFunction(const std::string& name); clang::QualType lookupType(const std::string& id); std::vector getStructFields(const clang::QualType& ty); llvm::Type* toLLVMType(const clang::QualType& t); bool isPointer(const clang::QualType& t); bool isArrayType(const std::string& type); bool isRecordType(const std::string& type); static std::vector fetchPackageFlags(const ExternEntry& entry); static std::vector fetchPackageLibs(const ExternEntry& entry); private: std::unique_ptr ast; std::unique_ptr __codegen; std::unique_ptr __clang; LLVMLayer* __llvm; std::vector entries; std::map __functions; void addExternalData(const std::vector& data); void loadLibraries(std::vector&& libs); }; } #endif //XREATE_EXTERNLAYER_H diff --git a/cpp/src/analysis/interpretation.cpp b/cpp/src/analysis/interpretation.cpp index 7c18b4e..26e5c64 100644 --- a/cpp/src/analysis/interpretation.cpp +++ b/cpp/src/analysis/interpretation.cpp @@ -1,269 +1,267 @@ /* * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * Author: pgess * Created on June 25, 2018, 3:25 PM */ #include "analysis/interpretation.h" using namespace std; namespace xreate{ namespace interpretation{ typedef vector InstancePacked; std::list generateAllInstancesInDomain2(const ExpandedType& domainT) { if(!domainT->isValid()) { return {Expression()}; } assert(domainT->__operator == TypeOperator::VARIANT); std::list results; int variantId = -1; bool flagDomainStateless = std::all_of(domainT->__operands.begin(), domainT->__operands.end(), [](const TypeAnnotation & subdomainT) { return !subdomainT.isValid(); }); for(const TypeAnnotation& subdomainT : domainT->__operands) { ++variantId; if(flagDomainStateless) { Expression result(Operator::VARIANT,{}); result.setValueDouble(variantId); results.push_back(result); continue; } std::list subresults = generateAllInstancesInDomain2(ExpandedType(subdomainT)); for (const Expression& subresult : subresults) { Expression result(Operator::VARIANT,{}); result.setValueDouble(variantId); result.operands.push_back(subresult); results.push_back(result); } } return results; } TypeAnnotation -collapseFnGroup(const std::list& symbols) { - Gringo::Symbol symbolAny = symbols.front(); - size_t operandsCount = symbolAny.args().size; +collapseFnGroup(const std::list& symbols) { + Clingo::Symbol symbolAny = symbols.front(); + size_t operandsCount = symbolAny.arguments().size(); TypeAnnotation resultT; resultT.__operands.reserve(operandsCount); for(size_t operandId = 0; operandId < operandsCount; ++operandId) { - std::list column; + std::list column; - for(const Gringo::Symbol& row : symbols) { - column.push_back(row.args()[operandId]); + for(const Clingo::Symbol& row : symbols) { + column.push_back(row.arguments()[operandId]); } TypeAnnotation operandT = collapseColumn(column); resultT.__operands.push_back(operandT); } if(resultT.__operands.size() == 1) { return resultT.__operands.front(); } if(resultT.__operands.size() > 1) { resultT.__operator = TypeOperator::LIST_RECORD; return resultT; } return resultT; } TypeAnnotation -collapseColumn(const std::list& symbols) { +collapseColumn(const std::list& symbols) { TypeAnnotation resultT; if(!symbols.size()) return resultT; - Gringo::Symbol symbolAny = symbols.front(); + Clingo::Symbol symbolAny = symbols.front(); switch(symbolAny.type()) { - case Gringo::SymbolType::Num: + case Clingo::SymbolType::Number: { return TypeAnnotation(TypePrimitive::Num); } - case Gringo::SymbolType::Str: + case Clingo::SymbolType::String: { return TypeAnnotation(TypePrimitive::String); } - case Gringo::SymbolType::Fun: + case Clingo::SymbolType::Function: { - map> fnGroups; + map> fnGroups; - for(const Gringo::Symbol& row : symbols) { - fnGroups[row.name().c_str()].push_back(row); + for(const Clingo::Symbol& row : symbols) { + fnGroups[row.name()].push_back(row); } TypeAnnotation resultT; resultT.__operands.reserve(fnGroups.size()); resultT.bindings.reserve(fnGroups.size()); for(const auto& group : fnGroups) { if(!group.second.size()) continue; TypeAnnotation variantT = collapseFnGroup(group.second); - Gringo::Symbol symbolAny = group.second.front(); - string variantName = symbolAny.name().c_str(); + Clingo::Symbol symbolAny = group.second.front(); + string variantName(symbolAny.name()); resultT.fields.push_back(variantName); resultT.__operands.push_back(variantT); } resultT.__operator = TypeOperator::VARIANT; // if(resultT.__operands.size() == 1) { // return resultT.__operands.front(); // } return resultT; } - case Gringo::SymbolType::Inf: - case Gringo::SymbolType::Special: - case Gringo::SymbolType::Sup: + case Clingo::SymbolType::Infimum: + case Clingo::SymbolType::Supremum: { break; } } assert(false); return TypeAnnotation(); } ExpandedType dereferenceSlaveType(ExpandedType t, const TranscendLayer* transcend) { assert(t->__operator == TypeOperator::SLAVE); const string& domain = t->__valueCustom; StaticModel model = transcend->query(domain); if(!model.size()) return ExpandedType(TypeAnnotation()); - std::list symbols; + std::list symbols; for(auto row : model) { symbols.push_back(row.second); } return ExpandedType(collapseFnGroup(symbols)); } Expression -representTransExpression(const Gringo::Symbol& atom, ExpandedType schemaT, TranscendLayer* transcend) { - atom.print(std::cout); std::cout<__operator) { case TypeOperator::NONE: { switch(schemaT->__value) { case TypePrimitive::I8: case TypePrimitive::I32: case TypePrimitive::I64: case TypePrimitive::Num: case TypePrimitive::Int: { - return Expression(Atom(atom.num())); + return Expression(Atom(atom.number())); } case TypePrimitive::String: { - return Expression(Atom(atom.string().c_str())); + return Expression(Atom(atom.string())); } case TypePrimitive::Invalid: case TypePrimitive::Bool: case TypePrimitive::Float: { assert(false); return Expression(); } } break; } case TypeOperator::SLAVE: { ExpandedType contentT = dereferenceSlaveType(schemaT, transcend); return representTransExpression(atom, contentT, transcend); } case TypeOperator::VARIANT: { map dictVariants; for(size_t variantId = 0; variantId < schemaT->fields.size(); ++variantId) { dictVariants.emplace(schemaT->fields.at(variantId), variantId); } - string predicateName = atom.name().c_str(); + string predicateName(atom.name()); assert(dictVariants.count(predicateName)); size_t predicateId = dictVariants.at(predicateName); Expression result(Operator::VARIANT,{}); result.op = Operator::VARIANT; result.setValueDouble(predicateId); if(!schemaT->__operands.size()) return result; ExpandedType contentT = schemaT->__operands.at(predicateId).__operator == TypeOperator::SLAVE ? dereferenceSlaveType(ExpandedType(schemaT->__operands.at(predicateId)), transcend) : ExpandedType(schemaT->__operands.at(predicateId)); //edge case, content's type is LIST_NAMED: if (contentT->__operator == TypeOperator::LIST_RECORD) { result.operands.push_back(representTransExpression(atom, contentT, transcend)); } else if(!contentT->isValid()) { return result; } else { - assert(atom.args().size); - result.operands.push_back(representTransExpression(atom.args()[0], contentT, transcend)); + assert(atom.arguments().size()); + result.operands.push_back(representTransExpression(atom.arguments()[0], contentT, transcend)); } return result; } case TypeOperator::LIST_RECORD: { - const Gringo::SymSpan& operandsRaw = atom.args(); - size_t opCount = operandsRaw.size; + const Clingo::SymbolSpan& operandsRaw = atom.arguments(); + size_t opCount = operandsRaw.size(); assert(opCount == schemaT->__operands.size()); size_t operandId = 0; std::vector operands; operands.reserve(opCount); for(const TypeAnnotation operandT : schemaT->__operands) { operands.push_back(representTransExpression(operandsRaw[operandId], ExpandedType(operandT), transcend)); ++operandId; } Expression result(Operator::LIST,{}); result.operands = operands; result.type = schemaT; return result; } case TypeOperator::LIST_ARRAY: case TypeOperator::CALL: case TypeOperator::CUSTOM: case TypeOperator::ACCESS: case TypeOperator::LINK: { assert(false); return Expression(); } } assert(false); return Expression(); } } } //end of xreate namespace diff --git a/cpp/src/analysis/interpretation.h b/cpp/src/analysis/interpretation.h index 8a93e17..c00e475 100644 --- a/cpp/src/analysis/interpretation.h +++ b/cpp/src/analysis/interpretation.h @@ -1,45 +1,45 @@ /* * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * Author: pgess * Created on June 25, 2018, 3:24 PM */ /** * \file interpretation.h * \brief Interpretation related functions */ #ifndef INTERPRETATION_H #define INTERPRETATION_H #include "transcendlayer.h" namespace xreate{ namespace interpretation{ /** * \brief Converts a Transcend's fact to a Xreate's expression that can be interpreted further. Supports `query` keyword. * @param atom Transcend's fact * @param schemaT Type of the resulting expression * @param transcend Transcend's instance * @return converted Transcend' fact in form of Xreate's expression */ - Expression representTransExpression(const Gringo::Symbol& atom, ExpandedType schemaT, TranscendLayer* transcend); + Expression representTransExpression(const Clingo::Symbol& atom, ExpandedType schemaT, TranscendLayer* transcend); /** * \brief Expands slave type. * @param t Slave type * @param transcend Instance of Transcend * @return The expanded slave type */ ExpandedType dereferenceSlaveType(ExpandedType t, const TranscendLayer* transcend); - TypeAnnotation collapseColumn(const std::list& symbols); + TypeAnnotation collapseColumn(const std::list& symbols); std::list generateAllInstancesInDomain2(const ExpandedType& domainT); } } #endif /* INTERPRETATION_H */ diff --git a/cpp/src/aux/latereasoning.cpp b/cpp/src/aux/latereasoning.cpp index a14143e..4942490 100644 --- a/cpp/src/aux/latereasoning.cpp +++ b/cpp/src/aux/latereasoning.cpp @@ -1,54 +1,54 @@ /* * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * Author: pgess * Created on June 7, 2018, 6:01 PM */ #include "aux/latereasoning.h" #include "analysis/interpretation.h" #include "ast.h" using namespace std; namespace xreate{ namespace latereasoning{ -LateAnnotation::LateAnnotation(const Gringo::Symbol& symbolStatic) { - guardedContent.push_back(pair, Gringo::Symbol>({}, symbolStatic)); +LateAnnotation::LateAnnotation(const Clingo::Symbol& symbolStatic) { + guardedContent.push_back(pair, Clingo::Symbol>({}, symbolStatic)); } -boost::optional +boost::optional LateAnnotation::select(const std::list& keys, AST* root, TranscendLayer* transcend) const { for(const auto& entry : guardedContent) { - const std::list& guardsExpected = entry.first; + const std::list& guardsExpected = entry.first; auto keyPSIt = guardKeys.begin(); auto keyActualIt = keys.begin(); bool result = true; - for(const Gringo::Symbol& guardExpectedGS : guardsExpected) { + for(const Clingo::Symbol& guardExpectedGS : guardsExpected) { auto keyS = transcend->unpack(*keyPSIt); const ExpandedType& keyT = root->getType(CodeScope::getDefinition(keyS)); const ExpandedType& keyTPlain = keyT->__operator == TypeOperator::SLAVE ? interpretation::dereferenceSlaveType(keyT, transcend) : keyT; Expression guardExpectedE = interpretation::representTransExpression( guardExpectedGS, keyTPlain, transcend); if(!(guardExpectedE == *keyActualIt)) { result = false; break; } ++keyActualIt; ++keyPSIt; } if(!result) continue; return entry.second; } return boost::none; } } } diff --git a/cpp/src/aux/latereasoning.h b/cpp/src/aux/latereasoning.h index e6ba460..d2e8946 100644 --- a/cpp/src/aux/latereasoning.h +++ b/cpp/src/aux/latereasoning.h @@ -1,91 +1,91 @@ /* * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * Author: pgess * Created on June 2, 2018, 1:08 PM */ /** * \file src/aux/latereasoning.h * \brief Late reasoning support */ #ifndef LATEREASONING_H #define LATEREASONING_H #include "transcendlayer.h" namespace xreate{ namespace latereasoning{ /** \brief Represents Late Annotation, i.e. an annotation with late or runtime defined parameters*/ struct LateAnnotation{ LateAnnotation(){} - LateAnnotation(const Gringo::Symbol& symbolStatic); - std::list, Gringo::Symbol>> guardedContent; + LateAnnotation(const Clingo::Symbol& symbolStatic); + std::list, Clingo::Symbol>> guardedContent; std::list guardKeys; - boost::optional select(const std::list& keys, AST* root, TranscendLayer* transcend) const; + boost::optional select(const std::list& keys, AST* root, TranscendLayer* transcend) const; }; /** \brief Represents a group of all late annotations attached to a specific target */ struct LateAnnotationsGroup{ - std::unordered_map annotations; + std::unordered_map annotations; }; -typedef std::map LateModel; +typedef std::map LateModel; /** * \brief Decorates \ref TranscendLayer to support late annotations processing * \extends TranscendLayer */ template class LateReasoningTranscendDecorator: public Parent{ public: const LateAnnotationsGroup& queryLate(const std::string& alias) const{ static LateAnnotationsGroup groupInvalid; if(!__modelLate.count(alias)) return groupInvalid; return __modelLate.at(alias); } protected: - virtual bool processSolution(Gringo::Model const &model) override{ + virtual bool processSolution(Clingo::Model const &model) override{ const std::string& atomLateStatement = "late"; - for(const Gringo::Symbol& atom: model.atoms(clingo_show_type_atoms)){ - std::string atomName(atom.name().c_str()); + for(const Clingo::Symbol& atom: model.symbols(clingo_show_type_atoms)){ + std::string atomName(atom.name()); if(atomName == atomLateStatement){ //late atom's format: (Target, (tuple of keys), (tuple of values), late-annotation) - auto atomLate = TranscendLayer::parse, std::list, Gringo::Symbol>(atom); - const std::string& atomAlias = std::get<3>(atomLate).name().c_str(); + auto atomLate = TranscendLayer::parse, std::list, Clingo::Symbol>(atom); + std::string atomAlias(std::get<3>(atomLate).name()); addLateAtom(atomAlias, std::get<0>(atomLate), std::get<3>(atomLate), std::get<1>(atomLate), std::get<2>(atomLate)); } } return Parent::processSolution(model); } private: std::map __modelLate; - void addLateAtom(const std::string& alias, const Gringo::Symbol& annId, - const Gringo::Symbol& content, const std::list& guardKeys, - const std::list& guardValues){ + void addLateAtom(const std::string& alias, const Clingo::Symbol& annId, + const Clingo::Symbol& content, const std::list& guardKeys, + const std::list& guardValues){ LateAnnotationsGroup& group = __modelLate[alias]; LateAnnotation& annotation = group.annotations[annId]; if (annotation.guardedContent.empty()){ annotation.guardKeys = guardKeys; } annotation.guardedContent.push_back(std::make_pair(guardValues, content)); } }; }} // end of xreate::latereasoning #endif /* LATEREASONING_H */ diff --git a/cpp/src/compilation/interpretation-instructions.cpp b/cpp/src/compilation/interpretation-instructions.cpp index f4387bd..57e9bf6 100644 --- a/cpp/src/compilation/interpretation-instructions.cpp +++ b/cpp/src/compilation/interpretation-instructions.cpp @@ -1,113 +1,113 @@ /* * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * Author: pgess * Created on June 15, 2018, 5:32 PM */ #include "compilation/interpretation-instructions.h" #include "analysis/interpretation.h" #include "transcendlayer.h" #include "targets.h" #include "aux/latereasoning.h" #include "latetranscend.h" #include "aux/transcend-decorators.h" #include "compilation/targetinterpretation.h" using namespace std; using namespace xreate::latereasoning; namespace xreate{ namespace interpretation{ Expression IntrinsicQueryInstruction::process(const Expression& expression) { AST* ast = static_cast (__fnI12n->man)->ast; TranscendLayer* transcend = static_cast (__fnI12n->man)->pass->man->transcend; ExpandedType targetT = ast->getType(expression); assert(expression.operands.size() == 1); assert(expression.operands.front().__state == Expression::STRING); assert(targetT->__operator == TypeOperator::LIST_ARRAY); std::string namePredicate = expression.operands.front().getValueString(); StaticModel model = (static_cast (__fnI12n->man))->pass->man->transcend->query(namePredicate); Expression result(Operator::LIST,{}); result.operands.reserve(model.size()); ExpandedType elementT = targetT->__operands.at(0).__operator == TypeOperator::SLAVE ? dereferenceSlaveType(ExpandedType(targetT->__operands.at(0)), transcend) : ExpandedType(targetT->__operands.at(0)); if(model.size()) { if (elementT->__operator == TypeOperator::LIST_RECORD) { //edge case, content's type is LIST_NAMED: for(const auto& row : model) { result.operands.push_back(representTransExpression(row.second, elementT, transcend)); } } else { for (const auto& row : model) { - assert(row.second.args().size); - result.operands.push_back(representTransExpression(row.second.args()[0], elementT, transcend)); + assert(row.second.arguments().size()); + result.operands.push_back(representTransExpression(row.second.arguments()[0], elementT, transcend)); } } } return result; } llvm::Value* IntrinsicQueryInstruction::processLate(const Expression& expression, const compilation::Context& context) { assert(expression.blocks.size()); CodeScope* body = expression.blocks.front(); PassManager* man = static_cast (__fnI12n->man)->pass->man; compilation::ICodeScopeUnit* bodyBrute = context.function->getScopeUnit(body); llvm::Type* instructionT = man->llvm->toLLVMType(man->root->getType(expression)); Expression atomNameE = __fnI12n->getScope(context.scope->scope)->process(expression.operands.front()); assert(atomNameE.__state == Expression::STRING); string atomName = atomNameE.getValueString(); std::string argName = expression.bindings.front(); ExpandedType argT = man->root->getType(body->getDefinition(body->getSymbol(argName))); if (argT->__operator == TypeOperator::SLAVE){ argT = dereferenceSlaveType(argT, man->transcend); } auto transcend = Decorators::getInterface(man->transcend); LateReasoningCompiler* compiler = new latereasoning::LateReasoningCompiler(__fnI12n, context); SymbolPacked targetSP = transcend->pack(Attachments::get(expression)); LateAnnotationsGroup feedbackAG = transcend->queryLate(atomName); for(const auto& feedback : feedbackAG.annotations) { SymbolPacked targetExpectedSP = ParseImplAtom::get(feedback.first); if (targetExpectedSP == targetSP) { const LateAnnotation& annotation = feedback.second; return compiler->compileAutoExpand(annotation, instructionT, "", - [transcend, &argT, this, body, bodyBrute, &argName](const Gringo::Symbol & atomRaw) { + [transcend, &argT, this, body, bodyBrute, &argName](const Clingo::Symbol & atomRaw) { InterpretationScope* bodyI12n = __fnI12n->getScope(body); Expression argValue; if (argT->__operator == TypeOperator::LIST_RECORD) { argValue = representTransExpression(atomRaw, argT, transcend); } else { - argValue = representTransExpression(atomRaw.args()[0], argT, transcend); + argValue = representTransExpression(atomRaw.arguments()[0], argT, transcend); } bodyI12n->overrideBindings({ {argValue, argName}}); bodyBrute->reset(); return bodyBrute->compile(); }); } } assert(false && "No appropriate late annotation"); return nullptr; //should not be ever reachable } } } //end of xreate::interpretation diff --git a/cpp/src/compilation/latetranscend.cpp b/cpp/src/compilation/latetranscend.cpp index 54ce3e7..e34afa2 100644 --- a/cpp/src/compilation/latetranscend.cpp +++ b/cpp/src/compilation/latetranscend.cpp @@ -1,183 +1,183 @@ /* * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * latereasoning.cpp * * Author: pgess * Created on May 26, 2018, 3:54 PM */ /** * \class xreate::latereasoning::LateReasoningCompiler * Provides Late Transcend feature. See [Late Transcend](/d/transcend/late-transcend/) for the general overview. */ #include "compilation/latetranscend.h" -//#include "aux/latereasoning.h" #include "compilation/scopedecorators.h" #include "analysis/interpretation.h" #include "compilation/targetinterpretation.h" #include +#include using namespace xreate::interpretation; using namespace xreate::compilation; using namespace std; namespace xreate{ namespace latereasoning{ #define HINT(x) (hint.empty()? x : hint) std::map LateReasoningCompiler:: __dictGuardDefinitions = std::map(); llvm::Value* LateReasoningCompiler::processSwitchLateStatement(const Expression& expr, const std::string& hint) { AST* root = __context.pass->man->root; LLVMLayer* llvm = __context.pass->man->llvm; CodeScope* scopeBody = expr.blocks.front(); Symbol guardS = Symbol{scopeBody->getSymbol(expr.bindings.front()), scopeBody}; const ExpandedType& guardT = root->getType(expr.operands.at(0)); const ExpandedType& guardTPlain = guardT->__operator == TypeOperator::SLAVE? interpretation::dereferenceSlaveType(guardT, __context.pass->man->transcend) : guardT; llvm::Value * guardRaw = __context.scope->process(expr.operands.at(0)); llvm::Type* instructionT = llvm->toLLVMType(root->getType(expr)); return compileExpand(guardS, guardRaw, guardTPlain, instructionT, hint, [this, scopeBody]() { ICodeScopeUnit* bodyUnit = this->__context.function->getScopeUnit(scopeBody); bodyUnit->reset(); return this->__context.function->getScopeUnit(scopeBody)->compile(); }); } llvm::Value* LateReasoningCompiler::compileAutoExpand(const LateAnnotation& annotation, llvm::Type* resultT, const std::string& hint, Handler handler) { TranscendLayer* transcend = __context.pass->man->transcend; AST* root = __context.pass->man->root; const std::list& guardKeys = annotation.guardKeys; std::list guardsToExpand; for(const SymbolPacked key : guardKeys) { if(!__dictGuardDefinitions.count(key)) { const Symbol& keyS = transcend->unpack(key); InterpretationScope* keyScope = __fnI12n->getScope(keyS.scope); if (!keyScope->isBindingDefined(keyS.identifier)) { guardsToExpand.push_back(keyS); } } } typedef std::function < llvm::Value * () > Compiler; Compiler programInit([handler, annotation, this]() { std::list&& values = findKeys(annotation.guardKeys); auto answer = annotation.select(values, __context.pass->man->root, __context.pass->man->transcend); assert(answer); return handler(*answer); }); Compiler aggregate = std::accumulate(guardsToExpand.begin(), guardsToExpand.end(), programInit, [this, root, transcend, &resultT, hint](Compiler program, const Symbol & key) { const ExpandedType& keyT = root->getType(CodeScope::getDefinition(key)); const ExpandedType& keyTPlain = keyT->__operator == TypeOperator::SLAVE? interpretation::dereferenceSlaveType(keyT, transcend) : keyT; return Compiler([this, key, keyTPlain, resultT, hint, program](){ llvm::Value * keyRaw = __context.scope->processSymbol(key); return compileExpand(key, keyRaw, keyTPlain, resultT, hint, program); }); } ); return aggregate(); } llvm::Value* LateReasoningCompiler::compileExpand(const Symbol& keyS, llvm::Value* keyRaw, const ExpandedType& domainT, llvm::Type* resultT, const std::string& hint, CompilerHandler compilerBody) { assert(domainT->__operator == TypeOperator::VARIANT); std::list domInstancesList = generateAllInstancesInDomain2(domainT); std::vector domInstances(domInstancesList.begin(), domInstancesList.end()); const int countInstances = domInstances.size(); assert(countInstances); TranscendLayer* transcend = __context.pass->man->transcend; SymbolPacked keyP = transcend->pack(keyS); LLVMLayer* llvm = __context.pass->man->llvm; llvm::IRBuilder<>& builder = llvm->builder; compilation::IFunctionUnit* function = __context.function; llvm::Type* typI8 = llvm::Type::getInt8Ty(llvm->llvmContext); llvm::Value* keyVariantRaw = builder.CreateExtractValue(keyRaw, llvm::ArrayRef({0})); llvm::SwitchInst* instructionSwitch = builder.CreateSwitch(keyVariantRaw, nullptr, countInstances); llvm::BasicBlock *blockEpilog = llvm::BasicBlock::Create( llvm->llvmContext, "epilog", function->raw); builder.SetInsertPoint(blockEpilog); llvm::PHINode *ret = builder.CreatePHI(resultT, countInstances, HINT("reverse")); llvm::BasicBlock* blockDefault = nullptr; for (int instanceId = 0; instanceId < countInstances; ++instanceId) { llvm::BasicBlock *blockCase = llvm::BasicBlock::Create( llvm->llvmContext, "case" + std::to_string(instanceId), function->raw); if(instanceId == 0) blockDefault = blockCase; builder.SetInsertPoint(blockCase); //assign guard values const Expression& instanceE = domInstances.at(instanceId); __dictGuardDefinitions[keyP] = instanceE; // __fnI12n->getScope(keyS.scope)->overrideBindings({ // {instanceE, keyS.identifier} // }); //invoke further compilation handler llvm::Value* resultCase = compilerBody(); ret->addIncoming(resultCase, builder.GetInsertBlock()); instructionSwitch->addCase(llvm::dyn_cast(llvm::ConstantInt::get(typI8, instanceId)), blockCase); builder.CreateBr(blockEpilog); } //erase guard assignment __dictGuardDefinitions.erase(keyP); instructionSwitch->setDefaultDest(blockDefault); builder.SetInsertPoint(blockEpilog); return ret; } std::list LateReasoningCompiler::findKeys(const std::list& keys) { TranscendLayer* transcend = __context.pass->man->transcend; std::list result; InterpretationScope* scopeI12n = __fnI12n->getScope(__context.scope->scope); std::transform(keys.begin(), keys.end(), std::inserter(result, result.end()), [this, scopeI12n, transcend](const SymbolPacked & key) { if (__dictGuardDefinitions.count(key)){ return __dictGuardDefinitions.at(key); } return scopeI12n->processSymbol(transcend->unpack(key)); }); return result; } } } diff --git a/cpp/src/compilation/latetranscend.h b/cpp/src/compilation/latetranscend.h index a2df895..2ea6043 100644 --- a/cpp/src/compilation/latetranscend.h +++ b/cpp/src/compilation/latetranscend.h @@ -1,76 +1,76 @@ /* * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * File: latereasoning.h * Author: pgess * * Created on May 26, 2018, 3:44 PM */ /** * \file latetranscend.h * \brief Late Transcend support */ #ifndef CMPLLATEREASONING_H #define CMPLLATEREASONING_H #include "ast.h" #include "aux/latereasoning.h" #include "pass/compilepass.h" #include "llvmlayer.h" #include "transcendlayer.h" #include "targets.h" namespace xreate{ namespace interpretation{ class InterpretationFunction; } } namespace llvm{ class Value; } namespace xreate{ namespace latereasoning{ typedef std::function CompilerHandler; -typedef std::function Handler; +typedef std::function Handler; /** \brief [Late Transcend](d/transcend/late-transcend/) compilation support */ class LateReasoningCompiler{ public: LateReasoningCompiler(interpretation::InterpretationFunction* fn, compilation::Context ctx) : __context(ctx), __fnI12n(fn){ } llvm::Value* processSwitchLateStatement(const Expression& expr, const std::string& identHint); llvm::Value* compileAutoExpand(const LateAnnotation& annotation, llvm::Type* resultT, const std::string& hint, Handler handler); private: compilation::Context __context; interpretation::InterpretationFunction* __fnI12n; static std::map __dictGuardDefinitions; llvm::Value* compileExpand(const Symbol& keyS, llvm::Value* keyRaw, const ExpandedType& domainT, llvm::Type* resultT, const std::string& hint, CompilerHandler compilerBody); std::list findKeys(const std::list& keys); }; } } #endif /* CMPLLATEREASONING_H */ diff --git a/cpp/src/compilation/latex.cpp b/cpp/src/compilation/latex.cpp index 9a4d11e..52cc308 100644 --- a/cpp/src/compilation/latex.cpp +++ b/cpp/src/compilation/latex.cpp @@ -1,36 +1,36 @@ /* * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * Author: pgess * Created on June 23, 2018, 4:33 PM */ /** * \file src/compilation/latex.h * \brief Latex(Late Context) support */ #include "compilation/latex.h" #include "analysis/interpretation.h" #include "llvmlayer.h" namespace xreate{ namespace latex{ ExpandedType getSubjectDomain(const std::string& subject, LatexQuery* query){ - std::list&& column = query->getSubjectDomain(subject); + std::list&& column = query->getSubjectDomain(subject); return ExpandedType(interpretation::collapseColumn(column)); } llvm::Value* ExtraArgsFnInvocation::operator() (std::vector&& args, const std::string& hintDecl) { args.insert(args.end(), __argsLatex.begin(), __argsLatex.end()); return __parent->operator ()(std::move(args), hintDecl); } } -} \ No newline at end of file +} diff --git a/cpp/src/compilation/latex.h b/cpp/src/compilation/latex.h index e35ffeb..9e63501 100644 --- a/cpp/src/compilation/latex.h +++ b/cpp/src/compilation/latex.h @@ -1,144 +1,144 @@ /* * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ /* * Author: pgess * Created on June 23, 2018, 2:51 PM * * \file latex.h * \brief latex */ #ifndef LATEX_H #define LATEX_H #include "compilation/latetranscend.h" #include "compilation/interpretation-instructions.h" #include "query/latex.h" #include "pass/compilepass.h" #include "analysis/interpretation.h" #include "compilation/targetinterpretation.h" namespace xreate{ namespace latex{ ExpandedType getSubjectDomain(const std::string& subject, LatexQuery* query); /** \brief Latex(Late Context)-aware decorator for \ref xreate::compilation::IFunctionUnit * \extends xreate::compilation::IFunctionUnit */ template class LatexBruteFunctionDecorator: public Parent{ public: LatexBruteFunctionDecorator(ManagedFnPtr f, CompilePass* p) : Parent(f, p){ __query = reinterpret_cast (Parent::pass->man->transcend->getQuery(QueryId::LatexQuery)); } protected: std::vector prepareSignature(){ std::vector&& signature = Parent::prepareSignature(); const Demand& demand = __query->getFnDemand(Parent::function->getName()); signature.reserve(signature.size() + demand.size()); int subjectId = __query->LatexParametersOffset; for(const std::string& subject: demand){ const ExpandedType& subjectT = getSubjectDomain(subject, __query); Expression bindingE; bindingE.type = subjectT; std::string argCaption = std::string("latex_") + subject; Parent::function->addBinding( Atom(std::string(argCaption)), std::move(bindingE), subjectId++); llvm::Type* subjectTRaw = Parent::pass->man->llvm->toLLVMType(subjectT); signature.push_back(subjectTRaw); } return signature; } public: LatexQuery* __query; }; /** \brief %Function invocation operator decorator to handle latex enabled functions with hidden extra arguments */ class ExtraArgsFnInvocation: public compilation::IFnInvocation{ public: ExtraArgsFnInvocation(std::vector argsLatex, compilation::IFnInvocation* parent) : __argsLatex(argsLatex), __parent(parent){ } llvm::Value* operator()(std::vector&& args, const std::string& hintDecl = ""); private: std::vector __argsLatex; compilation::IFnInvocation* __parent; }; /** * \brief Latex aware \ref xreate::compilation::ICodeScopeUnit decorator * \implements xreate::compilation::ICodeScopeUnit */ template class LatexBruteScopeDecorator: public Parent{ public: LatexBruteScopeDecorator(const CodeScope * const codeScope, compilation::IFunctionUnit* f, CompilePass* compilePass) : Parent(codeScope, f, compilePass){ } compilation::IFnInvocation* findFunction(const Expression& opCall){ compilation::IFnInvocation* invocDefault = Parent::findFunction(opCall); const std::string& calleeName = opCall.getValueString(); LatexQuery* query = reinterpret_cast (Parent::pass->man->transcend->getQuery(QueryId::LatexQuery)); const Demand& fnCalleeDemand = query->getFnDemand(calleeName); if(!fnCalleeDemand.size()) return invocDefault; //prepare latex arguments std::vector argsLatex; argsLatex.reserve(fnCalleeDemand.size()); for(const std::string& subject: fnCalleeDemand){ ExpandedType subjectT = getSubjectDomain(subject, query); llvm::Type* subjectTRaw = Parent::pass->man->llvm->toLLVMType(subjectT); const latereasoning::LateAnnotation& decision = query->getDecision(subject, Parent::scope); compilation::Context ctx{this, Parent::function, Parent::pass}; interpretation::InterpretationScope* scopeIntrpr = Parent::pass->targetInterpretation->transformContext(ctx); latereasoning::LateReasoningCompiler* compiler = new latereasoning::LateReasoningCompiler(dynamic_cast(scopeIntrpr->function), ctx); llvm::Value* subjectRaw = compiler->compileAutoExpand( decision, subjectTRaw, subject, - [&](const Gringo::Symbol & decisionRaw){ + [&](const Clingo::Symbol & decisionRaw){ const Expression& decisionE = interpretation::representTransExpression( - decisionRaw.args()[2], subjectT, Parent::pass->man->transcend); + decisionRaw.arguments()[2], subjectT, Parent::pass->man->transcend); Attachments::put(decisionE, subjectT); return Parent::process(decisionE, subject); }); argsLatex.push_back(subjectRaw); } return new ExtraArgsFnInvocation(std::move(argsLatex), invocDefault); } }; } } //end of namespace xreate::context #endif /* LATEX_H */ diff --git a/cpp/src/compilation/polymorph.cpp b/cpp/src/compilation/polymorph.cpp index 97e654b..1ddd1ce 100644 --- a/cpp/src/compilation/polymorph.cpp +++ b/cpp/src/compilation/polymorph.cpp @@ -1,50 +1,50 @@ /* * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ /* * Author: pgess * Created on July 9, 2018, 6:04 PM */ #include "compilation/polymorph.h" using namespace std; namespace xreate{ namespace polymorph{ PolymorphFnInvocation::PolymorphFnInvocation(const latereasoning::LateAnnotation& selector, std::list calleeSpecializations, CompilePass* pass, PolymorphQuery* query, LLVMLayer* llvm, latereasoning::LateReasoningCompiler* compiler) : __selector(selector), __calleeSpecializations(calleeSpecializations), __pass(pass), __query(query), __llvm(llvm), __compiler(compiler) { } llvm::Value* PolymorphFnInvocation::operator()(std::vector&& args, const std::string& hintDecl) { std::map dictSelectors; for(ManagedFnPtr specialization : __calleeSpecializations) { dictSelectors.emplace(specialization->guard, specialization); } compilation::IFunctionUnit* specAny = __pass->getFunctionUnit(__calleeSpecializations.front()); return __compiler->compileAutoExpand( __selector, specAny->prepareResult(), hintDecl, - [this, &args, hintDecl, &dictSelectors](const Gringo::Symbol & selectorRaw) { + [this, &args, hintDecl, &dictSelectors](const Clingo::Symbol & selectorRaw) { const Expression & selectorE = __query->getValue(selectorRaw); assert(dictSelectors.count(selectorE) && "Inappropriate specialization guard"); compilation::BruteFnInvocation* invoc = new compilation::BruteFnInvocation( __pass->getFunctionUnit(dictSelectors.at(selectorE))->compile(), __llvm); return invoc->operator()(move(args), hintDecl); }); } } } diff --git a/cpp/src/llvmlayer.cpp b/cpp/src/llvmlayer.cpp index 846d96c..012bc9b 100644 --- a/cpp/src/llvmlayer.cpp +++ b/cpp/src/llvmlayer.cpp @@ -1,242 +1,240 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * llvmlayer.cpp * * Author: pgess */ /** * \file llvmlayer.h * \brief Bytecode generation */ #include "ast.h" #include "llvmlayer.h" #include "ExternLayer.h" #include "llvm/ExecutionEngine/ExecutionEngine.h" #include "llvm/ExecutionEngine/MCJIT.h" #include "llvm/Support/TargetSelect.h" #include #include using namespace llvm; using namespace xreate; using namespace std; LLVMLayer::LLVMLayer(AST* root) : llvmContext(), builder(llvmContext), ast(root), module(new llvm::Module(root->getModuleName(), llvmContext)) { - layerExtern = new ExternLayer(this); - layerExtern->init(root); + layerExtern = new ExternLayer(this); + layerExtern->init(root); + + InitializeNativeTarget(); + InitializeNativeTargetAsmPrinter(); } void* LLVMLayer::getFunctionPointer(llvm::Function* function) { uint64_t entryAddr = jit->getFunctionAddress(function->getName().str()); return (void*) entryAddr; } void LLVMLayer::initJit() { - std::string ErrStr; - LLVMInitializeNativeTarget(); - llvm::InitializeNativeTargetAsmPrinter(); - - llvm::EngineBuilder builder(std::unique_ptr(module.release())); - jit.reset(builder - .setEngineKind(llvm::EngineKind::JIT) - .setErrorStr(&ErrStr) - .setVerifyModules(true) - .create() - ); + std::string errStr; + + jit.reset( + EngineBuilder(std::unique_ptr(module.release())) + .setErrorStr(&errStr) + .setEngineKind(llvm::EngineKind::JIT) + .setVerifyModules(true) + .create() + ); } void LLVMLayer::print() { - llvm::PassManager PM; - PM.addPass(llvm::PrintModulePass(llvm::outs(), "banner")); - llvm::AnalysisManager aman; - PM.run(*module.get(), aman); + module->print(llvm::outs(), nullptr); } void LLVMLayer::moveToGarbage(void *o) { __garbage.push_back(o); } llvm::Type* LLVMLayer::toLLVMType(const ExpandedType& ty) const { std::map empty; return toLLVMType(ty, empty); } llvm::Type* LLVMLayer::toLLVMType(const ExpandedType& ty, std::map& conjuctions) const { TypeAnnotation t = ty; switch (t.__operator) { case TypeOperator::LIST_ARRAY: { assert(t.__operands.size() == 1); TypeAnnotation elTy = t.__operands.at(0); return llvm::ArrayType::get(toLLVMType(ExpandedType(move(elTy)), conjuctions), t.__size); } case TypeOperator::LIST_RECORD: { std::vector pack_; pack_.reserve(t.__operands.size()); std::transform(t.__operands.begin(), t.__operands.end(), std::inserter(pack_, pack_.end()), [this, &conjuctions](const TypeAnnotation & t) { return toLLVMType(ExpandedType(TypeAnnotation(t)), conjuctions); }); llvm::ArrayRef pack(pack_); //process recursive types: if (conjuctions.count(t.conjuctionId)) { auto result = conjuctions[t.conjuctionId]; result->setBody(pack, false); return result; } return llvm::StructType::get(llvmContext, pack, false); }; case TypeOperator::LINK: { llvm::StructType* conjuction = llvm::StructType::create(llvmContext); int id = t.conjuctionId; conjuctions.emplace(id, conjuction); return conjuction; }; case TypeOperator::CALL: { assert(false); }; case TypeOperator::CUSTOM: { //Look in extern types clang::QualType qt = layerExtern->lookupType(t.__valueCustom); return layerExtern->toLLVMType(qt); }; //DEBT omit ID field in case of single variant. case TypeOperator::VARIANT: { /* Variant Type Layout: * { * id :: i8, Holds stored variant id * storage:: type of biggest variant * } */ uint64_t sizeStorage = 0; llvm::Type* typStorageRaw = llvm::Type::getVoidTy(llvmContext); for(const TypeAnnotation& subtype : t.__operands) { llvm::Type* subtypeRaw = toLLVMType(ExpandedType(subtype), conjuctions); if (subtypeRaw->isVoidTy()) continue; uint64_t sizeSubtype = module->getDataLayout().getTypeStoreSize(subtypeRaw); if (sizeSubtype > sizeStorage) { sizeStorage = sizeSubtype; typStorageRaw = subtypeRaw; } } std::vector layout; layout.push_back(llvm::Type::getInt8Ty(llvmContext)); //id const bool flagHoldsData = sizeStorage > 0; if (flagHoldsData) { layout.push_back(typStorageRaw); //storage } return llvm::StructType::get(llvmContext, llvm::ArrayRef(layout)); } case TypeOperator::NONE: { switch (t.__value) { case TypePrimitive::I32: case TypePrimitive::Int: case TypePrimitive::Num: return llvm::Type::getInt32Ty(llvmContext); case TypePrimitive::Bool: return llvm::Type::getInt1Ty(llvmContext); case TypePrimitive::I8: return llvm::Type::getInt8Ty(llvmContext); case TypePrimitive::I64: return llvm::Type::getInt64Ty(llvmContext); case TypePrimitive::Float: return llvm::Type::getDoubleTy(llvmContext); case TypePrimitive::String: return llvm::Type::getInt8PtrTy(llvmContext); case TypePrimitive::Invalid: return llvm::Type::getVoidTy(llvmContext); default: assert(false); } } default: assert(false); } assert(false); return nullptr; } bool TypeUtils::isStruct(const ExpandedType& ty) { const TypeAnnotation& t = ty.get(); if (t.__operator == TypeOperator::LIST_RECORD) { return true; } if (t.__operator != TypeOperator::CUSTOM) { return false; } clang::QualType tqual = llvm->layerExtern->lookupType(t.__valueCustom); const clang::Type * raw = tqual.getTypePtr(); // TODO skip ALL the pointers until non-pointer type found if (raw->isStructureType()) return true; if (!raw->isAnyPointerType()) return false; clang::QualType pointee = raw->getPointeeType(); return pointee->isStructureType(); } bool TypeUtils::isPointer(const ExpandedType &ty) { if (ty.get().__operator != TypeOperator::CUSTOM) return false; clang::QualType qt = llvm->layerExtern->lookupType(ty.get().__valueCustom); return llvm->layerExtern->isPointer(qt); } std::vector TypeUtils::getStructFields(const ExpandedType &t) { return (t.get().__operator == TypeOperator::LIST_RECORD) ? t.get().fields : llvm->layerExtern->getStructFields( llvm->layerExtern->lookupType(t.get().__valueCustom)); } \ No newline at end of file diff --git a/cpp/src/modules.cpp b/cpp/src/modules.cpp index ca196eb..bb14d7b 100644 --- a/cpp/src/modules.cpp +++ b/cpp/src/modules.cpp @@ -1,168 +1,162 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * modules.cpp * * Author: pgess * Created on July 22, 2017, 5:13 PM */ /** * \file modules.h * \brief Modules support */ #include "modules.h" #include "modules/Parser.h" #include "analysis/utils.h" -#include +#include #include #include #include #include using namespace std; namespace fs = boost::filesystem; namespace xreate { namespace modules{ void ModuleRecord::addRequest(const Expression& request){ __requests.push_back(request); } void ModuleRecord::addControllerPath(const std::string& path){ __controllers.push_back(path); } void ModuleRecord::addDiscoveryPath(const std::string& path){ __discoveryPaths.push_back(path); } void ModuleRecord::addProperty(const Expression& prop){ __properties.push_back(prop); } void ModulesSolver::loadControllers(const ModuleRecord& module){ for (const std::string& pathController: module.__controllers){ std::fstream fileContent(pathController); __program << fileContent.rdbuf(); } } void ModulesSolver::extractProperties(const ModuleRecord& module){ const std::string atomProperty = "bind_module"; boost::format formatProperty(atomProperty + "(\"%1%\", %2%)."); for (const Expression& property: module.__properties){ std::list reprProp = xreate::analysis::compile(property); assert(reprProp.size()== 1); __program << (formatProperty % module.__path % reprProp.front()) << std::endl; } } void ModulesSolver::discoverModules(const ModuleRecord& moduleClient){ std::regex extXreate("\\.xreate$", std::regex::basic); for(const std::string& path: moduleClient.__discoveryPaths){ for(fs::directory_entry e: fs::recursive_directory_iterator(path)) { if (fs::is_regular_file(e.status())){ if (!std::regex_search(e.path().string(), extXreate)) continue; FILE* script = fopen(e.path().c_str(), "r"); Scanner scanner(script); Parser parser(&scanner); parser.Parse(); assert(!parser.errors->count && "Discovery errors"); parser.module.__path = e.path().c_str(); extractProperties(parser.module); fclose(script); } } } } void ModulesSolver::extractRequirements(const ModuleRecord& module){ const std::string atomQuery = "modules_require"; boost::format formatProperty(atomQuery + "(\"%1%\", %2%)."); for (const Expression& query: module.__requests){ std::list reprQuery = xreate::analysis::compile(query); assert(reprQuery.size()== 1); __program << (formatProperty % module.__path % reprQuery.front()) << std::endl; } } void ModulesSolver::add(const std::string& base){ __program << base; } void ModulesSolver::init(const std::string& programBase, const ModuleRecord& module){ add(programBase); extractRequirements(module); extractProperties(module); loadControllers(module); discoverModules(module); std::cout << __program.str() << std::endl; } std::list ModulesSolver::run(const ModuleRecord& module){ const std::string predicateResolution = "modules_resolution"; std::map dictResolution; - std::vector args{"clingo", nullptr}; - DefaultGringoModule moduleDefault; - Gringo::Scripts scriptsDefault(moduleDefault); - ClingoLib ctl(scriptsDefault, 0, args.data(), {}, 0); - - ctl.add("base", {}, __program.str()); - ctl.ground({{"base", {}}}, nullptr); - ctl.solve([&predicateResolution, this, &dictResolution, &module](Gringo::Model const &model) { - for (Gringo::Symbol atom : model.atoms(clingo_show_type_atoms)) { - std::cout << atom << std::endl; - if (std::strcmp(atom.name().c_str(), predicateResolution.c_str())!=0) continue; - - if (atom.arity() == 2){ - auto resolution = TranscendLayer::parse(atom); - dictResolution.emplace(get<0>(resolution), get<1>(resolution)); - continue; - } - - if (atom.arity() == 3){ - auto resolution = TranscendLayer::parse(atom); - if(get<2>(resolution) != module.__path) continue; - dictResolution.emplace(get<0>(resolution), get<1>(resolution)); - continue; - } - assert(false && "Wrong resolution format"); - } - return true; - }, {}); + Clingo::Control solver; + solver.add("base", {}, __program.str().c_str()); + solver.ground({{"base", {}}}, nullptr); + auto solution = solver.solve(); + for (const Clingo::Symbol& atom : solution.model().symbols(clingo_show_type_atoms)) { + std::cout << atom << std::endl; + if (std::strcmp(atom.name(), predicateResolution.c_str())!=0) continue; + + if (atom.match(predicateResolution.c_str(), 2)){ + auto resolution = TranscendLayer::parse(atom); + dictResolution.emplace(get<0>(resolution), get<1>(resolution)); + continue; + } + + if (atom.match(predicateResolution.c_str(), 3)){ + auto resolution = TranscendLayer::parse(atom); + if(get<2>(resolution) != module.__path) continue; + + dictResolution.emplace(get<0>(resolution), get<1>(resolution)); + continue; + } + } std::list result; for(const Expression& request: module.__requests){ assert(dictResolution.count(request) && "Can't find requested module"); result.push_back(dictResolution.at(request)); } return result; } }} //namespace xreate::modules diff --git a/cpp/src/pass/compilepass.cpp b/cpp/src/pass/compilepass.cpp index 06049f2..604c267 100644 --- a/cpp/src/pass/compilepass.cpp +++ b/cpp/src/pass/compilepass.cpp @@ -1,788 +1,788 @@ /* 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 Main compilation routine. See \ref xreate::CompilePass */ #include "compilepass.h" #include "transcendlayer.h" #include #include "llvmlayer.h" #include "query/containers.h" #include "compilation/containers.h" #include "ExternLayer.h" #include "compilation/targetinterpretation.h" #include "pass/versionspass.h" #include "compilation/scopedecorators.h" #include "compilation/operators.h" #include "compilation/latex.h" #include "analysis/typeinference.h" #include #include #include using namespace std; using namespace llvm; namespace xreate{ namespace compilation{ std::string BasicFunctionUnit::prepareName() { AST* ast = IFunctionUnit::pass->man->root; string name = ast->getFunctionSpecializations(IFunctionUnit::function->__name).size() > 1 ? IFunctionUnit::function->__name + std::to_string(IFunctionUnit::function.id()) : IFunctionUnit::function->__name; return name; } std::vector BasicFunctionUnit::prepareSignature() { LLVMLayer* llvm = IFunctionUnit::pass->man->llvm; AST* ast = IFunctionUnit::pass->man->root; CodeScope* entry = IFunctionUnit::function->__entry; std::vector signature; std::transform(entry->__bindings.begin(), entry->__bindings.end(), std::inserter(signature, signature.end()), [llvm, ast, entry](const std::string & arg)->llvm::Type* { assert(entry->__identifiers.count(arg)); ScopedSymbol argid{entry->__identifiers.at(arg), versions::VERSION_NONE}; return llvm->toLLVMType(ast->expandType(entry->__declarations.at(argid).type)); }); return signature; } llvm::Type* BasicFunctionUnit::prepareResult() { LLVMLayer* llvm = IFunctionUnit::pass->man->llvm; AST* ast = IFunctionUnit::pass->man->root; CodeScope* entry = IFunctionUnit::function->__entry; return llvm->toLLVMType(ast->expandType(entry->__declarations.at(ScopedSymbol::RetSymbol).type)); } llvm::Function::arg_iterator BasicFunctionUnit::prepareBindings() { CodeScope* entry = IFunctionUnit::function->__entry; ICodeScopeUnit* entryCompilation = IFunctionUnit::getScopeUnit(entry); llvm::Function::arg_iterator fargsI = IFunctionUnit::raw->arg_begin(); for (std::string &arg : entry->__bindings) { ScopedSymbol argid{entry->__identifiers[arg], versions::VERSION_NONE}; entryCompilation->bindArg(&*fargsI, argid); fargsI->setName(arg); ++fargsI; } return fargsI; } //DEBT compiler rigidly depends on exact definition of DefaultFunctionUnit typedef latex::LatexBruteFunctionDecorator< compilation::BasicFunctionUnit> BruteFunctionDefault; ICodeScopeUnit::ICodeScopeUnit(const CodeScope * const codeScope, IFunctionUnit* f, CompilePass* compilePass) : pass(compilePass), function(f), scope(codeScope), currentBlockRaw(nullptr) { } llvm::Value* BruteFnInvocation::operator()(std::vector&& args, const std::string& hintDecl) { llvm::Function* calleeInfo = dyn_cast(__callee); if (calleeInfo) { auto argsFormal = calleeInfo->args(); size_t sizeArgsF = std::distance(argsFormal.begin(), argsFormal.end()); assert(args.size() >= sizeArgsF); assert(calleeInfo->isVarArg() || args.size() == sizeArgsF); auto argFormal = argsFormal.begin(); for(size_t argId = 0; argId < args.size(); ++argId){ if(argFormal != argsFormal.end()){ args[argId] = typeinference::doAutomaticTypeConversion( args.at(argId), argFormal->getType(), llvm->builder); ++argFormal; } } } //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 IFnInvocation{ public: CallStatementInline(IFunctionUnit* caller, IFunctionUnit* callee, LLVMLayer* l) : __caller(caller), __callee(callee), llvm(l) { } llvm::Value* operator()(std::vector&& args, const std::string& hintDecl) { //TOTEST inlining // CodeScopeUnit* entryCompilation = outer->getScopeUnit(function->__entry); // for(int i=0, size = args.size(); ibindArg(args.at(i), string(entryCompilation->scope->__bindings.at(i))); // } // // // return entryCompilation->compile(); return nullptr; } private: IFunctionUnit* __caller; IFunctionUnit* __callee; LLVMLayer* llvm; bool isInline() { // Symbol ret = Symbol{0, function->__entry}; // bool flagOnTheFly = SymbolAttachments::get(ret, false); //TODO consider inlining return false; } } ; BasicCodeScopeUnit::BasicCodeScopeUnit(const CodeScope * const codeScope, IFunctionUnit* f, CompilePass* compilePass) : ICodeScopeUnit(codeScope, f, compilePass) { } llvm::Value* BasicCodeScopeUnit::processSymbol(const Symbol& s, std::string hintRetVar) { Expression declaration = CodeScope::getDefinition(s); const CodeScope* scopeExternal = s.scope; ICodeScopeUnit* scopeBruteExternal = ICodeScopeUnit::function->getScopeUnit(scopeExternal); assert(scopeBruteExternal->currentBlockRaw); llvm::Value* resultRaw; llvm::BasicBlock* blockOwn = pass->man->llvm->builder.GetInsertBlock(); if (scopeBruteExternal->currentBlockRaw == blockOwn) { resultRaw = scopeBruteExternal->process(declaration, hintRetVar); scopeBruteExternal->currentBlockRaw = currentBlockRaw = pass->man->llvm->builder.GetInsertBlock(); } else { pass->man->llvm->builder.SetInsertPoint(scopeBruteExternal->currentBlockRaw); resultRaw = scopeBruteExternal->processSymbol(s, hintRetVar); pass->man->llvm->builder.SetInsertPoint(blockOwn); } return resultRaw; } IFnInvocation* BasicCodeScopeUnit::findFunction(const Expression& opCall) { const std::string& calleeName = opCall.getValueString(); LLVMLayer* llvm = pass->man->llvm; const std::list& specializations = pass->man->root->getFunctionSpecializations(calleeName); //if no specializations registered - check external function if (specializations.size() == 0) { llvm::Function* external = llvm->layerExtern->lookupFunction(calleeName); llvm::outs() << "Debug/External function: " << calleeName; external->getType()->print(llvm::outs(), true); llvm::outs() << "\n"; return new BruteFnInvocation(external, llvm); } //There should be only one specialization without any valid guards at this point return new BruteFnInvocation(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]); 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: if (left->getType()->isIntegerTy()) return l.builder.CreateSDiv(left, right, DEFAULT("tmp_div")); if (left->getType()->isFloatingPointTy()) return l.builder.CreateFDiv(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")); const ExpandedType& leftT = pass->man->root->getType(expr.operands[0]); const ExpandedType& rightT = pass->man->root->getType(expr.operands[0]); if(leftT->__operator == TypeOperator::VARIANT && rightT->__operator == TypeOperator::VARIANT){ llvm::Type* selectorT = llvm::cast(left->getType())->getElementType(0); llvm::Value* leftUnwapped = typeinference::doAutomaticTypeConversion(left, selectorT, l.builder); llvm::Value* rightUnwapped = typeinference::doAutomaticTypeConversion(right, selectorT, l.builder); return l.builder.CreateICmpEQ(leftUnwapped, rightUnwapped, 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]); ExpandedType leftTy = pass->man->root->getType(expr.operands[0]); if (leftTy->__value == TypePrimitive::Bool){ return l.builder.CreateNot(left, DEFAULT("tmp_not")); } else { return l.builder.CreateNeg(left, DEFAULT("tmp_neg")); } break; } case Operator::CALL: { assert(expr.__state == Expression::COMPOUND); shared_ptr callee(findFunction(expr)); const std::string& nameCallee = expr.getValueString(); //prepare arguments std::vector args; args.reserve(expr.operands.size()); std::transform(expr.operands.begin(), expr.operands.end(), std::inserter(args, args.end()), [this](const Expression & operand) { return process(operand); } ); return (*callee)(move(args), DEFAULT("res_" + nameCallee)); } case Operator::IF: { return instructions.compileIf(expr, DEFAULT("tmp_if")); } case Operator::SWITCH: { return instructions.compileSwitch(expr, DEFAULT("tmp_switch")); } case Operator::LOGIC_AND: { assert(expr.operands.size() == 1); return process(expr.operands[0]); } case Operator::LIST: { ExpandedType exprT = l.ast->getType(expr); bool flagIsArray; do { if (exprT->__operator == TypeOperator::CUSTOM){ if (l.layerExtern->isArrayType(exprT->__valueCustom)){ flagIsArray = true; break; } if (l.layerExtern->isRecordType(exprT->__valueCustom)){ flagIsArray = false; break; } assert(false && "Inapproriate external type"); } if (exprT->__operator != TypeOperator::LIST_ARRAY && exprT->__operator != TypeOperator::LIST_RECORD){ assert(false && "Inapproriate type"); } flagIsArray = exprT->__operator == TypeOperator::LIST_ARRAY; } while(false); if(flagIsArray){ return instructions.compileListAsSolidArray(expr, DEFAULT("tmp_list")); } const std::vector fieldsFormal = (exprT.get().__operator == TypeOperator::CUSTOM) ? l.layerExtern->getStructFields(l.layerExtern->lookupType(exprT.get().__valueCustom)) : exprT.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(exprT)); 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::LIST_RANGE: { assert(false); //no compilation phase for a range list // return InstructionList(this).compileConstantArray(expr, l, hintRetVar); }; case Operator::MAP: { assert(expr.blocks.size()); return instructions.compileMapSolidOutput(expr, DEFAULT("map")); }; case Operator::FOLD: { return instructions.compileFold(expr, DEFAULT("fold")); }; case Operator::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_RECORD: 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_ARRAY: { std::vector indexes; std::transform(++expr.operands.begin(), expr.operands.end(), std::inserter(indexes, indexes.end()), [this] (const Expression & op) { return process(op); } ); return instructions.compileArrayIndex(aggr, indexes, DEFAULT(string("el_") + hintIdent)); }; default: assert(false); } }; 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::QUERY: case Operator::QUERY_LATE: { assert(false && "Should be processed by interpretation"); } case Operator::VARIANT: { const ExpandedType& typVariant = pass->man->root->getType(expr); llvm::Type* typVariantRaw = l.toLLVMType(typVariant); llvm::Type* typIdRaw = llvm::cast(typVariantRaw)->getElementType(0); uint64_t id = expr.getValueDouble(); llvm::Value* variantRaw = llvm::UndefValue::get(typVariantRaw); variantRaw = l.builder.CreateInsertValue(variantRaw, llvm::ConstantInt::get(typIdRaw, id), llvm::ArrayRef({0})); const bool flagDoReference = expr.operands.size(); if (flagDoReference) { const ExpandedType& subtyp = ExpandedType(typVariant->__operands.at(id)); llvm::Type* subtypRaw = l.toLLVMType(subtyp); Attachments::put(expr.operands.at(0), subtyp); llvm::Value* subtypValue = process(expr.operands.at(0)); llvm::Type* typStorageRaw = llvm::cast(typVariantRaw)->getElementType(1); llvm::Value* addrAsStorage = l.builder.CreateAlloca(typStorageRaw); llvm::Value* addrAsSubtyp = l.builder.CreateBitOrPointerCast(addrAsStorage, subtypRaw->getPointerTo()); l.builder.CreateStore(subtypValue, addrAsSubtyp); llvm::Value* storageRaw = l.builder.CreateLoad(typStorageRaw, addrAsStorage); variantRaw = l.builder.CreateInsertValue(variantRaw, storageRaw, llvm::ArrayRef({1})); } return variantRaw; } case Operator::SWITCH_VARIANT: { return instructions.compileSwitchVariant(expr, DEFAULT("tmpswitch")); } case Operator::SWITCH_LATE: { assert(false && "Instruction's compilation should've been redirected to interpretation"); return nullptr; } case Operator::SEQUENCE: { return instructions.compileSequence(expr); } case Operator::UNDEF: { llvm::Type* typExprUndef = l.toLLVMType(typeinference::getType(expr, *pass->man->root)); return llvm::UndefValue::get(typExprUndef); } case Operator::INVALID: assert(expr.__state != Expression::COMPOUND); switch (expr.__state) { case Expression::IDENT: { Symbol s = Attachments::get(expr); return processSymbol(s, expr.getValueString()); } case Expression::NUMBER: { llvm::Type* typConst = l.toLLVMType(typeinference::getType(expr, *pass->man->root)); int literal = expr.getValueDouble(); if (typConst->isFloatingPointTy()) return llvm::ConstantFP::get(typConst, literal); if (typConst->isIntegerTy()) return llvm::ConstantInt::get(typConst, literal); assert(false && "Can't compile literal"); } case Expression::STRING: { return instructions.compileConstantStringAsPChar(expr.getValueString(), DEFAULT("tmp_str")); }; default: { break; } }; break; default: break; } assert(false && "Can't compile expression"); return 0; } llvm::Value* BasicCodeScopeUnit::compile(const std::string& hintBlockDecl) { LLVMLayer* llvm = pass->man->llvm; if (!hintBlockDecl.empty()) { llvm::BasicBlock *block = llvm::BasicBlock::Create(llvm->llvmContext, hintBlockDecl, function->raw); pass->man->llvm->builder.SetInsertPoint(block); } currentBlockRaw = pass->man->llvm->builder.GetInsertBlock(); Symbol symbScope = Symbol{ScopedSymbol::RetSymbol, scope}; return processSymbol(symbScope); } ICodeScopeUnit::~ICodeScopeUnit() { } IFunctionUnit::~IFunctionUnit() { } llvm::Function* IFunctionUnit::compile() { if (raw != nullptr) return raw; LLVMLayer* llvm = pass->man->llvm; llvm::IRBuilder<>& builder = llvm->builder; string&& functionName = prepareName(); std::vector&& types = prepareSignature(); llvm::Type* expectedResultType = prepareResult(); llvm::FunctionType *ft = llvm::FunctionType::get(expectedResultType, types, false); - raw = llvm::cast(llvm->module->getOrInsertFunction(functionName, ft)); + raw = llvm::cast(llvm->module->getOrInsertFunction(functionName, ft).getCallee()); 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 BruteFunctionDefault(function, this); } template<> compilation::ICodeScopeUnit* CompilePassCustomDecorators ::buildCodeScopeUnit(const CodeScope * const scope, IFunctionUnit* function) { return new DefaultCodeScopeUnit(scope, function, this); } } // end of compilation compilation::IFunctionUnit* CompilePass::getFunctionUnit(const ManagedFnPtr& function) { unsigned int id = function.id(); if (!functions.count(id)) { compilation::IFunctionUnit* unit = buildFunctionUnit(function); functions.emplace(id, unit); return unit; } return functions.at(id); } void CompilePass::run() { //Initialization: managerTransformations = new xreate::compilation::TransformationsManager(); targetInterpretation = new interpretation::TargetInterpretation(this->man->root, this); //Determine entry function: StaticModel model = man->transcend->query(Config::get("function-entry")); assert(model.size() && "Error: No entry function found"); assert(model.size() == 1 && "Error: Ambiguous entry function"); string nameMain = std::get<0>(TranscendLayer::parse(model.begin()->second)); compilation::IFunctionUnit* unitMain = getFunctionUnit(man->root->findFunction(nameMain)); //Compilation itself: entry = unitMain->compile(); } llvm::Function* CompilePass::getEntryFunction() { assert(entry); return entry; } void CompilePass::prepareQueries(TranscendLayer* transcend) { transcend->registerQuery(new containers::Query(), QueryId::ContainersQuery); transcend->registerQuery(new polymorph::PolymorphQuery(), QueryId::PolymorphQuery); transcend->registerQuery(new latex::LatexQuery(), QueryId::LatexQuery); } } //end of namespace xreate /** * \class xreate::CompilePass * \brief The owner of the compilation process. Performs fundamental compilation activities along with the xreate::compilation's routines * * xreate::CompilePass traverses over xreate::AST tree and produces executable code. * The pass performs compilation using the following data sources: * - %Attachments: the data gathered by the previous passes. See \ref xreate::Attachments. * - Transcend solutions accessible via queries. See \ref xreate::IQuery, \ref xreate::TranscendLayer. * * The pass generates a bytecode by employing \ref xreate::LLVMLayer(wrapper over LLVM toolchain). * Many compilation activities are delegated to more specific routines. Most notable delegated compilation aspects are: * - Containers support. See \ref xreate::containers. * - Latex compilation. See \ref xreate::latex. * - Interpretation support. See \ref xreate::interpretation. * - Loop saturation support. See \ref xreate::compilation::TransformationsScopeDecorator. * - External code interaction support. See \ref xreate::ExternLayer (wrapper over Clang library). * * \section adaptability_sect Adaptability * xreate::CompilePass's behaviour can be adapted in several ways: * - %Function Decorators to alter function-level compilation. See \ref xreate::compilation::IFunctionUnit * - Code Block Decorators to alter code block level compilation. See \ref 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 \ref xreate::compilation::Target. * - Altering %function invocation. See \ref xreate::compilation::IFnInvocation. * * Clients are free to construct a compiler instantiation with the desired decorators by using \ref xreate::compilation::CompilePassCustomDecorators. * As a handy alias, `CompilePassCustomDecorators` constructs the default compiler. * */ diff --git a/cpp/src/query/containers.cpp b/cpp/src/query/containers.cpp index 9bfa1a5..0e1af82 100644 --- a/cpp/src/query/containers.cpp +++ b/cpp/src/query/containers.cpp @@ -1,111 +1,111 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * Author: pgess * * containers.cpp * Created on 3/14/15. */ #include #include "query/containers.h" using namespace std; using namespace xreate::containers; using namespace xreate; Implementation Query::queryImplementation(xreate::Symbol const &s) { if (Attachments::exists(s)) { return Attachments::get(s); } return Implementation::create(s); } Query::Query() { Attachments::init(); } void Query::init(TranscendLayer* transcend) { if (flagDataIsLoaded) return; //Fill implementation data for a data sources: auto range = transcend->query(Config::get("containers.id.implementations")); if (range.size()) for(auto atom : range) { - auto data = TranscendLayer::parse(atom.second); + auto data = TranscendLayer::parse(atom.second); Symbol var = transcend->unpack(get<0>(data)); - string implStr = get<1>(data).name().c_str(); + string implStr(get<1>(data).name()); if (implStr == Config::get("containers.impl.solid")) { auto size = TranscendLayer::parse(get<1>(data)); Attachments::put(var,{SOLID, ImplementationRec {get<0>(size)}}); } else if (implStr == Config::get("containers.impl.onthefly")) { Attachments::put(var,{ON_THE_FLY, ImplementationRec {var}}); } else { assert(false && "Unable to determine proper implementation for the symbol"); } } flagDataIsLoaded = true; } Implementation Implementation::create(const Symbol &var) { //TODO review implementation determination strategy Expression varDecl = CodeScope::getDefinition(var); switch (varDecl.op) { case Operator::LIST_RANGE: { ImplementationRec rec{var}; return {ON_THE_FLY, rec}; } case Operator::LIST: { return {SOLID, ImplementationRec {varDecl.getOperands().size()}}; } default: break; }; ImplementationLinkedList ill(var); if (ill) { return ill.getImplementationData(); } assert(false && "Unable to determine proper implementation for the symbol"); return Implementation(); } ImplementationLinkedList::ImplementationLinkedList(const Symbol& source) : flagIsValid(false), s(source) { const Expression& sourceExpr = CodeScope::getDefinition(source); if (sourceExpr.tags.count(Config::get("containers.id.linkedlist"))) { flagIsValid = true; Expression tagLinkedlist = sourceExpr.tags.at(Config::get("containers.id.linkedlist")); assert(tagLinkedlist.operands.size() == 2); fieldPointer = tagLinkedlist.operands.at(0).getValueString(); terminator = tagLinkedlist.operands.at(1); } } ImplementationLinkedList::operator bool () const { return flagIsValid; } Implementation ImplementationLinkedList::getImplementationData() const { return {ON_THE_FLY, ImplementationRec{s}}; } diff --git a/cpp/src/query/latex.cpp b/cpp/src/query/latex.cpp index 6970cc7..4ed2485 100644 --- a/cpp/src/query/latex.cpp +++ b/cpp/src/query/latex.cpp @@ -1,101 +1,101 @@ /* * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ /* * Author: pgess * Created on June 25, 2018, 12:14 PM * * \file latex.cpp * \brief latex */ #include "query/latex.h" #include "aux/transcend-decorators.h" using namespace std; using namespace xreate::latereasoning; namespace xreate{ namespace latex{ void LatexQuery::init(TranscendLayer* transcend) { __transcend = transcend; //schema: latex_fn_demand(Fn, Subject) StaticModel data = __transcend->query("latex_fn_demand_ordered"); for(const auto& entry : data) { string fnName, subject; size_t id; tie(fnName, subject, id) = __transcend->parse(entry.second); __demand[fnName].resize(std::max(__demand[fnName].size(), id+1)); __demand[fnName][id] = subject; } //schema: latex_registered_subjects(Subject, Decision) data = __transcend->query("latex_registered_subjects"); for(const auto& entry : data) { string subject; - Gringo::Symbol decision; + Clingo::Symbol decision; - tie(subject, decision) = __transcend->parse(entry.second); + tie(subject, decision) = __transcend->parse(entry.second); __domains[subject].push_back(decision); } //schema: latex_decision(Scope, Subject, Decision) data = __transcend->query("latex_decision"); for(const auto& entry : data) { ScopePacked scope; string subject; - Gringo::Symbol decision; + Clingo::Symbol decision; - tie(scope, subject, decision) = __transcend->parse(entry.second); + tie(scope, subject, decision) = __transcend->parse(entry.second); __decisions[make_pair(scope, subject)] = entry.second; } //schema: latex_parameters_offset(int) //Override parameter from transcend data = __transcend->query("latex_parameters_offset"); if(data.size()) { LatexParametersOffset = std::get<0>(__transcend->parse(data.begin()->second)); } auto transcendLate = Decorators::getInterface(__transcend); //Later decisions. schema: Scope, Subject, Decision LateAnnotationsGroup group = transcendLate->queryLate("latex_decision"); for (auto entry: group.annotations) { auto key = __transcend->parse(entry.first); __decisionsLate.emplace(make_pair(get<0>(key), get<1>(key)), entry.second); } } Demand LatexQuery::getFnDemand(const std::string& fnName) { if (!__demand.count(fnName)) return Demand(); return __demand.at(fnName); } latereasoning::LateAnnotation LatexQuery::getDecision(const std::string& subject, const CodeScope* scopeCaller) { ScopePacked scopeP = __transcend->pack(scopeCaller); if(__decisions.count(make_pair(scopeP, subject))){ //found static decision return LateAnnotation(__decisions.at(make_pair(scopeP, subject))); } return __decisionsLate.at(make_pair(scopeP, subject)); } -std::list +std::list LatexQuery::getSubjectDomain(const std::string& subject) { assert(__domains.count(subject)); return __domains.at(subject); } } } diff --git a/cpp/src/query/latex.h b/cpp/src/query/latex.h index c66f39f..9f5cd09 100644 --- a/cpp/src/query/latex.h +++ b/cpp/src/query/latex.h @@ -1,45 +1,45 @@ /* * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ /** * \file query/latex.h * \brief Transcend solution on [Context](/d/concepts/context/) implementation details */ #ifndef LATEXQUERY_H #define LATEXQUERY_H #include "transcendlayer.h" #include "aux/latereasoning.h" #include namespace xreate{ namespace latex{ typedef std::vector Demand; /** \brief Queries Transcend solution on [Context](/d/concepts/context/) implementation details */ class LatexQuery: public IQuery{ public: VNameId LatexParametersOffset = 1000; //Default value. Overriden by `latex_parameters_offset` from transcend Demand getFnDemand(const std::string& fnName); latereasoning::LateAnnotation getDecision(const std::string& subject, const CodeScope* scopeCaller); - std::list getSubjectDomain(const std::string& subject); + std::list getSubjectDomain(const std::string& subject); void init(TranscendLayer* transcend); private: TranscendLayer* __transcend; std::map __demand; - std::map, Gringo::Symbol> __decisions; + std::map, Clingo::Symbol> __decisions; std::map, latereasoning::LateAnnotation> __decisionsLate; - std::map> __domains; + std::map> __domains; }; } } #endif diff --git a/cpp/src/query/polymorph.cpp b/cpp/src/query/polymorph.cpp index 52f6aa0..b7bf78a 100644 --- a/cpp/src/query/polymorph.cpp +++ b/cpp/src/query/polymorph.cpp @@ -1,71 +1,71 @@ /* * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * File: polymorph.cpp * Author: pgess * * Created on November 9, 2017, 12:14 PM */ #include "polymorph.h" #include "aux/transcend-decorators.h" using namespace std; namespace xreate{ namespace polymorph{ const std::string atomPolymorph = "dfa_callguard"; void PolymorphQuery::init(TranscendLayer* transcend) { __transcend = transcend; StaticModel queryResult = transcend->query(atomPolymorph); if (queryResult.size()) { for (auto entry : queryResult) { - auto answer = TranscendLayer::parse(entry.second); + auto answer = TranscendLayer::parse(entry.second); SymbolNode symbCaller = std::get<0>(answer); SymbolGeneralized symbCallerUnpacked = transcend->unpack(symbCaller); __cacheEarlyReasoning.emplace(symbCallerUnpacked, entry.second); } } auto transcendLate = Decorators::getInterface(__transcend); latereasoning::LateAnnotationsGroup group = transcendLate->queryLate(atomPolymorph); for(auto entry : group.annotations) { - auto targetWrapper = Gringo::Symbol::createTuple(Gringo::SymSpan{&entry.first, 1}); + auto targetWrapper = Clingo::Function("", Clingo::SymbolSpan{&entry.first, 1}); auto targetSP = __transcend->parse(targetWrapper); SymbolGeneralized targetS = __transcend->unpack(std::get<0>(targetSP)); __cacheLateReasoning.emplace(targetS, entry.second); } } latereasoning::LateAnnotation PolymorphQuery::get(const Expression& e) const { SymbolGeneralized targetS = Attachments::exists(e) ? SymbolGeneralized(Attachments::get(e)) : SymbolGeneralized(SymbolAnonymous{e.id}); if (__cacheEarlyReasoning.count(targetS)) { return latereasoning::LateAnnotation(__cacheEarlyReasoning.at(targetS)); } if (__cacheLateReasoning.count(targetS)) { return __cacheLateReasoning.at(targetS); } assert(false && "Can't find a guard"); } Expression -PolymorphQuery::getValue(const Gringo::Symbol& symbol) const { - auto result = __transcend->parse(symbol); +PolymorphQuery::getValue(const Clingo::Symbol& symbol) const { + auto result = __transcend->parse(symbol); return std::get<1>(result); } } } //end of xreate::polymorph diff --git a/cpp/src/query/polymorph.h b/cpp/src/query/polymorph.h index 7be4f56..1baff59 100644 --- a/cpp/src/query/polymorph.h +++ b/cpp/src/query/polymorph.h @@ -1,42 +1,42 @@ /* * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * File: polymorph.h * Author: pgess * * Created on November 9, 2017, 12:14 PM */ /** * \file query/polymorph.h * \brief Transcend solution on [Polymorphism](/d/concepts/polymorphism/) implementation details */ #ifndef POLYMORPHQUERY_H #define POLYMORPHQUERY_H #include "transcendlayer.h" #include "aux/latereasoning.h" #include namespace xreate { namespace polymorph { /** \brief Queries Transcend solution on [Polymorphism](/d/concepts/polymorphism/) implementation details */ class PolymorphQuery: public IQuery { public: latereasoning::LateAnnotation get(const Expression& e) const; - Expression getValue(const Gringo::Symbol& s) const; + Expression getValue(const Clingo::Symbol& s) const; virtual void init(TranscendLayer* transcend) override; private: - std::unordered_map __cacheEarlyReasoning; + std::unordered_map __cacheEarlyReasoning; std::unordered_map __cacheLateReasoning; TranscendLayer* __transcend = nullptr; }; }}//end of xreate::polymorph #endif /* POLYMORPHQUERY_H */ diff --git a/cpp/src/transcendlayer.cpp b/cpp/src/transcendlayer.cpp index 2ecd979..56984f9 100644 --- a/cpp/src/transcendlayer.cpp +++ b/cpp/src/transcendlayer.cpp @@ -1,495 +1,471 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * Author: pgess * File: transcendlayer.cpp */ /** * \file transcendlayer.h * \brief Transcend reasoning implementation */ #include "transcendlayer.h" #include "analysis/utils.h" #include "utils.h" -#include #include #include #include #include #include using namespace std; //TODO escape identifiers started with upper case symbol namespace xreate{ bool operator==(const SymbolAnonymous& s1, const SymbolAnonymous& s2) { return s1.id == s2.id && s1.flagIsUsed == s2.flagIsUsed; } struct VisitorSymbolNodeHash : public boost::static_visitor{ std::size_t operator()(const xreate::SymbolPacked& node) const noexcept { return 2 * (node.identifier + 3 * node.scope + 5 * std::abs(node.version)); } std::size_t operator()(const xreate::SymbolAnonymous& node) const noexcept { return 7 * node.id; } } ; } namespace std{ std::size_t hash::operator()(xreate::SymbolNode const& s) const noexcept { return boost::apply_visitor(xreate::VisitorSymbolNodeHash(), s); } std::size_t hash::operator()(xreate::SymbolGeneralized const& s) const noexcept { return xreate::AttachmentsId::getId(s); } } namespace xreate{ void TranscendLayer::printWarnings(std::ostream& out) { const std::string warningTag = "warning"; auto warningsModel = query(warningTag); if(warningsModel.size()) for(auto warning : warningsModel) { unsigned int warningId; - Gringo::Symbol params; - std::tie(warningId, params) = parse(warning.second); + Clingo::Symbol params; + std::tie(warningId, params) = parse(warning.second); cout << "Warning: " << __warnings.at(warningId) << " "; - params.print(out); out << params; } } bool -TranscendLayer::processSolution(Gringo::Model const &model) { +TranscendLayer::processSolution(Clingo::Model const &model) { cout << "Model: " << endl; const string& atomBindVar = Config::get("transcend.bindings.variable"); const string& atomBindFunc = Config::get("transcend.bindings.function"); const string& atomBindScope = Config::get("transcend.bindings.scope"); - for(Gringo::Symbol atom : model.atoms(clingo_show_type_atoms)) { - atom.print(cout); - cout << " | " << endl; + for(const Clingo::Symbol& atom : model.symbols(clingo_show_type_atoms)) { + cout << atom << endl; - string atomName(atom.name().c_str()); + string atomName(atom.name()); if(atomName == atomBindVar || atomName == atomBindFunc || atomName == atomBindScope) { - string atomAlias = std::get<1>(parse(atom)).name().c_str(); + string atomAlias(std::get<1>(parse(atom)).name()); __model.emplace(atomAlias, atom); continue; } __model.emplace(atomName, atom); } return true; } void TranscendLayer::registerReport(IAnalysisReport * report) { __reports.push_back(report); } void TranscendLayer::printReports() { for(IAnalysisReport* report : __reports) { report->print(__partGeneral); } } void TranscendLayer::deleteReports(){ for(IAnalysisReport* report : __reports) { delete report; } __reports.clear(); } void TranscendLayer::addRuleWarning(const RuleWarning & rule) { //__partGeneral << rule << endl; list domains; boost::format formatDef("%1%(%2%)"); std::transform(rule.__args.begin(), rule.__args.end(), std::inserter(domains, domains.begin()), [&formatDef](const std::pair &argument) { string domain; switch(argument.second) { case DomainAnnotation::FUNCTION: domain = "function"; break; case DomainAnnotation::VARIABLE: domain = "variable"; break; } return boost::str(formatDef % domain % argument.first); }); list vars; std::transform(rule.__args.begin(), rule.__args.end(), std::inserter(vars, vars.begin()), [](const std::pair &argument) { return argument.first.c_str(); }); list> guardsRaw; std::transform(rule.__guards.begin(), rule.__guards.end(), std::inserter(guardsRaw, guardsRaw.begin()), [this](const Expression & guard) { return xreate::analysis::compile(guard); }); const list& guards = xreate::analysis::multiplyLists(std::move(guardsRaw)); list &&branches = xreate::analysis::compileNeg(rule.__condition); boost::format formatWarning("warning(%1%, (%2%)):- %3%, %4%, %5%."); for(const string &guardsJoined : guards) for(const string &branch : branches) { unsigned int hook = registerWarning(string(rule.__message)); __partGeneral << formatWarning % (hook) % (boost::algorithm::join(vars, ", ")) % (branch) % (guardsJoined) % (boost::algorithm::join(domains, ", ")) << endl; } } unsigned int TranscendLayer::registerWarning(std::string && message) { static int warningId = 0; __warnings.emplace(warningId, message); return warningId++; } void TranscendLayer::involveImports() { ostream &out = __partGeneral; if(ast) for(string fn : ast->__rawImports) { std::ifstream file(fn); if(!file) { std::cout << "Can't process script file: " << fn << std::endl; assert(false); } while(!file.eof()) { string line; std::getline(file, line); out << line << endl; } } } void TranscendLayer::addRawScript(std::string && script) { __partGeneral << script; } void TranscendLayer::run() { involveImports(); printReports(); ostringstream program; program << __partTags.str() << __partGeneral.str(); cout << FYEL(program.str()) << endl; - std::vector args{"clingo", nullptr}; - DefaultGringoModule moduleDefault; - Gringo::Scripts scriptsDefault(moduleDefault); - - ClingoLib ctl(scriptsDefault, 0, args.data(), { }, 0); - - ctl.add("base",{}, program.str()); - ctl.ground({ - {"base", - {}} - }, nullptr); - - // solve - Gringo::SolveResult result = ctl.solve([this](Gringo::Model const &model) { - this->processSolution(model); - return true; - }, - { - }); - - if(result.satisfiable() == Gringo::SolveResult::Satisfiable) { - cout << FGRN("SUCCESSFULLY") << endl; - } else { - cout << FRED("UNSUCCESSFULLY") << endl; - } + Clingo::Control ctl; + ctl.add("base",{}, program.str().c_str()); + ctl.ground({{"base",{}}}, nullptr); + this->processSolution(ctl.solve().model()); // invoke all query plugins to process solution for(auto q : __queries) { q.second->init(this); } } TranscendLayer::TranscendLayer() : ast(nullptr) { } StaticModel TranscendLayer::query(const std::string & atom) const { StaticModel result; if (! __model.count(atom)) { return result; } auto currentDataRange = __model.equal_range(atom); std::copy(currentDataRange.first, currentDataRange.second, std::inserter(result, result.end())); return result; } ScopePacked TranscendLayer::pack(const CodeScope * const scope) { auto pos = __indexScopes.emplace(scope, __indexScopes.size()); if(pos.second) __registryScopes.push_back(scope); return pos.first->second; } size_t TranscendLayer::getScopesCount() const { return __registryScopes.size(); } SymbolPacked TranscendLayer::pack(const Symbol& symbol, std::string hintSymbolName) { SymbolPacked result(symbol.identifier.id, symbol.identifier.version, pack(symbol.scope)); __indexSymbolNameHints.emplace(result, hintSymbolName); return result; } Symbol TranscendLayer::unpack(const SymbolPacked & symbol) const { return Symbol{ScopedSymbol {symbol.identifier, symbol.version}, __registryScopes[symbol.scope]}; }; std::string TranscendLayer::getHintForPackedSymbol(const SymbolPacked & symbol) { auto result = __indexSymbolNameHints.find(symbol); return(result == __indexSymbolNameHints.end()) ? "" : result->second; } IQuery * TranscendLayer::registerQuery(IQuery *query, const QueryId & id) { return __queries.emplace(id, query).first->second; } IQuery * TranscendLayer::getQuery(const QueryId & id) { assert(__queries.count(id) && "Undefined query"); return __queries.at(id); } class VisitorUnpackSymbol : public boost::static_visitor{ public: VisitorUnpackSymbol(const TranscendLayer* transcend) : __transcend(transcend) { } SymbolGeneralized operator()(const SymbolPacked& symbol) const { return __transcend->unpack(symbol); } SymbolGeneralized operator()(const SymbolAnonymous& symbol) const { return symbol; } private: const TranscendLayer* __transcend; } ; class VisitorPackSymbol : public boost::static_visitor{ public: VisitorPackSymbol(TranscendLayer* transcend, const std::string& hintSymbolName) : __transcend(transcend), __hint(hintSymbolName) { } SymbolNode operator()(const Symbol& symbol) const { return __transcend->pack(symbol, __hint); } SymbolNode operator()(const SymbolAnonymous& symbol) const { return symbol; } private: TranscendLayer* __transcend; std::string __hint; } ; SymbolNode TranscendLayer::pack(const SymbolGeneralized& symbol, const std::string & hintSymbolName) { return boost::apply_visitor(VisitorPackSymbol(this, hintSymbolName), symbol); } SymbolGeneralized TranscendLayer::unpack(const SymbolNode & symbol) const { return boost::apply_visitor(VisitorUnpackSymbol(this), symbol); } bool operator==(const SymbolPacked& s1, const SymbolPacked & s2) { return s1.identifier == s2.identifier && s1.scope == s2.scope; } bool operator<(const SymbolPacked& s1, const SymbolPacked & s2) { return s1.scope < s2.scope || (s1.scope == s2.scope && s1.identifier < s2.identifier); } Expression ParseImplAtom -::get(const Gringo::Symbol & atom) { +::get(const Clingo::Symbol & atom) { switch(atom.type()) { - case Gringo::SymbolType::Num: return Expression(atom.num()); - case Gringo::SymbolType::Str: return Expression(Atom(std::string(atom.string().c_str()))); + case Clingo::SymbolType::Number: return Expression(atom.number()); + case Clingo::SymbolType::String: return Expression(Atom(std::string(atom.string()))); - case Gringo::SymbolType::Fun: + case Clingo::SymbolType::Function: { //FUNC - Expression result(Operator::CALL,{Expression(Atom(std::string(atom.name().c_str())))}); - for(const Gringo::Symbol& arg : atom.args()) { + Expression result(Operator::CALL,{Expression(Atom(std::string(atom.name())))}); + for(const Clingo::Symbol& arg : atom.arguments()) { result.addArg(ParseImplAtom::get(arg)); } return result; } default: { assert(false); } } } int ParseImplAtom -::get(const Gringo::Symbol & atom) { +::get(const Clingo::Symbol & atom) { switch(atom.type()) { - case Gringo::SymbolType::Num: return atom.num(); + case Clingo::SymbolType::Number: return atom.number(); default: break; } assert(false && "Inappropriate symbol type"); } std::string ParseImplAtom -::get(const Gringo::Symbol & atom) { +::get(const Clingo::Symbol & atom) { switch(atom.type()) { - case Gringo::SymbolType::Str: return atom.string().c_str(); - case Gringo::SymbolType::Fun: return atom.name().c_str(); + case Clingo::SymbolType::String: return atom.string(); + case Clingo::SymbolType::Function: return atom.name(); - default: break; + default: break; } assert(false && "Inappropriate symbol type"); } SymbolPacked ParseImplAtom -::get(const Gringo::Symbol & atom) { +::get(const Clingo::Symbol & atom) { auto result = TranscendLayer::parse(atom); return SymbolPacked(std::get<0>(result), std::get<1>(result), std::get<2>(result)); }; -Gringo::Symbol -ParseImplAtom -::get(const Gringo::Symbol & atom) { +Clingo::Symbol +ParseImplAtom +::get(const Clingo::Symbol & atom) { return atom; } SymbolNode ParseImplAtom -::get(const Gringo::Symbol & atom) { - assert(atom.type() == Gringo::SymbolType::Fun +::get(const Clingo::Symbol & atom) { + assert(atom.type() == Clingo::SymbolType::Function && "Inappropriate symbol type"); - if(atom.name() == "a") { + if(atom.match("a", 1)) { return SymbolAnonymous{(unsigned int) std::get<0>(TranscendLayer::parse(atom))}; - } else if(atom.name() == "s") { + } else if(atom.match("s", 3)) { return ParseImplAtom::get(atom); } assert(false && "Wrong symbol format"); } class VisitorSymbolId : public boost::static_visitor{ public: unsigned int operator()(const Symbol& symbol) const { return AttachmentsId::getId(symbol); } unsigned int operator()(const SymbolAnonymous& symbol) const { return symbol.id; } } ; unsigned int AttachmentsId ::getId(const SymbolGeneralized & symbol) { return boost::apply_visitor(VisitorSymbolId(), symbol); } } //end of xreate namespace /** * \class xreate::TranscendLayer * \brief Logic reasoning implementation. Internally, it's a proxy to the external ASP solver [Clasp](https://potassco.org/clasp/) * * Performs reasoning over source codes in order to facilitate efficient compilation using results from a number of internal analyzers. * Clients implement \ref IAnalysisReport to supply Transcend with data and implement \ref IQuery to find out resolutions. * * Transcend uses the following sources to build a logic program before actual reasoning is performed: * - Raw content. Clients are free to include arbitrary ASP format data in the logic program. See \ref addRawScript(). * - External scripts. External files with ASP scripts can be appended to the logic program. See `involveImports()` (private member). * - Diagnostic rules to produce diagnostic messages during * compilation(warnings) or even to signal to halt compilation with errors. See \ref addRuleWarning(), \ref registerWarning(). * - Internal analyzers. The analyzer can publish logic facts and rules by implementing \ref IAnalysisReport interface. * * Generally, Transcend input could be loosely broke down into three categories: * - Internally derived data. CFA, DFA, and other analyzers automatically supply the reasoner with * useful insights about source codes, the structure and algorithms of a program. * - User provided custom data. Analyzers extract manual developer-provided annotations from the source codes. * - External data. External files supply reasoner with third-party data * which relates to different aspects of a program possibly produced by external analyzers. * * After Transcend has gathered data from all providers and the logic program is fully constructed, * it runs the external logic reasoner to receive back the solution. * * The solution from the external logic reasoner is accessible via *queries*. * Classes which want to request data from Transcend should implement the \ref IQuery interface. See \ref IQuery descendants to find out currently available queries. * * \section tl_adapt Adaptability * Decorators are used to extend %TranscendLayer functionality. The default bundle defined by \ref DefaultTranscendLayerImpl. * * \sa See xreate::dfa::DFAPass, xreate::cfa::CFAPass, xreate::IQuery, xreate::IAnalysisReport */ diff --git a/cpp/src/transcendlayer.h b/cpp/src/transcendlayer.h index 6ad56de..495ceb5 100644 --- a/cpp/src/transcendlayer.h +++ b/cpp/src/transcendlayer.h @@ -1,284 +1,284 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * Author: pgess * File: transcendlayer.h */ #ifndef transcendLAYER_H #define transcendLAYER_H #include "ast.h" #include "contextrule.h" -#include +#include #include #include #include #include #include #include #include #include #include namespace xreate { typedef unsigned int ScopePacked; const ScopePacked SCOPE_ABSTRACT_GLOBAL = std::numeric_limits::max(); struct SymbolPacked { SymbolPacked(){} SymbolPacked(ScopedSymbol i, ScopePacked s): identifier(i.id), version(i.version), scope(s){} SymbolPacked(VNameId symbolId, versions::VariableVersion symbolVersion, ScopePacked symbolScope) : identifier(symbolId), version(symbolVersion), scope(symbolScope){} VNameId identifier; versions::VariableVersion version; ScopePacked scope; }; bool operator==(const SymbolPacked& s1, const SymbolPacked& s2); bool operator<(const SymbolPacked& s1, const SymbolPacked& s2); struct SymbolAnonymous { unsigned int id; bool flagIsUsed = false; }; bool operator==(const SymbolAnonymous& s1, const SymbolAnonymous& s2); typedef boost::variant SymbolNode; //DEBT use SymbolGeneralized communicating with Analysis rather than Symbol typedef boost::variant SymbolGeneralized; template<> struct AttachmentsId{ static unsigned int getId(const SymbolGeneralized& symbol); }; } namespace std { template<> struct hash { std::size_t operator()(xreate::SymbolNode const& s) const noexcept; }; template<> struct hash { std::size_t operator()(xreate::SymbolGeneralized const& s) const noexcept; }; } namespace xreate { enum class DFGConnection { STRONG, WEAK, PROTOTYPE }; /** \brief Supplies \ref TranscendLayer with results of an analysis*/ class IAnalysisReport { public: /** \brief Composes a logic program to represent the analysis data in ASP format, and appends to a stream*/ virtual void print(std::ostringstream& output) const = 0; virtual ~IAnalysisReport(){}; }; /** \brief Transcend solutions querying interface */ class IQuery { public: virtual void init(TranscendLayer* transcend) = 0; virtual ~IQuery() {} }; enum class QueryId { ContainersQuery, PolymorphQuery, LatexQuery }; namespace dfa{ class DFAGraph; } namespace cfa { class CFAGraph; } -typedef std::multimap StaticModel; +typedef std::multimap StaticModel; typedef StaticModel::const_iterator StaticModelIterator; class TranscendLayer { friend class ContextRule; /**\name Data Providers Management */ ///@{ public: void registerReport(IAnalysisReport* report); void printReports(); void deleteReports(); /** \brief Appends arbitrary string to a logic program */ void addRawScript(std::string&& script); private: std::list __reports; /** Includes external text files to a *logic program* */ void involveImports(); ///@} /**\name Queries Management */ ///@{ public: /** \brief Registers a query. See xreate::IQuery */ IQuery* registerQuery(IQuery* query, const QueryId& id); /** \brief Returns a particular query. See xreate::IQuery */ IQuery* getQuery(const QueryId& id); template - static std::tuple parse(const Gringo::Symbol& atom); + static std::tuple parse(const Clingo::Symbol& atom); StaticModel query(const std::string& atom) const; size_t getScopesCount() const; SymbolPacked pack(const Symbol& symbol, std::string hintSymbolName = ""); ScopePacked pack(const CodeScope * const scope); Symbol unpack(const SymbolPacked& symbol) const; SymbolNode pack(const SymbolGeneralized& symbol, const std::string& hintSymbolName); SymbolGeneralized unpack(const SymbolNode& symbol) const; std::string getHintForPackedSymbol(const SymbolPacked& symbol); ///@} private: std::map __queries; std::map __indexSymbolNameHints; std::unordered_map __indexScopes; std::vector __registryScopes; /**\name Diagnostic */ ///@{ //TODO diagnostic move over to separate provider/query public: /** \brief Registers diagnostic rules */ void addRuleWarning(const RuleWarning &rule); /** \brief Registers diagnostic messages */ unsigned int registerWarning(std::string &&message); private: std::map __warnings; void printWarnings(std::ostream& out); ///@} ///@{ public: TranscendLayer(); /** \brief Executes reasoning */ void run(); ///@} AST *ast; protected: - virtual bool processSolution(Gringo::Model const &model); + virtual bool processSolution(Clingo::Model const &model); private: StaticModel __model; std::ostringstream __partTags; std::ostringstream __partGeneral; }; template struct ParseImplAtom { - static typ get(const Gringo::Symbol& atom) { - return atom.num(); + static typ get(const Clingo::Symbol& atom) { + return atom.number(); } }; template<> struct ParseImplAtom { - static int get(const Gringo::Symbol& atom); + static int get(const Clingo::Symbol& atom); }; template<> struct ParseImplAtom { - static std::string get(const Gringo::Symbol& atom); + static std::string get(const Clingo::Symbol& atom); }; template<> struct ParseImplAtom { - static SymbolPacked get(const Gringo::Symbol& atom); + static SymbolPacked get(const Clingo::Symbol& atom); }; template<> struct ParseImplAtom { - static SymbolNode get(const Gringo::Symbol& atom); + static SymbolNode get(const Clingo::Symbol& atom); }; template<> -struct ParseImplAtom { - static Gringo::Symbol get(const Gringo::Symbol& atom); +struct ParseImplAtom { + static Clingo::Symbol get(const Clingo::Symbol& atom); }; template struct ParseImplAtom>{ static std::list - get(const Gringo::Symbol& atom){ - bool flagIsList = (atom.type() == Gringo::SymbolType::Fun) && atom.name().empty(); + get(const Clingo::Symbol& atom){ + bool flagIsList = (atom.type() == Clingo::SymbolType::Function) && std::string(atom.name()).empty(); std::list result; if(!flagIsList) { //treat as degenerate case: list with a single element result.push_back(ParseImplAtom::get(atom)); return result; } - for (const Gringo::Symbol& arg: atom.args()) { + for (const Clingo::Symbol& arg: atom.arguments()) { result.push_back(ParseImplAtom::get(arg)); } return result; } }; template<> struct ParseImplAtom { - static Expression get(const Gringo::Symbol& atom); + static Expression get(const Clingo::Symbol& atom); }; template struct Parse_Impl { - static void parse(Tuple& tup, Gringo::SymSpan::iterator arg) { + static void parse(Tuple& tup, Clingo::SymbolSpan::IteratorType arg) { const size_t tupleSize = std::tuple_size::value; typedef typename std::tuple_element < tupleSize - index, Tuple>::type ElType; ElType& el = std::get < tupleSize - index > (tup); - Gringo::Symbol atom = *arg; + Clingo::Symbol atom = *arg; el = ParseImplAtom::get(atom); Parse_Impl ::parse(tup, ++arg); } }; template struct Parse_Impl { - static void parse(Tuple& tup, Gringo::SymSpan::iterator arg) { + static void parse(Tuple& tup, Clingo::SymbolSpan::IteratorType arg) { } }; template std::tuple -TranscendLayer::parse(const Gringo::Symbol& atom) { +TranscendLayer::parse(const Clingo::Symbol& atom) { typedef std::tuple < Types...> Tuple; Tuple tup; - Parse_Impl::value>::parse(tup, atom.args().first); + Parse_Impl::value>::parse(tup, atom.arguments().begin()); return tup; } } //end of xreate namespace #endif diff --git a/cpp/tests/CMakeLists.txt b/cpp/tests/CMakeLists.txt index 2890e4b..618a5eb 100644 --- a/cpp/tests/CMakeLists.txt +++ b/cpp/tests/CMakeLists.txt @@ -1,60 +1,64 @@ 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}) +set (CLINGO_LIBS_DIR ${CLINGO_PATH}/build/bin ${CLINGO_PATH}/build/lib) +message("CLINGO_LIBS_DIR: " ${CLINGO_LIBS_DIR}) +link_directories(${CLINGO_LIBS_DIR}) #aux_source_directory(. TEST_FILES) set(TEST_FILES +# vendors/clang.cpp + vendors/clingo.cpp + vendors/llvm.cpp introduction.cpp unit-test-example.cpp transcend-ast.cpp supplemental/docutils latetranscend.cpp cfa.cpp latex.cpp polymorph.cpp transcend.cpp virtualization.cpp exploitation.cpp effects-communication.cpp association.cpp main.cpp modules.cpp attachments.cpp ast.cpp dfa.cpp compilation.cpp ExpressionSerializer.cpp externc.cpp types.cpp #vendorsAPI/clangAPI.cpp #vendorsAPI/xml2.cpp #vendorsAPI/json.cpp containers.cpp interpretation.cpp loops.cpp #supplemental/versions-algorithm-data_dependency.cpp effects-versions.cpp ) add_executable(${PROJECT_NAME} ${TEST_FILES}) target_link_libraries(${PROJECT_NAME} xreate ${GTEST_LIBRARIES} pthread xml2 gcov) add_custom_target (coverage COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/src/code-coverage.sh WORKING_DIRECTORY ${CMAKE_BINARY_DIR}) diff --git a/cpp/tests/latex.cpp b/cpp/tests/latex.cpp index be55f08..c684754 100644 --- a/cpp/tests/latex.cpp +++ b/cpp/tests/latex.cpp @@ -1,358 +1,357 @@ /* Any copyright is dedicated to the Public Domain. * http://creativecommons.org/publicdomain/zero/1.0/ * * Author: pgess * Created on June 25, 2018, 5:42 PM * * \file latex.cpp * \brief Testing of latex */ #include "xreatemanager.h" #include "pass/compilepass.h" #include "transcendlayer.h" #include "query/latex.h" #include "compilation/latex.h" #include "aux/xreatemanager-decorators.h" #include "compilation/scopedecorators.h" #include "llvmlayer.h" #include "supplemental/docutils.h" #include "supplemental/defines.h" #include #include using namespace xreate::latex; using namespace xreate::latereasoning; using namespace xreate::compilation; using namespace xreate; using namespace std; TEST(Latex, Script_NestedScopePropagation_1) { std::string program = R"CODE( import raw("scripts/cfa/context.lp"). fn = function:: int; entry { context:: test1. if(1==11)::int {2} else {3} } )CODE"; std::unique_ptr man(details::tier1::XreateManager::prepare(move(program))); CodeScope* blockTrue = man->root->findFunction("fn")->getEntryScope()->getBody().blocks.front(); auto blockTrueP = man->transcend->pack(blockTrue); boost::format formatAlias("alias(%1%, %2%)."); man->transcend->addRawScript((formatAlias % blockTrueP % "block1").str()); man->transcend->addRawScript( R"SCRIPT( success1:- bind_scope(Block1, test1, strong); alias(Block1, block1). )SCRIPT"); man->analyse(); ASSERT_EQ(1, man->transcend->query("success1").size()); } TEST(Latex, Script_DemAndDecision_1) { std::string program = R"CODE( import raw("scripts/cfa/context.lp"). a = function:: int { context:: forC(a). c() } b = function:: int { context:: forC(b). c() } c = function:: int {0} main = function:: int; entry { a() + b() } )CODE"; std::unique_ptr man(details::tier1::XreateManager::prepare(move(program))); CodeScope* blockC = man->root->findFunction("c")->getEntryScope(); auto blockCP = man->transcend->pack(blockC); boost::format formatAlias("alias(%1%, %2%)."); man->transcend->addRawScript((formatAlias % blockCP % "blockC").str()); man->transcend->addRawScript( R"SCRIPT( latex_scope_demand(BlockC, forC):- alias(BlockC, blockC). latex_registered_subjects(forC, Variant):- bind_scope(_, Variant, strong); Variant = forC(_). )SCRIPT"); man->analyse(); ASSERT_EQ(1, man->transcend->query("latex_fn_demand").size()); ASSERT_EQ(2, man->transcend->query("latex_decision").size()); } TEST(Latex, LatexQuery_getFnDemand_1){ std::string program = R"CODE( import raw("scripts/cfa/context.lp"). main = function:: int; entry { context:: alias(blockMain). 0 } )CODE"; std::unique_ptr man(details::tier1::XreateManager::prepare(move(program))); man->transcend->addRawScript( R"SCRIPT( latex_scope_demand(BlockC, forC):- bind_scope(BlockC, alias(blockMain), strong). latex_registered_subjects(forC, decisionSome). )SCRIPT"); LatexQuery* query = new LatexQuery(); man->transcend->registerQuery(query, QueryId::LatexQuery); man->analyse(); Demand demand = query->getFnDemand("main"); ASSERT_EQ(1, demand.size()); ASSERT_STREQ("forC", demand.front().c_str()); } TEST(Latex, LatexQuery_getDecision_static_1){ std::string program = R"CODE( import raw("scripts/cfa/context.lp"). a = function:: int {context::decisionSome. c()} b = function:: int {c()} c = function:: int {context:: alias(blockC). 0} )CODE"; std::unique_ptr man(details::tier1::XreateManager::prepare(move(program))); man->transcend->addRawScript( R"SCRIPT( latex_scope_demand(BlockC, forC):- bind_scope(BlockC, alias(blockC), strong). latex_registered_subjects(forC, decisionSome). )SCRIPT"); LatexQuery* query = new LatexQuery(); man->transcend->registerQuery(query, QueryId::LatexQuery); man->analyse(); LateAnnotation decisionLA = query->getDecision("forC", man->root->findFunction("a")->getEntryScope()); auto decisionGS = decisionLA.select({}, man->root, man->transcend); ASSERT_TRUE(decisionGS); - decisionGS->print(cout); - cout << endl; - auto decisionTuple = man->transcend->parse(*decisionGS); + cout << decisionGS.get() << endl; + auto decisionTuple = man->transcend->parse(*decisionGS); string decision = get<2>(decisionTuple); ASSERT_STREQ("decisionSome", decision.c_str()); } TEST(Latex, Compilation_1) { std::string program = R"CODE( a = function:: int {0} main = function:: int; entry { a() } )CODE"; string script = R"SCRIPT( latex_fn_demand(%1%, subject1). latex_decision(%2%, subject1, 5). latex_registered_subjects(subject1, 1). latex_registered_subjects(subject1, 5). )SCRIPT"; typedef LatexBruteFunctionDecorator FnImpl; typedef LatexBruteScopeDecorator> ScopeImpl; std::unique_ptr man(details::tier1::XreateManager::prepare(move(program))); ScopePacked scopeMainP = man->transcend->pack(man->root->findFunction("main")->getEntryScope()); boost::format format(script); man->transcend->addRawScript((format % "a" % scopeMainP).str()); man->transcend->registerQuery(new LatexQuery(), QueryId::LatexQuery); man->analyse(); std::unique_ptr compiler(new compilation::CompilePassCustomDecorators(man.get())); compiler->run(); man->llvm->initJit(); int(*fnMain)() = (int(*)())man->llvm->getFunctionPointer(compiler->getEntryFunction()); ASSERT_EQ(0, fnMain()); } // //TEST(Latex, Full1) { // std::string program = // R"CODE( // import raw("scripts/cfa/context.lp"). // // a = function:: int // { // context:: forC(a). // c() // } // // b = function:: int // { // context:: forC(b). // c() // } // // c = function:: int {0} // // main = function:: int; entry // { // a() + b() // } // )CODE"; // // string script = // R"SCRIPT( // alias(%1%, scopeC). // latex_scope_demand(ScopeC, forC) :- alias(ScopeC, scopeC). // latex_registered_subjects(forC, forC(a)). // latex_registered_subjects(forC, forC(b)). // )SCRIPT"; // // typedef LatexBruteFunctionDecorator FnImpl; // typedef LatexBruteScopeDecorator> ScopeImpl; // // std::unique_ptr man(details::tier1::XreateManager::prepare(move(program))); // ScopePacked scopeMainP = man->transcend->pack(man->root->findFunction("main")->getEntryScope()); // auto scopeCP = man->transcend->pack(man->root->findFunction("c")->getEntryScope()); // boost::format format(script); // man->transcend->addRawScript((format %scopeCP).str()); // man->transcend->registerQuery(new LatexQuery(), QueryId::LatexQuery); // man->analyse(); // // std::unique_ptr compiler(new compilation::CompilePassCustomDecorators(man.get())); // compiler->run(); // man->llvm->print(); //} // TEST(Latex, Compilation_TransitFn1){ std::string program = R"CODE( import raw("scripts/cfa/context.lp"). branchA = function:: int { context:: sink_a. fnTransit() } branchB = function:: int { context:: sink_b. fnTransit() } fnSink = function:: int {0} fnTransit = function:: int {fnSink()} main = function:: int; entry { branchA() + branchB() } )CODE"; string script = R"SCRIPT( alias(scopeSink, %1%). latex_scope_demand(ScopeSink, sink):- alias(scopeSink, ScopeSink). latex_registered_subjects(sink, sink_a). latex_registered_subjects(sink, sink_b). )SCRIPT"; typedef LatexBruteFunctionDecorator FnImpl; typedef LatexBruteScopeDecorator> ScopeImpl; std::unique_ptr man(details::tier1::XreateManager::prepare(move(program))); CodeScope* scopeSink = man->root->findFunction("fnSink")->getEntryScope(); auto scopeSinkP = man->transcend->pack(scopeSink); ScopedSymbol argLatexSS{1, -1}; Symbol argLatexS{argLatexSS, scopeSink}; man->transcend->pack(argLatexS); boost::format format(script); man->transcend->addRawScript((format %scopeSinkP).str()); man->transcend->registerQuery(new LatexQuery(), QueryId::LatexQuery); man->analyse(); std::unique_ptr compiler(new compilation::CompilePassCustomDecorators(man.get())); compiler->run(); man->llvm->print(); man->llvm->initJit(); int(*fnMain)() = (int(*)()) man->llvm->getFunctionPointer(compiler->getEntryFunction()); int valueActual = fnMain(); ASSERT_EQ(0, valueActual); } TEST(Latex, Doc_Examples1){ std::string program = getDocumentationExampleById("documentation/Concepts/context.xml", "Examples_1"); std::unique_ptr man(details::tier1::XreateManager::prepare(move(program))); } TEST(Latex, Doc_Examples2){ std::string program = getDocumentationExampleById("documentation/Concepts/context.xml", "Examples_2"); std::unique_ptr man(details::tier1::XreateManager::prepare(move(program))); } TEST(Latex, Doc_ContextPropagation1){ std::string program =getDocumentationExampleById("documentation/Concepts/context.xml", "ContextPropagation1"); std::unique_ptr man(details::tier1::XreateManager::prepare(move(program))); } TEST(Latex, Doc_ContextPropagation2){ std::string program = getDocumentationExampleById("documentation/Concepts/context.xml", "ContextPropagation2"); std::unique_ptr man(details::tier1::XreateManager::prepare(move(program))); } TEST(Latex, Doc_Latex1){ std::string program = getDocumentationExampleById("documentation/Concepts/context.xml", "Latex1"); string script = R"SCRIPT( latef(compute). latex_scope_demand(Scope, f_guarded(F)):- cfa_call(Scope, F); latef(F). latex_registered_subjects(f_guarded(F), Guard):- cfa_function_specializations(F, Guard); latef(F). late(TargetS, LatexParam, Guard, dfa_callguard(TargetS, Guard)):- dfa_callfn(TargetS, FnGuarded); latef(FnGuarded); latex_symbol(FnCallerBody, f_guarded(FnGuarded), LatexParam); TargetS=s(_,_, TargetScope); scope_fnbody(TargetScope, FnCallerBody); cfa_function_specializations(FnGuarded, Guard). )SCRIPT"; auto man(XreateManager::prepare(move(program))); man->transcend->addRawScript(move(script)); Fn3args fn = (Fn3args) man->run(); int resultActual = fn(1, 4, 3); ASSERT_EQ(7, resultActual); resultActual = fn(0, 4, 3); ASSERT_EQ(1, resultActual); -} \ No newline at end of file +} diff --git a/cpp/tests/polymorph.cpp b/cpp/tests/polymorph.cpp index 5a930bc..aa602a5 100644 --- a/cpp/tests/polymorph.cpp +++ b/cpp/tests/polymorph.cpp @@ -1,160 +1,159 @@ /* Any copyright is dedicated to the Public Domain. * http://creativecommons.org/publicdomain/zero/1.0/ * * polymorph.cpp * * Author: pgess * Created on October 11, 2017, 8:37 PM */ #include "xreatemanager.h" #include "ast.h" #include "transcendlayer.h" #include "aux/latereasoning.h" #include #include "gtest/gtest.h" #include "query/polymorph.h" #include "supplemental/docutils.h" using namespace xreate; using namespace xreate::latereasoning; using namespace xreate::polymorph; using namespace std; TEST(Polymorphs, ast1) { xreate::XreateManager* man = xreate::XreateManager::prepare( R"CODE( guard:: a { test = function:: int {0} } guard:: b { test = function:: int {1} } main = function:: int; entry { test() } )CODE"); const std::list& specs = man->root->getFunctionSpecializations("test"); ASSERT_EQ(2, specs.size()); auto itSpecs = specs.begin(); ASSERT_EQ("a", (*itSpecs)->guard.getValueString()); itSpecs++; ASSERT_EQ("b", (*itSpecs)->guard.getValueString()); } TEST(Polymorphs, PolymorphQuery_Static_1) { xreate::details::tier1::XreateManager* man = xreate::details::tier1::XreateManager::prepare( R"CODE( import raw("scripts/dfa/polymorphism.lp"). guard:: a { test = function:: int {0} } guard:: b { test = function:: int {1} } main = function:: int; entry { test()::int; callguard(b); dfa_polym(ret)} )CODE"); man->analyse(); PolymorphQuery* query = dynamic_cast (man->transcend->getQuery(QueryId::PolymorphQuery)); const Expression& bodyE = man->root->findFunction("main")->getEntryScope()->getBody(); LateAnnotation decisionLA = query->get(bodyE); ASSERT_EQ(1, decisionLA.guardedContent.size()); auto decisionOptSymb = decisionLA.select({}, man->root, man->transcend); ASSERT_TRUE(decisionOptSymb); - - decisionOptSymb->print(cout); - cout << endl; + + cout << decisionOptSymb.get() << endl; string guard = query->getValue(*decisionOptSymb).getValueString(); ASSERT_STREQ("b", guard.c_str()); } TEST(Polymorphs, PolymorphQuery_Late_1){ xreate::details::tier1::XreateManager* man = xreate::details::tier1::XreateManager::prepare( R"CODE( Late = type variant{a, b}. main = function:: int; entry{key= a():: Late; test. key::int} )CODE"); man->transcend->addRawScript( R"RULE( late(S, S, a, dfa_callguard(S, a)):- bind(S, test). late(S, S, b, dfa_callguard(S, b)):- bind(S, test). )RULE"); man->analyse(); PolymorphQuery* query = dynamic_cast (man->transcend->getQuery(QueryId::PolymorphQuery)); CodeScope* scopeMain = man->root->findFunction("main")->getEntryScope(); Symbol keyS = Symbol{scopeMain->getSymbol("key"), scopeMain}; Expression keyE = scopeMain->getDefinition(keyS); latereasoning::LateAnnotation answerLA = query->get(keyE); Expression valueB(Operator::VARIANT, {}); valueB.setValueDouble(1); auto answerRaw = answerLA.select({valueB}, man->root, man->transcend); ASSERT_TRUE(answerRaw); Expression answerE = query->getValue(*answerRaw); ASSERT_STREQ("b", answerE.getValueString().c_str()); } TEST(Polymorphs, PSCU_1){ auto man = details::tier1::XreateManager::prepare(R"Code( Dom = type variant {guard1, guard2}. guard:: guard1 { compute = function :: int {0} } guard:: guard2 { compute = function :: int {1} } test = function:: int; entry { xLate = guard2():: Dom. y1= switch late (xLate:: Dom; alias(xLate)):: int { compute():: int; guardkey(xLate) }. y1 } )Code"); man->transcend->addRawScript(R"RAW( dom(guard1; guard2). late(Target, Key, Variant, dfa_callguard(Target, Variant)):- bind(Target, guardkey(Alias)); bind(Key, alias(Alias)); dom(Variant). )RAW"); man->analyse(); int (*program)() = (int (*)())man->run(); int result = program(); ASSERT_EQ(1, result); } TEST(Polymorphs, Doc_FnLvlPoly_1){ string example = getDocumentationExampleById("documentation/Concepts/polymorphism.xml", "FnLvlPoly_1"); auto man = XreateManager::prepare(move(example)); ASSERT_TRUE(true); } TEST(Polymorphs, Doc_LatePoly_1){ string example = getDocumentationExampleById("documentation/Concepts/polymorphism.xml", "LatePoly_1"); auto man = XreateManager::prepare(move(example)); ASSERT_TRUE(true); } \ No newline at end of file diff --git a/cpp/tests/transcend-ast.cpp b/cpp/tests/transcend-ast.cpp index c8c6044..4fe628f 100644 --- a/cpp/tests/transcend-ast.cpp +++ b/cpp/tests/transcend-ast.cpp @@ -1,77 +1,77 @@ /* Any copyright is dedicated to the Public Domain. * http://creativecommons.org/publicdomain/zero/1.0/ * * AST-Transcend Correspondence Tests * * Created on: Dec 2, 2018 * Author: pgess */ #include #include "xreatemanager.h" #include "pass/dfapass.h" #include "supplemental/docutils.h" #include #include "gtest/gtest.h" using namespace xreate; using namespace std; struct TestRec { string refExample; string refOutput; PassId pass; }; std::list tests = { {"ExprAnn_1", "Output_ExprAnn_1", PassId::DFAPass}, {"CodeBlock_1", "Output_CodeBlock_1", PassId::CFAPass}, {"CodeBlockAnns_1", "Output_CodeBlockAnns_1", PassId::CFAPass}, {"CodeBlockBinds_1", "Output_CodeBlockBinds_1", PassId::CFAPass}, {"CodeBlockParents_1", "Output_CodeBlockParents_1",PassId::CFAPass}, {"Fn_1", "Output_Fn_1", PassId::CFAPass}, {"FnAnns_1", "Output_FnAnns_1", PassId::CFAPass}, {"FnSpecs_1", "Output_FnSpecs_1", PassId::CFAPass}, {"FnEntry_1", "Output_FnEntry_1", PassId::CFAPass}, {"FnResult_1", "Output_FnResult_1", PassId::CFAPass}, {"OpInvoc_1", "Output_OpInvoc_1", (PassId) 1000}, {"OpLoops_1", "Output_OpLoops_1", PassId::DFAPass} }; TEST(ASTCorrespondence, Doc_BasicTests) { for(auto test: tests) { string program = getDocumentationExampleById("documentation/Transcend/ast-api.xml", test.refExample); string outputExpected = getDocumentationExampleById("documentation/Transcend/ast-api.xml", test.refOutput); std::unique_ptr man(details::tier2::XreateManager::prepare(move(program))); switch(test.pass) { case PassId::CFAPass: man->registerPass(new cfa::CFAPass(man.get()), test.pass); break; case PassId::DFAPass: man->registerPass(new dfa::DFAPass(man.get()), test.pass); break; default: man->registerPass(new dfa::DFAPass(man.get()), PassId::DFAPass); man->registerPass(new cfa::CFAPass(man.get()), PassId::CFAPass); break; } man->registerPass(new dfa::DFAPass(man.get()), test.pass); man->executePasses(); cout << "Test: " << test.refExample << endl; testing::internal::CaptureStdout(); man->analyse(); std::string outputActual = testing::internal::GetCapturedStdout(); - //cout << outputActual << endl; + cout << outputActual << endl; //check every line independently if outputActual is multi-line string std::vector lines; boost::split(lines, outputExpected, [](char c){return c == '\n';}); for(auto line: lines) { ASSERT_NE(std::string::npos, outputActual.find(line)); } } } diff --git a/cpp/tests/transcend.cpp b/cpp/tests/transcend.cpp index 022b105..176573b 100644 --- a/cpp/tests/transcend.cpp +++ b/cpp/tests/transcend.cpp @@ -1,92 +1,92 @@ /* Any copyright is dedicated to the Public Domain. * http://creativecommons.org/publicdomain/zero/1.0/ * * Author: pgess * Created on June 7, 2018, 3:35 PM * * \file transcend.cpp * \brief Transcend's tests */ #include "xreatemanager.h" #include "transcendlayer.h" #include "supplemental/docutils.h" #include using namespace xreate; using namespace std; TEST(Transcend, Parse1) { std::string script = R"Code( )Code"; std::unique_ptr man(details::tier1::XreateManager::prepare(std::move(script))); std::string scriptTranscend = R"Code( test1((1)). test2((1, 2)). )Code"; man->transcend->addRawScript(move(scriptTranscend)); man->analyse(); StaticModel solution = man->transcend->query("test1"); - Gringo::Symbol symbTest1 = solution.begin()->second; + Clingo::Symbol symbTest1 = solution.begin()->second; auto answer1 = man->transcend->parse>(symbTest1); ASSERT_EQ(1, get<0>(answer1).size()); solution = man->transcend->query("test2"); - Gringo::Symbol symbTest2 = solution.begin()->second; + Clingo::Symbol symbTest2 = solution.begin()->second; auto answer2 = get<0>(man->transcend->parse>(symbTest2)); ASSERT_EQ(2, answer2.size()); } TEST(Transcend, Doc_Expressions1) { string code = getDocumentationExampleById("documentation/Transcend/transcend.xml", "Expressions1"); XreateManager* man = XreateManager::prepare(move(code)); man->run(); delete man; ASSERT_TRUE(true); } TEST(Transcend, Doc_SlaveTypes1){ string code = getDocumentationExampleById("documentation/Transcend/transcend.xml", "Codeblocks1"); XreateManager::prepare(move(code)); ASSERT_TRUE(true); } TEST(Transcend, Doc_Codeblocks1) { string code = getDocumentationExampleById("documentation/Transcend/transcend.xml", "Codeblocks1"); XreateManager::prepare(move(code)); ASSERT_TRUE(true); } TEST(Transcend, Doc_Diagnostics1) { string code = getDocumentationExampleById("documentation/Transcend/transcend.xml", "Diagnostics1"); string scriptTranscend = getDocumentationExampleById("documentation/Transcend/transcend.xml", "Diagnostics1_Rules"); string scriptSupport = R"Code( scope_func_dict(S, Fn):- cfa_parent(S, function(Fn)). scope_func_dict(S1, Fn):- cfa_parent(S1, scope(S2)); scope_func_dict(S2, Fn). )Code"; auto man = XreateManager::prepare(move(code)); man->transcend->addRawScript(move(scriptTranscend)); man->transcend->addRawScript(move(scriptSupport)); testing::internal::CaptureStdout(); man->run(); delete man; std::string outputActual = testing::internal::GetCapturedStdout(); string outputExpected = "warning(\"Visibility violation\",test,sum)"; ASSERT_NE(std::string::npos, outputActual.find(outputExpected)); -} \ No newline at end of file +} diff --git a/cpp/tests/vendors/llvm.cpp b/cpp/tests/vendors/llvm.cpp new file mode 100644 index 0000000..0bcfc74 --- /dev/null +++ b/cpp/tests/vendors/llvm.cpp @@ -0,0 +1,47 @@ +/* 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: llvm.cpp + * Author: pgess + * + * Created on 05/09/2020 + */ + +#include +#include +#include +#include + +#include + +using namespace llvm; +typedef int (*FnNoArgs)(); + +TEST(Vendors, LLVM_Ver9_0_1_Basic1){ + llvm::LLVMContext context; + std::unique_ptr module(new Module("test", context)); + + InitializeNativeTarget(); + InitializeNativeTargetAsmPrinter(); + + FunctionType* fnMainT = FunctionType::get(Type::getInt32Ty(context), {}, false); + Function* fnMain = Function::Create(fnMainT, Function::ExternalLinkage, "main", module.get()); + + BasicBlock *blockEntry = BasicBlock::Create(context, "entry", fnMain); + ReturnInst::Create( + context, + ConstantInt::get(Type::getInt32Ty(context), 0), + blockEntry); + + module->print(llvm::outs(), nullptr); + + std::string errStr; + ExecutionEngine *engine = + EngineBuilder(std::move(module)) + .setErrorStr(&errStr) + .create(); + + FnNoArgs fnMainRaw = (FnNoArgs) engine->getFunctionAddress("main"); + ASSERT_EQ(0, fnMainRaw()); +} \ No newline at end of file diff --git a/documentation/Transcend/ast-api.xml b/documentation/Transcend/ast-api.xml index c757ee2..f76860f 100644 --- a/documentation/Transcend/ast-api.xml +++ b/documentation/Transcend/ast-api.xml @@ -1,495 +1,495 @@ AST API In order to reason about program, code model is translated into form suited for processing by Transcend. Translation details are described below.
Expression Annotations: 'bind' SYNTAX: **bind**(//symbol-ref//, //annotation//) symbol-ref reference to the expression or identifier annotation expression's annotation Declares expression's annotations. Example: name="tests/transcend-ast.cpp: ASTCorrespondence.Doc_BasicTests" test = function:: int { x = 5:: int; expected(even_number). x } gets translated into: - bind(s(1,-2,0),expected(even_number)) + bind(s(1,-2,0),expected(even_number))
Code Block: 'scope' SYNTAX: **scope**(//scope-ref//) scope-ref reference to the code block Declares code block under its unique reference identifier. Example: name="tests/transcend-ast.cpp: ASTCorrespondence.Doc_BasicTests" test = function:: float { x = 3:: float. y = 8:: float. x + y } Translation result: scope(0)
Code Block Annotations: 'bind_scope' Pending syntax changes SYNTAX: **bind_scope**(//scope-ref//, //annotation//, strong) (1) **bind_scope**(//scope-ref//, //annotation//, weak(..)) (2) scope-ref child block's reference annotation code block's annotation Declares code block's annotations called context. There are two forms for different context' type: strong context known at compile time weak possible context, can't be decided for sure at compile time Example: name="tests/transcend-ast.cpp: ASTCorrespondence.Doc_BasicTests" test = function:: float { context:: arithmetic(fast). x = 3:: float. y = 8:: float. x + y } Translation's result: bind_scope(0,arithmetic(fast),strong)
Code Block Bindings: 'ast_scope_binding' SYNTAX: **ast_scope_binding**(//scope-ref//, //binding-id//, //binding-alias//) scope-ref code block's reference binding-id number of code block's binding binding-alias name of a binding Code blocks have zero or more bindings, i.e. Identifiers that have special meaning within the block. Predicate declares such code block's bindings. Bindings organized into ordered list. Order is conveyed by specifying binding-id for each binding-alias. Example: name="tests/transcend-ast.cpp: ASTCorrespondence.Doc_BasicTests" test = function:: int { loop ( 0 -> acc ):: int { if(acc > 10):: int {acc:: int; final} else {acc + 1} } } Translation result: ast_scope_binding(1,0,"acc")
Code Block Parents: 'cfa_parent' SYNTAX: **cfa_parent**(//scope-ref//, **scope**(//scope-parent-ref//)) scope-ref child block's reference scope-parent-ref parent block's reference Represents nested code blocks structure in terms of child-parent relation. Example: name="tests/transcend-ast.cpp: ASTCorrespondence.Doc_BasicTests" test = function:: int { x = 19:: int. if (x>5):: int {x + 1} else {x - 1} } Translation's result: cfa_parent(1, scope(0)). cfa_parent(2, scope(0)).
Function: 'function' SYNTAX: **function**(//fn-name//) fn-name function name Declares function identified by its name. Example: name="tests/transcend-ast.cpp: ASTCorrespondence.Doc_BasicTests" test = function:: int {0} Translation's result: function(test)
Function's Annotations: 'bind_func' SYNTAX: **bind_func**(//fn-name//, //annotation//) fn-name function's name Declares function's annotations. Example: name="tests/transcend-ast.cpp: ASTCorrespondence.Doc_BasicTests" test = function:: int; status(obsolete) {0} Translation's result: bind_func(test,status(obsolete))
Function's Specialization: 'cfa_function_specializations' SYNTAX: **cfa_function_specializations**(//fn-name//, //guard//) fn-name name of function guard specialization guard There is a possibility to have several functions with the same name called specializations. Each specialization is uniquely determined by annotation of special kind called guard. Example: name="tests/transcend-ast.cpp: ASTCorrespondence.Doc_BasicTests" guard:: arch(amd64) { test = function:: i64 {0} } Translation's result: cfa_function_specializations(test,arch(amd64)) See also specializations syntax
Function's Entry: 'cfa_parent' SYNTAX: **cfa_parent**(//scope-entry-ref//, functon(//fn-name//)) scope-entry-ref function's entry code block reference fn-name function's name Each function has a single entry code block and is declared in terms of child-parent relation between entry block(which is top-level in blocks hierarchy of the given function) and the function itself. Example: name="tests/transcend-ast.cpp: ASTCorrespondence.Doc_BasicTests" test = function:: int {0} Translation's result: cfa_parent(0,function(test))
Function's Result: 'dfa_fnret' SYNTAX: **dfa_fnret**(//fn-name//, //symbol-ret-ref//) symbol-ret-ref reference to a function's return expression Specifies which expression is used to compute function's return value. Example: name="tests/transcend-ast.cpp: ASTCorrespondence.Doc_BasicTests" test = function:: int {0} Translation's result: dfa_fnret(test,s(0,-2,0))
Operations. Invocation: 'cfa_call', 'dfa_callfn', 'dfa_callargs' SYNTAX: **cfa_call**(//scope-caller-ref//, //fn-callee-name//) (1) **dfa_callfn**(//symbol-ref//, //fn-callee-name//) (2) **dfa_callargs**(//symbol-ref//, //arg-formal-name//, //arg-actual-ref//) (3) **weak**(**dfa_callargs**(//symbol-ref//, //arg-formal-name//, //arg-actual-ref//)) (4) scope-caller-ref caller's code block's reference fn-callee-name callee function name symbol-ref invocation operation reference arg-formal-name function's formal argument arg-actual-ref actual argument reference Each function invocation is transformed into several transcend facts as explained below: (1) cfa_call Specifies caller's code block and callee function name (2) dfa_callfn Declares unique reference to a particular invocation site.The reference used by other facts to supply additional information (3) dfa_callargs Declares assignment relations between actual arguments and formal arguments (4) weak(dfa_callargs) The same as form (3). Weak relation used in cases when there is no enough information at compile time. One such case is when several function specializations exist and it's impossible to say which exactly specialization is called Example: name="tests/transcend-ast.cpp: ASTCorrespondence.Doc_BasicTests" inc = function (x::int):: int { x + 1 } main = function:: int { arg = 10:: int. inc(arg) } After translation following transcend facts are present: cfa_call(1,inc) dfa_callfn(s(0,-2,1),inc) weak(dfa_callargs(s(0,-2,1),s(1,-2,0),s(1,-2,1))) dfa_callargs(s(0,-2,1),s(1,-2,0),s(1,-2,1))
Operations. Loops **ast_op_map**(//symbol-result-ref//, //symbol-source-ref//, //loop-body-ref//) **ast_op_fold**(//symbol-result-ref//, //symbol-source-ref//, //symbol-acc-ref//, //loop-body-ref//) symbol-source-ref input list reference symbol-acc-ref accumulator reference symbol-result-ref result list reference loop-body-ref refers to a loop body expression Facts declare loop operations. Example: name="tests/transcend-ast.cpp: ASTCorrespondence.Doc_BasicTests" test = function:: int; entry { singles = {1, 2, 3}:: [int]. doubles = loop map(singles->element:: int)::[int] {2 * element}. doubles[0] } produces fact: ast_op_map(s(2,-2,0),s(1,-2,0),s(0,-2,1))
diff --git a/vendors/coco/generator/Copyright.frame b/vendors/coco/generator/Copyright.frame deleted file mode 120000 index 708b5d5..0000000 --- a/vendors/coco/generator/Copyright.frame +++ /dev/null @@ -1 +0,0 @@ -/usr/share/coco-cpp/Copyright.frame \ No newline at end of file diff --git a/vendors/coco/generator/Scanner.frame b/vendors/coco/generator/Scanner.frame deleted file mode 120000 index d1ee132..0000000 --- a/vendors/coco/generator/Scanner.frame +++ /dev/null @@ -1 +0,0 @@ -/usr/share/coco-cpp/Scanner.frame \ No newline at end of file