diff --git a/config/default.json b/config/default.json index cb11b3f..7d84629 100644 --- a/config/default.json +++ b/config/default.json @@ -1,75 +1,75 @@ { "containers": { "id": { "implementations": "impl_fulfill_cluster", "clusters": "var_cluster", "prototypes": "proto_cluster", "linkedlist": "linkedlist" }, "impl": { "solid": "solid", "onthefly": "on_the_fly" } }, "logging": { "id": "logging" }, "function-entry": "entry", "transcend": { "bindings" : { "variable": "bind", "function": "bind_func", "scope": "bind_scope", "function_demand" : "bind_function_demand", "scope_decision": "bind_scope_decision" }, "context" : { "decisions":{ "dependent": "resolution_dependency" } }, "nonevalue": "nonevalue", "ret": { "symbol": "retv", "tag": "ret" } }, "tests": { - "template": "latex", + "template": "virtualization", "templates": { "current-fix":"*", "default": "*-Adhoc.*:Containers.*:Compilation.full_IFStatementWithVariantType:Types.full_VariantType_Switch1:Context.full_LateContext:Context.pathDependentContext:CFA.testLoopContextExists", "ast": "AST.*", "effects": "Effects.*", "basic": "Attachments.*", "compilation": "Compilation.*-Compilation.full_IFStatementWithVariantType", "communication": "Communication.*", "cfa": "CFA.*", "containers": "Containers.*", "dfa": "DFA.*", "diagnostic": "Diagnostic.*", "dsl": "Association.*:Interpretation.*", "exploitation": "Exploitation.*", "ExpressionSerializer": "ExpressionSerializer.*", "externc": "InterfaceExternC.*", "loops": "Loop.*", "latereasoning": "LateReasoning.Syntax1:LateReasoning.Pass_DFAPassDec_1", "latex": "Latex.Compilation_TransitFn1", "modules": "Modules.*", "polymorphs": "Polymorphs.*", "intrinsic-query": "Types.SlaveTypes*:Association.TypedQuery*", "types": "Types.*", - "virtualization": "Virtualization.test2", + "virtualization": "Virtualization.*", "vendorsAPI/clang": "ClangAPI.*", "vendorsAPI/xml2": "libxml2*" } } } diff --git a/cpp/src/CMakeLists.txt b/cpp/src/CMakeLists.txt index 2be602b..f86a842 100644 --- a/cpp/src/CMakeLists.txt +++ b/cpp/src/CMakeLists.txt @@ -1,236 +1,236 @@ cmake_minimum_required(VERSION 2.8.11) project(xreate) cmake_policy(SET CMP0022 NEW) message("MODULES" ${CMAKE_MODULE_PATH}) # LLVM #====================== FIND_PACKAGE (LLVM REQUIRED) set(LLVM_VERSION ${LLVM_VERSION_MAJOR}.${LLVM_VERSION_MINOR}) message(STATUS "Found LLVM ${LLVM_PACKAGE_VERSION}") message("LLVM LIB PATH:" ${LLVM_LIBRARY_DIRS}) message(STATUS "Using LLVMConfig.cmake in: ${LLVM_DIR}") INCLUDE_DIRECTORIES(${LLVM_INCLUDE_DIRS}) message(STATUS "INCLUDE DIR: ${LLVM_INCLUDE_DIRS}") add_definitions(${LLVM_DEFINITIONS}) message(STATUS "LLVM DEFS: " ${LLVM_DEFINITIONS}) execute_process( COMMAND llvm-config --libs OUTPUT_VARIABLE LLVM_LIBS OUTPUT_STRIP_TRAILING_WHITESPACE) message(STATUS "LLVM LIBS: " ${LLVM_LIBS}) # CLANG #====================== set(CLANG_LIBS clangCodeGen clangASTMatchers clangQuery clangTooling clangFrontend clangSerialization clangDriver clangParse clangSema clangAnalysis clangAST clangEdit clangLex clangBasic ) # POTASSCO #====================== set(POTASSCO_PATH "/opt/potassco/clingo" CACHE PATH "Path to potassco sources") set(POTASSCO_INCLUDE_PATH ${POTASSCO_PATH}/libgringo ${POTASSCO_PATH}/libclasp ${POTASSCO_PATH}/libclingo ${POTASSCO_PATH}/libprogram_opts ${POTASSCO_PATH}/liblp ) INCLUDE_DIRECTORIES(${POTASSCO_INCLUDE_PATH}) set(LIBCLASP_LIBS clingo clasp gringo program_opts reify lp ) message("CLASP LIBS: " ${LIBCLASP_LIBS}) # OTHER DEPENDENCIES #=========================== set(JEAYESON_INCLUDE_PATH ${CMAKE_HOME_DIRECTORY}/../vendors/jeayeson/include/ ) INCLUDE_DIRECTORIES(${JEAYESON_INCLUDE_PATH}) # COCO #=========================== set(COCO_EXECUTABLE "" CACHE PATH "Path to coco executable") set(COCO_FRAMES_PATH "" CACHE PATH "Path to coco frames") set(COCO_GRAMMAR_PATH ${CMAKE_HOME_DIRECTORY}/../grammar/) set(COCO_SOURCE_FILES_MAIN ${COCO_GRAMMAR_PATH}/main/Parser.cpp ${COCO_GRAMMAR_PATH}/main/Scanner.cpp ) set(COCO_SOURCE_FILES_MODULES ${COCO_GRAMMAR_PATH}/modules/Parser.cpp ${COCO_GRAMMAR_PATH}/modules/Scanner.cpp ) set(COCO_SOURCE_FILES ${COCO_SOURCE_FILES_MODULES} ${COCO_SOURCE_FILES_MAIN}) INCLUDE_DIRECTORIES(${COCO_GRAMMAR_PATH}) add_custom_command(OUTPUT ${COCO_SOURCE_FILES_MAIN} COMMAND ${COCO_GRAMMAR_PATH}/gen-grammar main ${COCO_EXECUTABLE} ${COCO_FRAMES_PATH} WORKING_DIRECTORY ${COCO_GRAMMAR_PATH} MAIN_DEPENDENCY ${COCO_GRAMMAR_PATH}/xreate.ATG ) add_custom_command(OUTPUT ${COCO_SOURCE_FILES_MODULES} COMMAND ${COCO_GRAMMAR_PATH}/gen-grammar modules ${COCO_EXECUTABLE} ${COCO_FRAMES_PATH} WORKING_DIRECTORY ${COCO_GRAMMAR_PATH} MAIN_DEPENDENCY ${COCO_GRAMMAR_PATH}/modules.ATG ) message(STATUS "COCO GRAMMAR BUILD STATUS:" ${COCO_OUTPUT}) # XREATE #====================== set(SOURCE_FILES + compilation/interpretation-instructions.cpp + ExternLayer.cpp analysis/cfagraph.cpp compilation/latereasoning.cpp analysis/interpretation.cpp query/latex.cpp query/polymorph.cpp compilation/polymorph.cpp aux/latereasoning.cpp compilation/latex.cpp - compilation/interpretation-instructions.cpp analysis/typeinference.cpp xreatemanager.cpp transcendlayer.cpp analysis/dfagraph.cpp analysis/DominatorsTreeAnalysisProvider.cpp llvmlayer.cpp - ExternLayer.cpp pass/compilepass.cpp 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 pass/cfapass.cpp contextrule.cpp query/containers.cpp aux/serialization/expressionserializer.cpp modules.cpp ) set(XREATE_INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/ ) INCLUDE_DIRECTORIES(${XREATE_INCLUDE_DIRS}) set(XREATE_PRIVATE_INCLUDE_DIRS ${XREATE_INCLUDE_DIRS} ${COCO_GRAMMAR_PATH} ${JEAYESON_INCLUDE_PATH} ${LLVM_INCLUDE_DIRS} ${POTASSCO_INCLUDE_PATH} ) add_library(${PROJECT_NAME} SHARED ${COCO_SOURCE_FILES} ${SOURCE_FILES}) target_link_libraries(${PROJECT_NAME}) target_include_directories(${PROJECT_NAME} INTERFACE ${XREATE_INCLUDE_DIRS} ${COCO_GRAMMAR_PATH} ${JEAYESON_INCLUDE_PATH} ${LLVM_INCLUDE_DIRS} ${POTASSCO_INCLUDE_PATH} ) get_directory_property(DEFINITIONS_ALL DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} COMPILE_DEFINITIONS) message("definitions all: " ${DEFINITIONS_ALL}) target_compile_definitions(${PROJECT_NAME} INTERFACE ${DEFINITIONS_ALL}) get_directory_property(COMPILATION_OPTIONS_ALL DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} COMPILE_OPTIONS) message("compilations all: " ${COMPILATION_OPTIONS_ALL}) target_compile_options(${PROJECT_NAME} INTERFACE ${COMPILATION_OPTIONS_ALL}) SET_PROPERTY(TARGET ${PROJECT_NAME} PROPERTY INTERFACE_LINK_LIBRARIES ${LIBCLASP_LIBS} ${CLANG_LIBS} ${LLVM_LIBS} tbb boost_system boost_filesystem ) #${CLANG_LIBS} #set (LINK_INTERFACE_LIBRARIES "") # FUNCTION(PREPEND var prefix) # SET(listVar "") # FOREACH(f ${ARGN}) # LIST(APPEND listVar "${prefix}/${f}") # ENDFOREACH(f) # SET(${var} "${listVar}" PARENT_SCOPE) # ENDFUNCTION(PREPEND) #set(COTIRE_UNITY_SOURCE_MAXIMUM_NUMBER_OF_INCLUDES "-j4") #cotire(xreate) # MACRO (ADD_PCH_RULE _header_filename _src_list) # SET(_gch_filename "${_header_filename}.gch") # LIST(APPEND ${_src_list} ${_gch_filename}) # SET (_args ${CMAKE_CXX_FLAGS}) # LIST(APPEND _args -c ${_header_filename} -o ${_gch_filename}) # GET_DIRECTORY_PROPERTY(DIRINC INCLUDE_DIRECTORIES) # foreach (_inc ${DIRINC}) # LIST(APPEND _args "-I" ${_inc}) # endforeach(_inc ${DIRINC}) # SEPARATE_ARGUMENTS(_args) # add_custom_command(OUTPUT ${_gch_filename} # COMMAND rm -f ${_gch_filename} # COMMAND ${CMAKE_CXX_COMPILER} ${CMAKE_CXX_COMPILER_ARG1} ${_args} # DEPENDS ${_header_filename}) # ENDMACRO(ADD_PCH_RULE _header_filename _src_list) # ADD_PCH_RULE (${CMAKE_HOME_DIRECTORY}/src/ast.h SOURCE_FILES) # ADD_PCH_RULE (${CMAKE_HOME_DIRECTORY}/src/llvmlayer.h SOURCE_FILES) # ADD_PCH_RULE (${CMAKE_HOME_DIRECTORY}/src/clasplayer.h SOURCE_FILES) # ADD_PCH_RULE (${CMAKE_HOME_DIRECTORY}/src/pass/abstractpass.h SOURCE_FILES) diff --git a/cpp/src/ExternLayer.cpp b/cpp/src/ExternLayer.cpp index 02bdedb..5c39308 100644 --- a/cpp/src/ExternLayer.cpp +++ b/cpp/src/ExternLayer.cpp @@ -1,318 +1,315 @@ /* 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 * * \file ExternLayer.h * \brief Support of external C code. Wrapper over Clang */ #include "ExternLayer.h" #include "clang/Tooling/Tooling.h" #include "clang/Frontend/ASTUnit.h" #include "clang/Frontend/CodeGenOptions.h" #include "clang/ASTMatchers/ASTMatchers.h" #include "clang/ASTMatchers/ASTMatchFinder.h" #include "clang/Basic/TargetInfo.h" -#include "clang/Lex/PreprocessorOptions.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 : +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")) { + virtual void + run(const MatchFinder::MatchResult &Result) { + if (const TypedefDecl * decl = Result.Nodes.getNodeAs("typename")) { typeResult = decl->getUnderlyingType(); } } -}; +} ; -class FinderCallbackFunction : public MatchFinder::MatchCallback { -public : +class FinderCallbackFunction : public MatchFinder::MatchCallback{ +public: QualType typeResult; - virtual void run(const MatchFinder::MatchResult &Result) { - if (const FunctionDecl* decl = Result.Nodes.getNodeAs("function")) { + 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) -{ +ExternData::addLibrary(Atom&& name, Atom&& package) { __dictLibraries.emplace(name.get(), package.get()); } void -ExternData::addIncludeDecl(Expression&& e) -{ +ExternData::addIncludeDecl(Expression&& e) { assert(e.op == Operator::LIST_NAMED); - //TODO ?? implement Expression parsing(Array of Expr as vector); - for(size_t i=0, size=e.operands.size(); i); + 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(); - }); + [](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){ +ExternLayer::addExternalData(const std::vector& data) { entries.insert(entries.end(), data.begin(), data.end()); } ExternLayer::ExternLayer(LLVMLayer *llvm) - : __llvm(llvm) -{} - +: __llvm(llvm) { } std::vector -ExternLayer::fetchPackageFlags(const ExternEntry& entry){ +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 + 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); +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 "<&& 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' + // 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" + , "-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: "; + 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 << "> "; + for(const string arg : args2) { + llvm::outs() << "<" << arg << "> "; } - llvm::outs()<<"\n[ExternC] libs: "; + llvm::outs() << "\n[ExternC] libs: "; args2 = fetchPackageLibs(entry); - for(const string arg: args2) { - llvm::outs()<< "<" << arg << "> "; + for(const string arg : args2) { + llvm::outs() << "<" << arg << "> "; } libs.insert(libs.end(), args2.begin(), args2.end()); - llvm::outs()<<"\n[ExternC] headers: "; + 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 << "> "; + 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( - ast->getASTContext().getDiagnostics(), + __clang->getDiagnostics(), __llvm->module->getName(), - HeaderSearchOptions(), - PreprocessorOptions(), - CodeGenOptions(), + __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){ +ExternLayer::toLLVMType(const clang::QualType& t) { return CodeGen::convertTypeForMemory( __codegen->CGM(), t); } std::vector -ExternLayer::getStructFields(const clang::QualType& ty) -{ +ExternLayer::getStructFields(const clang::QualType& ty) { clang::QualType t = ty; - if (isPointer(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){ + for (auto i = record->getDecl()->field_begin(); i != record->getDecl()->field_end(); ++i) { result.push_back(i->getName()); } return result; } clang::QualType -ExternLayer::lookupType(const std::string& id){ +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); - } +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: "<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 fde7e6a..49fe4b3 100644 --- a/cpp/src/ExternLayer.h +++ b/cpp/src/ExternLayer.h @@ -1,63 +1,65 @@ /* 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 */ #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 clang{ +class CodeGenerator; } -namespace xreate { - struct ExternData { - void addLibrary(Atom&& name, Atom&& package); - void addIncludeDecl(Expression&& e); +namespace xreate{ - std::vector entries; - std::map __dictLibraries; - }; +struct ExternData{ + void addLibrary(Atom&& name, Atom&& package); + void addIncludeDecl(Expression&& e); - class ExternLayer { - public: - ExternLayer(LLVMLayer* llvm); + std::vector entries; + std::map __dictLibraries; +}; - llvm::Function* lookupFunction(const std::string& name); - clang::QualType lookupType(const std::string& id); - std::vector getStructFields(const clang::QualType& ty); +class ExternLayer{ +public: + ExternLayer(LLVMLayer* llvm); + void init(const AST* root); - llvm::Type* toLLVMType(const clang::QualType& t); - bool isPointer(const clang::QualType& t); + 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); - void init(const AST* root); - static std::vector fetchPackageFlags(const ExternEntry& entry); - static std::vector fetchPackageLibs(const ExternEntry& entry); - private: + static std::vector fetchPackageFlags(const ExternEntry& entry); + static std::vector fetchPackageLibs(const ExternEntry& entry); - std::unique_ptr ast; - std::unique_ptr __codegen; - LLVMLayer* __llvm; - std::vector entries; - std::map __functions; +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); - }; + void addExternalData(const std::vector& data); + void loadLibraries(std::vector&& libs); +}; } #endif //XREATE_EXTERNLAYER_H diff --git a/cpp/src/analysis/cfagraph.cpp b/cpp/src/analysis/cfagraph.cpp index 9d3caa9..df29784 100644 --- a/cpp/src/analysis/cfagraph.cpp +++ b/cpp/src/analysis/cfagraph.cpp @@ -1,221 +1,220 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * File: CFAGraph.cpp * Author: pgess * * Created on June 27, 2016, 2:09 PM */ /** * \file cfagraph.h * \brief Control Flow Analysis(CFA) graph data * */ #include "analysis/cfagraph.h" #include "analysis/utils.h" using namespace xreate::cfa; using namespace std; void CFAGraph::print(std::ostringstream& output) const { const std::string& atomBinding = Config::get("transcend.bindings.function"); const std::string& atomBindingScope = Config::get("transcend.bindings.scope"); output << endl << "%\t\tStatic analysis: CFA" << endl; output << __outputPrecomputed.str(); //show function tags int counterTags = 0; std::ostringstream bufFunctionNames; boost::format formatFunction("function(%1%)."); boost::format formatBind(atomBinding + "(%1%, %2%)."); for (auto function : this->__nodesFunction.left) { const auto tags = this->__functionTags.equal_range(function.first); if (tags.first == tags.second) { //no tags bufFunctionNames << "; " << function.second ; continue; } output << formatFunction % (function.second) << std::endl; for (const auto& tag_ : boost::make_iterator_range(tags)) { const Expression& tag = tag_.second; list tagRaw = xreate::analysis::compile(tag); assert(tagRaw.size() == 1); output << formatBind % (function.second) % (tagRaw.front()) << endl; ++counterTags; } } if (bufFunctionNames.tellp()) { output << formatFunction % (bufFunctionNames.str().substr(2)) << std::endl; } if (counterTags == 0) { - output << "%no functtion tags at all" << endl; + output << "%no function tags at all" << endl; } //declare scopes boost::format formatScope("scope(0..%1%)."); output << formatScope % (__transcend->getScopesCount() - 1) << std::endl; //show context rules: for (auto rule : this->__contextRules) { output << ContextRule(rule.second).compile(rule.first) << std::endl; }; //show scope tags: counterTags = 0; boost::format formatScopeBind(atomBindingScope + "(%1%, %2%, strong)."); for (auto entry : this->__scopeTags) { ScopePacked scopeId = entry.first; const Expression& tag = entry.second; list tagRaw = xreate::analysis::compile(tag); assert(tagRaw.size() == 1); output << formatScopeBind % scopeId % (tagRaw.front()) << endl; ++counterTags; } if (counterTags == 0) { output << "%scope tags: no tags at all" << endl; } //parent connections //TOTEST CFG parent function boost::format formatFunctionParent("cfa_parent(%1%, function(%2%))."); for (const auto &relation : this->__parentFunctionRelations) { const string& function = this->__nodesFunction.left.at(relation.right); output << formatFunctionParent % relation.left % function << endl; } //TOTEST CFG parent scope boost::format formatScopeParent("cfa_parent(%1%, scope(%2%))."); for (const auto &relation : this->__parentScopeRelations) { output << formatScopeParent % relation.first % relation.second << endl; } //call connections boost::format formatCall("cfa_call(%1%, %2%)."); for (const auto &relation : this->__callRelations) { const ScopePacked scopeFrom = relation.left; const string& functionTo = this->__nodesFunction.left.at(relation.right); output << formatCall % (scopeFrom) % (functionTo) << endl; } - //function specializations descrtiption - //SECTIONTAG late-context cfa_function_specializations + //function specializations description boost::format formatSpecializations("cfa_function_specializations(%1%, %2%)."); const list& functions = __transcend->ast->getAllFunctions(); for (auto f : functions) { if (f->guard.isValid()) { list guardRaw = xreate::analysis::compile(f->guard); assert(guardRaw.size() == 1); output << formatSpecializations % (f->getName()) % (guardRaw.front()) << endl; } } //Dependencies boost::format formatDependencies("cfa_scope_depends(%1%, %2%)."); for(const auto relation : __dependencyRelations) { output << formatDependencies % relation.first % relation.second << endl; } std::multimap __dependencyRelations; } void CFAGraph::addFunctionAnnotations(const std::string& function, const std::map& tags) { unsigned int fid = registerNodeFunction(function); for (auto& tag : tags) { __functionTags.emplace(fid, tag.second); } } void CFAGraph::addScopeAnnotations(const ScopePacked& scope, const std::vector& tags) { for (Expression tag : tags) { __scopeTags.emplace(scope, tag); } } void CFAGraph::addContextRules(const ScopePacked& scope, const std::vector& rules) { for (Expression rule : rules) { __contextRules.emplace(scope, rule); } } void CFAGraph::addCallConnection(const ScopePacked& scopeFrom, const std::string& functionTo) { unsigned int idFuncTo = registerNodeFunction(functionTo); __callRelations.insert(CALL_RELATIONS::value_type(scopeFrom, idFuncTo)); } void CFAGraph::addParentConnection(const ScopePacked& scope, const std::string& functionParent) { __parentFunctionRelations.insert(PARENT_FUNCTION_RELATIONS::value_type(scope, registerNodeFunction(functionParent))); } void CFAGraph::addParentConnection(const ScopePacked& scope, const ScopePacked& scopeParent) { __parentScopeRelations.emplace(scope, scopeParent); } unsigned int CFAGraph::registerNodeFunction(const std::string& fname) { auto pos = __nodesFunction.left.insert(make_pair(__nodesFunction.size(), fname)); return pos.first->first; } void CFAGraph::addDependency(const ScopePacked& scope, const ScopePacked& scopeDependency) { __dependencyRelations.emplace(scope, scopeDependency); } bool CFAGraph::isDependent(const ScopePacked& scope) const { return __dependencyRelations.count(scope) > 0; } void CFAGraph::transmitDependencies(const ScopePacked& scopeTo, const ScopePacked& scopeFrom) { auto range = __dependencyRelations.equal_range(scopeFrom); std::list dependencies; for (auto pairI = range.first; pairI != range.second; ++pairI) { dependencies.push_back(pairI->second); } for(auto dep : dependencies) { __dependencyRelations.emplace(scopeTo, dep); } } void CFAGraph::addScope(CodeScope* scope) { boost::format formatScopeBinding("ast_scope_binding(%1%, %2%, \"%3%\")."); ScopePacked scopeId = __transcend->pack(scope); - for (int id, size = scope->__bindings.size(); id < size; ++id) { + for (int id=0, size = scope->__bindings.size(); id < size; ++id) { __outputPrecomputed << formatScopeBinding % scopeId % id % scope->__bindings.at(id) << endl; } -} \ No newline at end of file +} diff --git a/cpp/src/analysis/typeinference.cpp b/cpp/src/analysis/typeinference.cpp index 379739c..3583aca 100644 --- a/cpp/src/analysis/typeinference.cpp +++ b/cpp/src/analysis/typeinference.cpp @@ -1,79 +1,87 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * typeinference.cpp * * Author: pgess * Created on April 16, 2017, 10:13 AM */ /** * \file typeinference.h * \brief Type inference analysis */ #include "typeinference.h" #include "llvmlayer.h" +#include "transcendlayer.h" #include "llvm/IR/Function.h" #include "llvm/IR/DerivedTypes.h" -#include "transcendlayer.h" using namespace std; namespace xreate{ namespace typeinference{ //TODO type conversion: //a) automatically expand types int -> bigger int; int -> floating //b) detect exact type of `num` based on max used numeral / function type -//c) warning if need to truncate (allow/dissalow based on annotations) +//c) warning if need to truncate (allow/dissallow based on annotations) llvm::Value* doAutomaticTypeConversion(llvm::Value* source, llvm::Type* tyTarget, llvm::IRBuilder<>& builder) { if(tyTarget->isIntegerTy() && source->getType()->isIntegerTy()) { llvm::IntegerType* tyTargetInt = llvm::dyn_cast(tyTarget); llvm::IntegerType* tySourceInt = llvm::dyn_cast(source->getType()); if(tyTargetInt->getBitWidth() < tySourceInt->getBitWidth()) { return builder.CreateCast(llvm::Instruction::Trunc, source, tyTarget); } if(tyTargetInt->getBitWidth() > tySourceInt->getBitWidth()) { return builder.CreateCast(llvm::Instruction::SExt, source, tyTarget); } } if(source->getType()->isIntegerTy() && tyTarget->isFloatingPointTy()) { return builder.CreateCast(llvm::Instruction::SIToFP, source, tyTarget); } + + if (source->getType()->isStructTy() && tyTarget->isIntegerTy()){ + llvm::StructType* sourceST = llvm::cast(source->getType()); + if(sourceST->getNumElements() == 1) { + llvm::Value* sourceElRaw = builder.CreateExtractValue(source, llvm::ArrayRef({0})); + return doAutomaticTypeConversion(sourceElRaw, tyTarget, builder); + } + } return source; } ExpandedType getType(const Expression& expression, const AST& ast) { if(expression.type.isValid()) { return ast.expandType(expression.type); } if(expression.__state == Expression::IDENT) { Symbol s = Attachments::get(expression); return getType(CodeScope::getDefinition(s), ast); } if(Attachments::exists(expression)) { return Attachments::get(expression); } if(expression.__state == Expression::NUMBER) { return ExpandedType(TypeAnnotation(TypePrimitive::I32)); } assert(false && "Type can't be determined for an expression"); } } } //end of namespace xreate::typeinference diff --git a/cpp/src/ast.cpp b/cpp/src/ast.cpp index 8a91699..73dfef3 100644 --- a/cpp/src/ast.cpp +++ b/cpp/src/ast.cpp @@ -1,982 +1,977 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * Author: pgess * File: ast.cpp */ /** * \file ast.h * \brief Syntax Tree and related code * * \sa xreate::AST */ #include "ast.h" #include "ExternLayer.h" #include "analysis/typeinference.h" #include #include //TODO BDecl. forbid multiple body declaration (ExprTyped) namespace std { std::size_t hash::operator()(xreate::ScopedSymbol const& s) const { return s.id ^ (s.version << 2); } bool equal_to::operator()(const xreate::ScopedSymbol& __x, const xreate::ScopedSymbol& __y) const { return __x.id == __y.id && __x.version == __y.version; } size_t hash::operator()(xreate::Symbol const& s) const { return hash()(s.identifier) ^ ((long int) s.scope << 1); } bool equal_to::operator()(const xreate::Symbol& __x, const xreate::Symbol& __y) const { return __x == __y; }; } using namespace std; namespace xreate { Atom::Atom(const std::wstring& value) { __value = wstring_to_utf8(value); } Atom::Atom(std::string && name) : __value(name) { } const std::string& Atom::get() const { return __value; } Atom::Atom(wchar_t* value) { //DEBT reconsider number literal recognition __value = wcstol(value, 0, 10); } Atom::Atom(int value) : __value(value) { } double Atom::get()const { return __value; } Atom::Atom(const std::wstring& value) { assert(value.size() >= 2); __value = wstring_to_utf8(value.substr(1, value.size() - 2)); } Atom::Atom(std::string && name) : __value(name) {} const std::string& Atom::get() const { return __value; } class ExpressionHints { public: static bool isStringValueValid(const Expression& e) { switch (e.__state) { case Expression::INVALID: assert(false); case Expression::IDENT: case Expression::STRING: return true; case Expression::NUMBER: case Expression::BINDING: return false; case Expression::COMPOUND: { switch (e.op) { case Operator::CALL: return true; default: return false; } } } return false; } static bool isDoubleValueValid(const Expression& e) { switch (e.__state) { case Expression::NUMBER: return true; case Expression::INVALID: assert(false); case Expression::IDENT: case Expression::STRING: case Expression::BINDING: return false; case Expression::COMPOUND: { switch (e.op) { case Operator::VARIANT: return true; default: return false; } } } return false; } }; class TypesResolver { private: const AST* ast; std::map scope; std::map signatures; ExpandedType expandType(const TypeAnnotation &t, const std::vector &args = std::vector()) { return TypesResolver(ast, scope, signatures)(t, args); } std::vector expandOperands(const std::vector& operands) { std::vector pack; pack.reserve(operands.size()); std::transform(operands.begin(), operands.end(), std::inserter(pack, pack.end()), [this](const TypeAnnotation & t) { return expandType(t); }); return pack; } public: TypesResolver(const AST* root, const std::map& scopeOuter = std::map(), std::map signaturesOuter = std::map()) : ast(root), scope(scopeOuter), signatures(signaturesOuter) { } ExpandedType operator()(const TypeAnnotation &t, const std::vector &args = std::vector()) { //assert(args.size() == t.bindings.size()); // invalid number of arguments for (size_t i = 0; i < args.size(); ++i) { scope[t.bindings.at(i)] = args.at(i); } switch (t.__operator) { case TypeOperator::LIST: { assert(t.__operands.size() == 1); Expanded elTy = expandType(t.__operands.at(0)); return ExpandedType(TypeAnnotation(tag_array, elTy, 0)); } case TypeOperator::LIST_NAMED: { std::vector&& packOperands = expandOperands(t.__operands); auto typNew = TypeAnnotation(TypeOperator::LIST_NAMED, move(packOperands)); typNew.fields = t.fields; return ExpandedType(move(typNew)); }; case TypeOperator::VARIANT: { std::vector&& packOperands = expandOperands(t.__operands); auto typNew = TypeAnnotation(TypeOperator::VARIANT, move(packOperands)); typNew.fields = t.fields; return ExpandedType(move(typNew)); }; case TypeOperator::CALL: { std::string alias = t.__valueCustom; //find in local scope: TypeAnnotation ty; if (scope.count(alias)) { ty = scope.at(alias); } else if (ast->__indexTypeAliases.count(alias)) { ty = ast->__indexTypeAliases.at(alias); } else { assert(false && "Undefined or external type"); } std::vector&& operands = expandOperands(t.__operands); TypeAnnotation signature(TypeOperator::CALL, move(operands)); signature.__valueCustom = alias; if (signatures.count(signature)) { auto link = TypeAnnotation(TypeOperator::LINK,{}); link.conjuctionId = signatures.at(signature); return ExpandedType(move(link)); } int cid = signatures.size(); signatures[signature] = cid; TypeAnnotation tyResult = expandType(ty, operands); tyResult.conjuctionId = cid; return ExpandedType(move(tyResult)); }; case TypeOperator::CUSTOM: { if (signatures.count(t)) { return ExpandedType(TypeAnnotation(TypeOperator::LINK, {t})); } signatures.emplace(t, signatures.size()); std::string alias = t.__valueCustom; //find in local scope: if (scope.count(alias)) { return expandType(scope.at(alias)); } //find in general scope: if (ast->__indexTypeAliases.count(alias)) { return expandType(ast->__indexTypeAliases.at(t.__valueCustom)); } //if type is unknown keep it as is. return ExpandedType(TypeAnnotation(t)); }; case TypeOperator::ACCESS: { std::string alias = t.__valueCustom; ExpandedType tyAlias = ExpandedType(TypeAnnotation()); //Find in local scope: if (scope.count(alias)) { tyAlias = expandType(scope.at(alias)); //Find in global scope: } else if ((ast->__indexTypeAliases.count(alias))) { tyAlias = expandType(ast->__indexTypeAliases.at(alias)); } else { assert(false && "Undefined or external type"); } assert(tyAlias->__operator == TypeOperator::LIST_NAMED); for (const string& field : t.fields) { auto fieldIt = std::find(tyAlias->fields.begin(), tyAlias->fields.end(), field); assert(fieldIt != tyAlias->fields.end() && "unknown field"); int fieldId = fieldIt - tyAlias->fields.begin(); tyAlias = expandType(tyAlias->__operands.at(fieldId)); } return tyAlias; } case TypeOperator::NONE: { return ExpandedType(TypeAnnotation(t)); } case TypeOperator::SLAVE: { return ExpandedType(t); } default: assert(false); } assert(false); return ExpandedType(TypeAnnotation()); } }; TypeAnnotation::TypeAnnotation() : __operator(TypeOperator::NONE), __value(TypePrimitive::Invalid) { } TypeAnnotation::TypeAnnotation(TypePrimitive typ) : __value(typ) { } TypeAnnotation::TypeAnnotation(TypeOperator op, std::initializer_list operands) : __operator(op), __operands(operands) { } TypeAnnotation::TypeAnnotation(TypeOperator op, std::vector&& operands) : __operator(op), __operands(operands) { } TypeAnnotation::TypeAnnotation(llvm_array_tag, TypeAnnotation typ, int size) : TypeAnnotation(TypeOperator::LIST,{typ}) { __size = size; } bool TypeAnnotation::isValid() const { return !(__value == TypePrimitive::Invalid && __operator == TypeOperator::NONE); } bool TypeAnnotation::operator<(const TypeAnnotation& t) const { if (__operator != t.__operator) return __operator < t.__operator; if (__operator == TypeOperator::NONE) return __value < t.__value; if (__operator == TypeOperator::CALL || __operator == TypeOperator::CUSTOM || __operator == TypeOperator::ACCESS) { if (__valueCustom != t.__valueCustom) return __valueCustom < t.__valueCustom; } return __operands < t.__operands; } /* TypeAnnotation (struct_tag, std::initializer_list) {} */ void TypeAnnotation::addBindings(std::vector>&& params) { bindings.reserve(bindings.size() + params.size()); std::transform(params.begin(), params.end(), std::inserter(bindings, bindings.end()), [](const Atom& ident) { return ident.get(); }); } void TypeAnnotation::addFields(std::vector>&& listFields) { fields.reserve(fields.size() + listFields.size()); std::transform(listFields.begin(), listFields.end(), std::inserter(fields, fields.end()), [](const Atom& ident) { return ident.get(); }); } unsigned int Expression::nextVacantId = 0; Expression::Expression(const Atom& number) : Expression() { __state = NUMBER; op = Operator::INVALID; __valueD = number.get(); } Expression::Expression(const Atom& a) : Expression() { __state = STRING; op = Operator::INVALID; __valueS = a.get(); } Expression::Expression(const Atom &ident) : Expression() { __state = IDENT; op = Operator::INVALID; __valueS = ident.get(); } Expression::Expression(const Operator &oprt, std::initializer_list params) : Expression() { __state = COMPOUND; op = oprt; if (op == Operator::CALL) { assert(params.size() > 0); Expression arg = *params.begin(); assert(arg.__state == Expression::IDENT); __valueS = std::move(arg.__valueS); operands.insert(operands.end(), params.begin() + 1, params.end()); return; } operands.insert(operands.end(), params.begin(), params.end()); } void Expression::setOp(Operator oprt) { op = oprt; switch (op) { case Operator::INVALID: __state = INVALID; break; default: __state = COMPOUND; break; } } void Expression::addArg(Expression &&arg) { operands.push_back(arg); } void Expression::addTags(const std::list tags) const { std::transform(tags.begin(), tags.end(), std::inserter(this->tags, this->tags.end()), [](const Expression & tag) { return make_pair(tag.getValueString(), tag); }); } void Expression::addBindings(std::initializer_list> params) { addBindings(params.begin(), params.end()); } void Expression::bindType(TypeAnnotation t) { type = move(t); } void Expression::addBlock(ManagedScpPtr scope) { blocks.push_back(scope.operator->()); } const std::vector& Expression::getOperands() const { return operands; } double Expression::getValueDouble() const { return __valueD; } const std::string& Expression::getValueString() const { return __valueS; } void Expression::setValue(const Atom&& v) { __valueS = v.get(); } void Expression::setValueDouble(double value) { __valueD = value; } bool Expression::isValid() const { return (__state != INVALID); } bool Expression::isDefined() const { return (__state != BINDING && __state != INVALID); } Expression::Expression() : __state(INVALID), op(Operator::INVALID), id(nextVacantId++) { } namespace details { namespace inconsistent { AST::AST() { Attachments::init(); Attachments::init(); Attachments::init(); Attachments::init(); } void AST::addInterfaceData(const ASTInterface& interface, Expression&& data) { __interfacesData.emplace(interface, move(data)); } void AST::addDFAData(Expression &&data) { __dfadata.push_back(data); } void AST::addExternData(ExternData &&data) { __externdata.insert(__externdata.end(), data.entries.begin(), data.entries.end()); } void AST::add(Function* f) { __functions.push_back(f); __indexFunctions.emplace(f->getName(), __functions.size() - 1); } void AST::add(MetaRuleAbstract *r) { __rules.push_back(r); } void AST::add(TypeAnnotation t, Atom alias) { if (t.__operator == TypeOperator::VARIANT) { for (int i = 0, size = t.fields.size(); i < size; ++i) { __dictVariants.emplace(t.fields[i], make_pair(t, i)); } } __indexTypeAliases.emplace(alias.get(), move(t)); } ManagedScpPtr AST::add(CodeScope* scope) { this->__scopes.push_back(scope); return ManagedScpPtr(this->__scopes.size() - 1, &this->__scopes); } std::string AST::getModuleName() { const std::string name = "moduleTest"; return name; } ManagedPtr AST::findFunction(const std::string& name) { int count = __indexFunctions.count(name); if (!count) { return ManagedFnPtr::Invalid(); } assert(count == 1); auto range = __indexFunctions.equal_range(name); return ManagedPtr(range.first->second, &this->__functions); } std::list AST::getAllFunctions() const { const size_t size = __functions.size(); std::list result; for (size_t i = 0; i < size; ++i) { result.push_back(ManagedFnPtr(i, &this->__functions)); } return result; } //TASK select default specializations std::list AST::getFunctionSpecializations(const std::string& fnName) const { auto functions = __indexFunctions.equal_range(fnName); std::list result; std::transform(functions.first, functions.second, inserter(result, result.end()), [this](auto f) { return ManagedFnPtr(f.second, &this->__functions); }); return result; } template<> ManagedPtr AST::begin() { return ManagedPtr(0, &this->__functions); } template<> ManagedPtr AST::begin() { return ManagedPtr(0, &this->__scopes); } template<> ManagedPtr AST::begin() { return ManagedPtr(0, &this->__rules); } void AST::recognizeVariantConstructor(Expression& function) { assert(function.op == Operator::CALL); std::string variant = function.getValueString(); if (!__dictVariants.count(variant)) { return; } auto record = __dictVariants.at(variant); const TypeAnnotation& typ = record.first; function.op = Operator::VARIANT; function.setValueDouble(record.second); function.type = typ; } Atom AST::recognizeVariantConstructor(Atom ident) { std::string variant = ident.get(); assert(__dictVariants.count(variant) && "Can't recognize variant constructor"); auto record = __dictVariants.at(variant); return Atom(record.second); } void AST::postponeIdentifier(CodeScope* scope, const Expression& id) { bucketUnrecognizedIdentifiers.emplace(scope, id); } void AST::recognizePostponedIdentifiers() { for (const auto& identifier : bucketUnrecognizedIdentifiers) { if (!identifier.first->recognizeIdentifier(identifier.second)) { //exception: Ident not found std::cout << "Unknown symbol: " << identifier.second.getValueString() << std::endl; assert(false && "Symbol not found"); } } } xreate::AST* AST::finalize() { //all finalization steps: recognizePostponedIdentifiers(); return reinterpret_cast (this); } } } //namespace details::incomplete Expanded AST::findType(const std::string& name) { // find in general scope: if (__indexTypeAliases.count(name)) return expandType(__indexTypeAliases.at(name)); //if type is unknown keep it as is. TypeAnnotation t(TypeOperator::CUSTOM,{}); t.__valueCustom = name; return ExpandedType(move(t)); } Expanded AST::expandType(const TypeAnnotation &t) const { return TypesResolver(this)(t); } ExpandedType AST::getType(const Expression& expression) { return typeinference::getType(expression, *this); } Function::Function(const Atom& name) : __entry(new CodeScope(0)) { __name = name.get(); } void Function::addTag(Expression&& tag, const TagModifier mod) { string name = tag.getValueString(); __tags.emplace(move(name), move(tag)); } const std::map& Function::getTags() const { return __tags; } CodeScope* Function::getEntryScope() const { return __entry; } void -Function::addBinding(Atom && name, Expression&& argument) { - __entry->addBinding(move(name), move(argument)); +Function::addBinding(Atom && name, Expression&& argument, const VNameId hintBindingId) { + __entry->addBinding(move(name), move(argument), hintBindingId); } const std::string& Function::getName() const { return __name; } ScopedSymbol -CodeScope::registerIdentifier(const Expression& identifier) { +CodeScope::registerIdentifier(const Expression& identifier, const VNameId hintBindingId) { versions::VariableVersion version = Attachments::get(identifier, versions::VERSION_NONE); - auto result = __identifiers.emplace(identifier.getValueString(), __vCounter); - if (result.second) { - ++__vCounter; - return { __vCounter - 1, version }; - } - + auto result = __identifiers.emplace(identifier.getValueString(), hintBindingId? hintBindingId: __identifiers.size() + 1); return { result.first->second, version }; } bool CodeScope::recognizeIdentifier(const Expression& identifier) const { versions::VariableVersion version = Attachments::get(identifier, versions::VERSION_NONE); const std::string& name = identifier.getValueString(); //search identifier in the current block if (__identifiers.count(name)) { VNameId id = __identifiers.at(name); Symbol s; s.identifier = ScopedSymbol{id, version}; s.scope = const_cast (this); Attachments::put(identifier, s); return true; } //search in the parent scope if (__parent) { return __parent->recognizeIdentifier(identifier); } return false; } ScopedSymbol CodeScope::getSymbol(const std::string& alias) { assert(__identifiers.count(alias)); VNameId id = __identifiers.at(alias); return {id, versions::VERSION_NONE }; } void -CodeScope::addBinding(Expression&& var, Expression&& argument) { +CodeScope::addBinding(Expression&& var, Expression&& argument, const VNameId hintBindingId) { argument.__state = Expression::BINDING; __bindings.push_back(var.getValueString()); - ScopedSymbol binding = registerIdentifier(var); + ScopedSymbol binding = registerIdentifier(var, hintBindingId); __declarations[binding] = move(argument); } Symbol CodeScope::addDefinition(Expression&& var, Expression&& body) { ScopedSymbol s = registerIdentifier(var); __declarations[s] = move(body); return Symbol{s, this}; } CodeScope::CodeScope(CodeScope* parent) : __parent(parent) { } CodeScope::~CodeScope() { } void CodeScope::setBody(const Expression &body) { assert(__declarations.count(ScopedSymbol::RetSymbol)==0 && "Attempt to reassign scope body"); __declarations[ScopedSymbol::RetSymbol] = body; } const Expression& CodeScope::getBody() const{ return __declarations.at(ScopedSymbol::RetSymbol); } const Expression& CodeScope::getDefinition(const Symbol& symbol, bool flagAllowUndefined){ const CodeScope* self = symbol.scope; return self->getDefinition(symbol.identifier, flagAllowUndefined); } const Expression& CodeScope::getDefinition(const ScopedSymbol& symbol, bool flagAllowUndefined) const{ static Expression expressionInvalid; if (!__declarations.count(symbol)){ if (flagAllowUndefined) return expressionInvalid; assert(false && "Symbol's declaration not found"); } return __declarations.at(symbol); } void RuleArguments::add(const Atom &arg, DomainAnnotation typ) { emplace_back(arg.get(), typ); } void RuleGuards::add(Expression&& e) { push_back(e); } MetaRuleAbstract:: MetaRuleAbstract(RuleArguments&& args, RuleGuards&& guards) : __args(std::move(args)), __guards(std::move(guards)) { } MetaRuleAbstract::~MetaRuleAbstract() { } RuleWarning:: RuleWarning(RuleArguments&& args, RuleGuards&& guards, Expression&& condition, Atom&& message) : MetaRuleAbstract(std::move(args), std::move(guards)), __message(message.get()), __condition(condition) { } RuleWarning::~RuleWarning() { } void RuleWarning::compile(TranscendLayer& layer) { //TODO restore addRuleWarning //layer.addRuleWarning(*this); } bool operator<(const ScopedSymbol& s1, const ScopedSymbol& s2) { return (s1.id < s2.id) || (s1.id == s2.id && s1.version < s2.version); } bool operator==(const ScopedSymbol& s1, const ScopedSymbol& s2) { return (s1.id == s2.id) && (s1.version == s2.version); } bool operator<(const Symbol& s1, const Symbol& s2) { return (s1.scope < s2.scope) || (s1.scope == s2.scope && s1.identifier < s2.identifier); } bool operator==(const Symbol& s1, const Symbol& s2) { return (s1.scope == s2.scope) && (s1.identifier == s2.identifier); } bool operator<(const Expression&a, const Expression&b) { if (a.__state != b.__state) return a.__state < b.__state; assert(a.__state != Expression::INVALID); switch (a.__state) { case Expression::IDENT: case Expression::STRING: return a.getValueString() < b.getValueString(); case Expression::NUMBER: return a.getValueDouble() < b.getValueDouble(); case Expression::COMPOUND: { assert(a.blocks.size() == 0); assert(b.blocks.size() == 0); if (a.op != b.op) { return a.op < b.op; } bool flagAValid = ExpressionHints::isStringValueValid(a); bool flagBValid = ExpressionHints::isStringValueValid(b); if (flagAValid != flagBValid) { return flagAValid < flagBValid; } if (flagAValid) { if (a.getValueString() != b.getValueString()) { return a.getValueString() < b.getValueString(); } } flagAValid = ExpressionHints::isDoubleValueValid(a); flagBValid = ExpressionHints::isDoubleValueValid(b); if (flagAValid != flagBValid) { return flagAValid < flagBValid; } if (flagAValid) { if (a.getValueDouble() != b.getValueDouble()) { return a.getValueDouble() < b.getValueDouble(); } } if (a.operands.size() != b.operands.size()) { return (a.operands.size() < b.operands.size()); } for (size_t i = 0; i < a.operands.size(); ++i) { bool result = a.operands[i] < b.operands[i]; if (result) return true; } return false; } case Expression::BINDING: case Expression::INVALID: assert(false); } return false; } bool Expression::operator==(const Expression& other) const { if (this->__state != other.__state) return false; if (ExpressionHints::isStringValueValid(*this)) { if (this->__valueS != other.__valueS) return false; } if (ExpressionHints::isDoubleValueValid(*this)) { if (this->__valueD != other.__valueD) return false; } if (this->__state != Expression::COMPOUND) { return true; } if (this->op != other.op) { return false; } if (this->operands.size() != other.operands.size()) { return false; } for (size_t i = 0; ioperands.size(); ++i) { if (!(this->operands[i] == other.operands[i])) return false; } assert(!this->blocks.size()); assert(!other.blocks.size()); return true; } const ScopedSymbol ScopedSymbol::RetSymbol = ScopedSymbol{0, versions::VERSION_NONE}; } //end of namespace xreate diff --git a/cpp/src/ast.h b/cpp/src/ast.h index 7052451..768092f 100644 --- a/cpp/src/ast.h +++ b/cpp/src/ast.h @@ -1,741 +1,740 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * Author: pgess * File: ast.h */ #ifndef AST_H #define AST_H #include "attachments.h" #include #include #include #include #include #include #include #include "utils.h" #include namespace llvm { class Value; } namespace xreate { struct ScopedSymbol; struct Symbol; } namespace std { template<> struct hash { std::size_t operator()(xreate::ScopedSymbol const& s) const; }; template<> struct equal_to { bool operator()(const xreate::ScopedSymbol& __x, const xreate::ScopedSymbol& __y) const; }; template<> struct hash { size_t operator()(xreate::Symbol const& s) const; }; template<> struct equal_to { bool operator()(const xreate::Symbol& __x, const xreate::Symbol& __y) const; }; } namespace xreate { struct String_t { }; struct Identifier_t { }; struct Number_t { }; struct Type_t { }; template class Atom { }; //DEBT store line:col for all atoms/identifiers template<> class Atom { public: Atom(const std::wstring& value); Atom(std::string && name); const std::string& get() const; private: std::string __value; }; template<> class Atom { public: Atom(wchar_t* value); Atom(int value); double get()const; private: double __value; }; template<> class Atom { public: Atom(const std::wstring& value); Atom(std::string && name); const std::string& get() const; private: std::string __value; }; enum class TypePrimitive { Invalid, Bool, I8, I32, I64, Num, Int, Float, String }; enum class TypeOperator { NONE, CALL, CUSTOM, VARIANT, LIST, LIST_NAMED, ACCESS, LINK, SLAVE }; struct llvm_array_tag { }; struct struct_tag { }; const llvm_array_tag tag_array = llvm_array_tag(); const struct_tag tag_struct = struct_tag(); /** * \brief Represents type to support type system * * This class represents type in denormalized form, i.e. without arguments and aliases substitution * \sa AST::expandType() */ class TypeAnnotation { public: TypeAnnotation(); TypeAnnotation(const Atom& typ); TypeAnnotation(TypePrimitive typ); TypeAnnotation(llvm_array_tag, TypeAnnotation typ, int size); TypeAnnotation(TypeOperator op, std::initializer_list operands); TypeAnnotation(TypeOperator op, std::vector&& operands); void addBindings(std::vector>&& params); void addFields(std::vector>&& listFields); bool operator<(const TypeAnnotation& t) const; // TypeAnnotation (struct_tag, std::initializer_list); bool isValid() const; TypeOperator __operator = TypeOperator::NONE; std::vector __operands; TypePrimitive __value; std::string __valueCustom; int conjuctionId = -1; //conjunction point id (relevant for recursive types) uint64_t __size = 0; std::vector fields; std::vector bindings; private: }; enum class Operator { INVALID, UNDEF, ADD, SUB, MUL, DIV, EQU, NE, NEG, LSS, LSE, GTR, GTE, LIST, LIST_RANGE, LIST_NAMED, - CALL, CALL_INTRINSIC, + CALL, CALL_INTRINSIC, QUERY, QUERY_LATE, IMPL/* implication */, MAP, FOLD, FOLD_INF, INDEX, IF, SWITCH, SWITCH_VARIANT, SWITCH_LATE, CASE, CASE_DEFAULT, LOGIC_AND, CONTEXT_RULE, VARIANT, SEQUENCE }; class Function; class AST; class CodeScope; class MetaRuleAbstract; typedef ManagedPtr ManagedFnPtr; typedef ManagedPtr ManagedScpPtr; typedef ManagedPtr ManagedRulePtr; const ManagedScpPtr NO_SCOPE = ManagedScpPtr(UINT_MAX, 0); /** * \brief Represents every instruction in Xreate's syntax tree * \attention In case of any changes update xreate::ExpressionHints auxiliary helper as well * * Expression is generic building block of syntax tree able to hold node data * as well as child nodes as operands. Not only instructions use expression for representation in syntax tree * but annotation as well. * * Additionally, `types` as a special kind of annotations use Expression-like data structure TypeAnnotation * \sa xreate::AST, xreate::TypeAnnotation */ // struct Expression { friend class CodeScope; friend class TranscendLayer; friend class CFAPass; friend class ExpressionHints; Expression(const Operator &oprt, std::initializer_list params); Expression(const Atom& ident); Expression(const Atom& number); Expression(const Atom& a); Expression(); void setOp(Operator oprt); void addArg(Expression&& arg); void addBindings(std::initializer_list> params); void bindType(TypeAnnotation t); template void addBindings(InputIt paramsBegin, InputIt paramsEnd); void addTags(const std::list tags) const; void addBlock(ManagedScpPtr scope); const std::vector& getOperands() const; double getValueDouble() const; void setValueDouble(double value); const std::string& getValueString() const; void setValue(const Atom&& v); bool isValid() const; bool isDefined() const; bool operator==(const Expression& other) const; /** * \brief is it string, number, compound operation and so on */ enum { INVALID, COMPOUND, IDENT, NUMBER, STRING, BINDING } __state = INVALID; /** * \brief Valid for compound State. Holds type of compound operator */ Operator op; /** * \brief Unique id to identify expression within syntax tree */ unsigned int id; /** * \brief Exact meaning depends on particular instruction * \details As an example, named lists/structs hold field names in bindings */ std::vector bindings; std::map __indexBindings; /** * \brief Holds child instructions as arguments */ std::vector operands; /** * \brief Holds type of instruction's result */ TypeAnnotation type; /** * \brief Holds additional annotations */ mutable std::map tags; /** * \brief Child code blocks * \details For example, If statement holds TRUE-branch as first and FALSE-branch as second block here */ std::list blocks; private: std::string __valueS; double __valueD; static unsigned int nextVacantId; }; bool operator<(const Expression&, const Expression&); template void Expression::addBindings(InputIt paramsBegin, InputIt paramsEnd) { size_t index = bindings.size(); std::transform(paramsBegin, paramsEnd, std::inserter(bindings, bindings.end()), [&index, this] (const Atom atom) { std::string key = atom.get(); this->__indexBindings[key] = index++; return key; }); } typedef std::list ExpressionList; enum class TagModifier { NONE, ASSERT, REQUIRE }; enum class DomainAnnotation { FUNCTION, VARIABLE }; class RuleArguments : public std::vector> { public: void add(const Atom& name, DomainAnnotation typ); }; class RuleGuards : public std::vector { public: void add(Expression&& e); }; class TranscendLayer; class LLVMLayer; class MetaRuleAbstract { public: MetaRuleAbstract(RuleArguments&& args, RuleGuards&& guards); virtual ~MetaRuleAbstract(); virtual void compile(TranscendLayer& layer) = 0; protected: RuleArguments __args; RuleGuards __guards; }; class RuleWarning : public MetaRuleAbstract { friend class TranscendLayer; public: RuleWarning(RuleArguments&& args, RuleGuards&& guards, Expression&& condition, Atom&& message); virtual void compile(TranscendLayer& layer); ~RuleWarning(); private: std::string __message; Expression __condition; }; typedef unsigned int VNameId; namespace versions { typedef int VariableVersion; const VariableVersion VERSION_NONE = -2; const VariableVersion VERSION_INIT = 0; } template<> struct AttachmentsDict { typedef versions::VariableVersion Data; static const unsigned int key = 6; }; struct ScopedSymbol { VNameId id; versions::VariableVersion version; static const ScopedSymbol RetSymbol; }; struct Symbol { ScopedSymbol identifier; const CodeScope * scope; }; struct IdentifierSymbol{}; struct SymbolAlias{}; template<> struct AttachmentsDict { typedef Symbol Data; static const unsigned int key = 7; }; template<> struct AttachmentsDict { typedef Symbol Data; static const unsigned int key = 9; }; typedef std::pair Tag; bool operator<(const ScopedSymbol& s1, const ScopedSymbol& s2); bool operator==(const ScopedSymbol& s1, const ScopedSymbol& s2); bool operator<(const Symbol& s1, const Symbol& s2); bool operator==(const Symbol& s1, const Symbol& s2); /** * \brief Represents code block and single scope of visibility * * Holds single expression as a *body* and set of variable assignments(declarations) used in body's expression * \sa xreate::AST */ class CodeScope { friend class Function; friend class PassManager; public: CodeScope(CodeScope* parent = 0); ~CodeScope(); /** \brief Set expression as a body */ void setBody(const Expression& body); /** \brief Returns current code scope body */ const Expression& getBody() const; /** \brief Adds variable definition to be used in body as well as in other declarations */ Symbol addDefinition(Expression&& var, Expression&& body); /** \brief Returns symbols' definition */ static const Expression& getDefinition(const Symbol& symbol, bool flagAllowUndefined = false); const Expression& getDefinition(const ScopedSymbol& symbol, bool flagAllowUndefined = false) const; /** \brief Adds variable defined elsewhere */ - void addBinding(Expression&& var, Expression&& argument); + void addBinding(Expression&& var, Expression&& argument, const VNameId hintBindingId = 0); std::vector __bindings; std::map __identifiers; CodeScope* __parent; //TODO move __definitions to SymbolsAttachments data //NOTE: definition of return type has index 0 std::unordered_map __declarations; std::vector tags; std::vector contextRules; private: - VNameId __vCounter = 1; - ScopedSymbol registerIdentifier(const Expression& identifier); + ScopedSymbol registerIdentifier(const Expression& identifier, const VNameId hintBindingId = 0); public: bool recognizeIdentifier(const Expression& identifier) const; ScopedSymbol getSymbol(const std::string& alias); }; /** * \brief Represents single function in Xreate's syntax tree * * Holds an entry code scope and `guardContext` required for function to operate * \sa xreate::AST */ class Function { friend class Expression; friend class CodeScope; friend class AST; public: Function(const Atom& name); /** * \brief Adds function arguments */ - void addBinding(Atom && name, Expression&& argument); + void addBinding(Atom && name, Expression&& argument, const VNameId hintBindingId=0); /** * \brief Adds additional function annotations */ void addTag(Expression&& tag, const TagModifier mod); const std::string& getName() const; const std::map& getTags() const; CodeScope* getEntryScope() const; CodeScope* __entry; std::string __name; bool isPrefunction = false; //SECTIONTAG adhoc Function::isPrefunction flag Expression guard; private: std::map __tags; }; class ExternData; struct ExternEntry { std::string package; std::vector headers; }; typedef Expanded ExpandedType; struct TypeInferred{}; template<> struct AttachmentsDict { typedef ExpandedType Data; static const unsigned int key = 11; }; enum ASTInterface { CFA, DFA, Extern, Adhoc }; struct FunctionSpecialization { std::string guard; size_t id; }; struct FunctionSpecializationQuery { std::unordered_set context; }; template<> struct AttachmentsId{ static unsigned int getId(const Expression& expression){ return expression.id; } }; template<> struct AttachmentsId{ static unsigned int getId(const Symbol& s){ return s.scope->__declarations.at(s.identifier).id; } }; template<> struct AttachmentsId{ static unsigned int getId(const ManagedFnPtr& f){ const Symbol symbolFunction{ScopedSymbol::RetSymbol, f->getEntryScope()}; return AttachmentsId::getId(symbolFunction); } }; template<> struct AttachmentsId{ static unsigned int getId(const CodeScope* scope){ const Symbol symbolScope{ScopedSymbol::RetSymbol, scope}; return AttachmentsId::getId(symbolScope); } }; template<> struct AttachmentsId{ static unsigned int getId(const unsigned int id){ return id; } }; class TypesResolver; namespace details { namespace inconsistent { /** * \brief Syntax tree under construction in inconsistent form * * Represents Syntax Tree under construction(**inconsistent state**). * \attention Clients should use rather xreate::AST unless client's code explicitly works with Syntax Tree during construction. * * Typically instance only created by xreate::XreateManager and filled in by Parser * \sa xreate::XreateManager::prepare(std::string&&) */ class AST { friend class xreate::TypesResolver; public: AST(); /** * \brief Adds new function to AST * \param f Function to register */ void add(Function* f); /** * \brief Adds new declarative rule to AST * \param r Declarative Rule */ void add(MetaRuleAbstract* r); /** \brief Registers new code block */ ManagedScpPtr add(CodeScope* scope); /** * \brief Add new type to AST * @param t Type definition * @param alias Typer name */ void add(TypeAnnotation t, Atom alias); /** \brief Current module's name */ std::string getModuleName(); /** * \brief Looks for function with given name * \param name Function name to find * \note Requires that only one function exists under given name * \return Found function */ ManagedPtr findFunction(const std::string& name); /** \brief Returns all function in AST */ std::list getAllFunctions() const; /** * \brief Returns all specializations of a function with a given name * \param fnName function to find * \return list of found function specializations */ std::list getFunctionSpecializations(const std::string& fnName) const; /** * \return First element in Functions/Scopes/Rules list depending on template parameter * \tparam Target either Function or CodeScope or MetaRuleAbstract */ template ManagedPtr begin(); /** * \brief Performs all necessary steps after AST is built * * Performs all finzalisation steps and move AST into consistent state represented by xreate::AST * \sa xreate::AST * \return AST in consistent state */ xreate::AST* finalize(); typedef std::multimap FUNCTIONS_REGISTRY; std::vector __externdata; std::list __dfadata; //TODO move to more appropriate place std::list __rawImports; //TODO move to more appropriate place std::multimap __interfacesData; //TODO CFA data here. private: std::vector __rules; std::vector __functions; std::vector __scopes; FUNCTIONS_REGISTRY __indexFunctions; protected: std::map __indexTypeAliases; public: /** * \brief Stores DFA scheme for later use by DFA Pass * * Treats expression as a DFA scheme and feeds to a DFA Pass later * \paramn Expression DFA Scheme * \sa xreate::DFAPass */ void addDFAData(Expression&& data); /** \brief Stores data for later use by xreate::ExternLayer */ void addExternData(ExternData&& data); /** * \brief Generalized function to store particular data for later use by particular pass * \param interface Particular Interface * \param data Particular data */ void addInterfaceData(const ASTInterface& interface, Expression&& data); /**\name Symbols Recognition */ ///@{ public: //TODO revisit enums/variants, move to codescope /** * \brief Tries to find out whether expression is Variant constructor */ void recognizeVariantConstructor(Expression& function); Atom recognizeVariantConstructor(Atom ident); private: std::map> __dictVariants; public: std::set> bucketUnrecognizedIdentifiers; public: /** * \brief Postpones unrecognized identifier for future second round of recognition * \param scope Code block identifier is encountered * \param id Identifier */ void postponeIdentifier(CodeScope* scope, const Expression& id); /** \brief Second round of identifiers recognition done right after AST is fully constructed */ void recognizePostponedIdentifiers(); ///@} }; template<> ManagedPtr AST::begin(); template<> ManagedPtr AST::begin(); template<> ManagedPtr AST::begin(); } } // namespace details::incomplete /** * \brief Xreate's Syntax Tree in consistent state * * Syntax Tree has two mutually exclusive possible states: * - inconsistent state while AST is under construction. Represented by xreate::details::inconsistent::AST * - consistent state when AST is built and finalize() is done. * * This class represents consistent state and should be used everywhere unless client's code explicitly works with AST under construction. * Consistent AST enables access to additional functions(currently related to type management). * \sa xreate::details::inconsistent::AST */ class AST : public details::inconsistent::AST { public: AST() : details::inconsistent::AST() {} /** * \brief Computes fully expanded form of type by substituting all arguments and aliases * \param t Type to expand * \return Expdanded or normal form of type * \sa TypeAnnotation */ ExpandedType expandType(const TypeAnnotation &t) const; /** * Searches type by given name * \param name Typename to search * \return Expanded or normal form of desired type * \note if type name is not found returns new undefined type with this name */ ExpandedType findType(const std::string& name); /** * Invokes Type Inference Analysis to find out expanded(normal) form expressions's type * \sa typeinference.h * \param expression * \return Type of expression */ ExpandedType getType(const Expression& expression); }; } #endif // AST_H diff --git a/cpp/src/compilation/interpretation-instructions.cpp b/cpp/src/compilation/interpretation-instructions.cpp index 4b0da50..7c4845f 100644 --- a/cpp/src/compilation/interpretation-instructions.cpp +++ b/cpp/src/compilation/interpretation-instructions.cpp @@ -1,61 +1,116 @@ /* * 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 "latereasoning.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 (__scope->function->man)->ast; - TranscendLayer* transcend = static_cast (__scope->function->man)->pass->man->transcend; - InterpretationFunction* function = static_cast (__scope->function); + AST* ast = static_cast (__fnI12n->man)->ast; + TranscendLayer* transcend = static_cast (__fnI12n->man)->pass->man->transcend; - ExpandedType targetT = ast->expandType(expression.type); + ExpandedType targetT = ast->getType(expression); assert(expression.operands.size() == 1); assert(expression.operands.front().__state == Expression::STRING); assert(targetT->__operator == TypeOperator::LIST); std::string namePredicate = expression.operands.front().getValueString(); - StaticModel model = (static_cast (function->man))->pass->man->transcend->query(namePredicate); + 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)); + ? dereferenceSlaveType(ExpandedType(targetT->__operands.at(0)), transcend) + : ExpandedType(targetT->__operands.at(0)); if(model.size()) { if (elementT->__operator == TypeOperator::LIST_NAMED) { //edge case, content's type is LIST_NAMED: for(const auto& row : model) { result.operands.push_back(representTransExpression(row.second, elementT, transcend)); } } else { for (const auto& row : model) { assert(row.second.args().size); result.operands.push_back(representTransExpression(row.second.args()[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) { + InterpretationScope* bodyI12n = __fnI12n->getScope(body); + Expression argValue; + if (argT->__operator == TypeOperator::LIST_NAMED) { + argValue = representTransExpression(atomRaw, argT, transcend); + } else { + argValue = representTransExpression(atomRaw.args()[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 \ No newline at end of file diff --git a/cpp/src/compilation/interpretation-instructions.h b/cpp/src/compilation/interpretation-instructions.h index 9f1c0a5..284b094 100644 --- a/cpp/src/compilation/interpretation-instructions.h +++ b/cpp/src/compilation/interpretation-instructions.h @@ -1,38 +1,46 @@ /* * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ /* * Author: pgess * Created on June 15, 2018, 5:28 PM * * \file interpretation-instructions.h * \brief Additional intepretation statements */ #ifndef INTERPRETATION_INSTRUCTIONS_H #define INTERPRETATION_INSTRUCTIONS_H -#include "compilation/targetinterpretation.h" #include "ast.h" +namespace xreate{ +namespace compilation{ + class Context; +} +} + namespace xreate{ namespace interpretation{ +class InterpretationFunction; + class IntrinsicQueryInstruction{ public: - IntrinsicQueryInstruction(InterpretationScope* scope): __scope(scope){ } + IntrinsicQueryInstruction(InterpretationFunction* fn): __fnI12n(fn){ } Expression process(const Expression& expression); + llvm::Value* processLate(const Expression& expression, const compilation::Context& context); private: - InterpretationScope* __scope; + InterpretationFunction* __fnI12n; }; } } //end of xreate::interpretation #endif /* INTERPRETATION_INSTRUCTIONS_H */ diff --git a/cpp/src/compilation/latereasoning.cpp b/cpp/src/compilation/latereasoning.cpp index 34e8882..45f8ccd 100644 --- a/cpp/src/compilation/latereasoning.cpp +++ b/cpp/src/compilation/latereasoning.cpp @@ -1,166 +1,175 @@ /* * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * latereasoning.cpp * * Author: pgess * Created on May 26, 2018, 3:54 PM */ #include "compilation/latereasoning.h" //#include "aux/latereasoning.h" #include "compilation/scopedecorators.h" #include "analysis/interpretation.h" #include "compilation/targetinterpretation.h" #include using namespace xreate::interpretation; using namespace xreate::compilation; using namespace std; namespace xreate{ namespace latereasoning{ #define HINT(x) (hint.empty()? x : hint) 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 = interpretation::dereferenceSlaveType(guardT, __context.pass->man->transcend); llvm::Value * guardRaw = __context.scope->process(expr.operands.at(0)); llvm::Type* instructionT = llvm->toLLVMType(root->getType(expr)); 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* +llvm::Value* LateReasoningCompiler::compileAutoExpand(const LateAnnotation& annotation, llvm::Type* resultT, const std::string& hint, Handler handler) { TranscendLayer* transcend = __context.pass->man->transcend; - InterpretationFunction* functionI12n = - dynamic_cast (__scopeI12n->function); AST* root = __context.pass->man->root; const std::list& guardKeys = annotation.guardKeys; - std::list notfound_guardKeys; + std::list guardsToExpand; for(const SymbolPacked key : guardKeys) { - const Symbol& keyS = transcend->unpack(key); - InterpretationScope* keyScope = functionI12n->getScope(keyS.scope); - if (!keyScope->isBindingDefined(keyS.identifier)) { - notfound_guardKeys.push_back(keyS); + 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(notfound_guardKeys.begin(), notfound_guardKeys.end(), + 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); - InterpretationFunction* functionI12n = dynamic_cast (__scopeI12n->function); llvm::Value* keyVariantRaw = builder.CreateExtractValue(keyRaw, llvm::ArrayRef({0})); llvm::SwitchInst* instructionSwitch = builder.CreateSwitch(keyVariantRaw, nullptr, countInstances); llvm::BasicBlock *blockEpilog = llvm::BasicBlock::Create( llvm->llvmContext, "epilog", function->raw); builder.SetInsertPoint(blockEpilog); llvm::PHINode *ret = builder.CreatePHI(resultT, countInstances, HINT("reverse")); llvm::BasicBlock* blockDefault = nullptr; for (int instanceId = 0; instanceId < countInstances; ++instanceId) { llvm::BasicBlock *blockCase = llvm::BasicBlock::Create( llvm->llvmContext, "case" + std::to_string(instanceId), function->raw); if(instanceId == 0) blockDefault = blockCase; builder.SetInsertPoint(blockCase); - //assign bindings - + //assign guard values const Expression& instanceE = domInstances.at(instanceId); - functionI12n->getScope(keyS.scope)->overrideBindings({ - {instanceE, keyS.identifier} - }); + __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, transcend](const SymbolPacked & key) { - return __scopeI12n->processSymbol(transcend->unpack(key)); + [this, scopeI12n, transcend](const SymbolPacked & key) { + if (__dictGuardDefinitions.count(key)){ + return __dictGuardDefinitions.at(key); + } + return scopeI12n->processSymbol(transcend->unpack(key)); }); return result; } } -} \ No newline at end of file +} diff --git a/cpp/src/compilation/latereasoning.h b/cpp/src/compilation/latereasoning.h index a065fde..c88d298 100644 --- a/cpp/src/compilation/latereasoning.h +++ b/cpp/src/compilation/latereasoning.h @@ -1,68 +1,72 @@ /* * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * File: latereasoning.h * Author: pgess * * Created on May 26, 2018, 3:44 PM */ #ifndef CMPLLATEREASONING_H #define CMPLLATEREASONING_H #include "ast.h" #include "aux/latereasoning.h" #include "pass/compilepass.h" #include "llvmlayer.h" #include "transcendlayer.h" +#include "targets.h" namespace xreate{ namespace interpretation{ -class InterpretationScope; +class InterpretationFunction; } } namespace llvm{ class Value; } namespace xreate{ namespace latereasoning{ typedef std::function CompilerHandler; typedef std::function Handler; class LateReasoningCompiler{ public: - LateReasoningCompiler(interpretation::InterpretationScope* scope, - compilation::Context ctx) - : __context(ctx), __scopeI12n(scope) {} - + + 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); + llvm::Type* resultT, + const std::string& hint, + Handler handler); private: compilation::Context __context; - interpretation::InterpretationScope* __scopeI12n; + interpretation::InterpretationFunction* __fnI12n; + 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.h b/cpp/src/compilation/latex.h index e5c7fc1..339b82e 100644 --- a/cpp/src/compilation/latex.h +++ b/cpp/src/compilation/latex.h @@ -1,135 +1,140 @@ /* * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ /* * Author: pgess * Created on June 23, 2018, 2:51 PM * * \file latex.h * \brief latex */ #ifndef LATEX_H #define LATEX_H #include "compilation/latereasoning.h" #include "compilation/interpretation-instructions.h" #include "query/latex.h" #include "pass/compilepass.h" #include "analysis/interpretation.h" +#include "compilation/targetinterpretation.h" namespace xreate{ namespace latex{ ExpandedType getSubjectDomain(const std::string& subject, LatexQuery* query); /** \brief Latex(Late Context)-enabled decorator for IFunctionUnit * \extends IFunctionUnit */ template class LatexBruteFunctionDecorator: public Parent{ public: LatexBruteFunctionDecorator(ManagedFnPtr f, CompilePass* p) : Parent(f, p){ __query = reinterpret_cast (Parent::pass->man->transcend->getQuery(QueryId::LatexQuery)); } protected: std::vector prepareSignature(){ std::vector&& signature = Parent::prepareSignature(); const Demand& demand = __query->getFnDemand(Parent::function->getName()); signature.reserve(signature.size() + demand.size()); - + + 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)); + 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; }; 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; }; 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(scopeIntrpr, ctx); + = new latereasoning::LateReasoningCompiler(dynamic_cast(scopeIntrpr->function), ctx); llvm::Value* subjectRaw = compiler->compileAutoExpand( decision, subjectTRaw, subject, [&](const Gringo::Symbol & decisionRaw){ const Expression& decisionE = interpretation::representTransExpression( decisionRaw.args()[2], subjectT, Parent::pass->man->transcend); Attachments::put(decisionE, subjectT); return Parent::process(decisionE, subject); }); argsLatex.push_back(subjectRaw); } return new ExtraArgsFnInvocation(std::move(argsLatex), invocDefault); } }; } } //end of namespace xreate::context #endif /* LATEX_H */ diff --git a/cpp/src/compilation/polymorph.h b/cpp/src/compilation/polymorph.h index e49d7bd..def1bc1 100644 --- a/cpp/src/compilation/polymorph.h +++ b/cpp/src/compilation/polymorph.h @@ -1,95 +1,96 @@ /* * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * File: polymorphcompiler.h * Author: pgess * * Created on October 7, 2017 */ #ifndef POLYMORPHCOMPILER_H #define POLYMORPHCOMPILER_H #include "pass/compilepass.h" #include "query/polymorph.h" #include "compilation/latereasoning.h" +#include "compilation/targetinterpretation.h" namespace xreate{ namespace polymorph{ typedef Expression Selector; class PolymorphFnInvocation: public compilation::IFnInvocation{ public: PolymorphFnInvocation(const latereasoning::LateAnnotation& selector, std::list calleeSpecializations, CompilePass* pass, PolymorphQuery* query, LLVMLayer* llvm, latereasoning::LateReasoningCompiler* compiler); llvm::Value* operator()(std::vector&& args, const std::string& hintDecl = ""); private: latereasoning::LateAnnotation __selector; std::list __calleeSpecializations; CompilePass* __pass; PolymorphQuery* __query; LLVMLayer* __llvm; latereasoning::LateReasoningCompiler* __compiler; }; template class PolymorphCodeScopeUnit: public Parent{ public: PolymorphCodeScopeUnit(const CodeScope * const codeScope, compilation::IFunctionUnit* f, CompilePass* compilePass) : Parent(codeScope, f, compilePass){ } protected: compilation::IFnInvocation* findFunction(const Expression& opCall) override{ // //Check does invocation require guards satisfaction const std::string& nameCallee = opCall.getValueString(); const std::list& specializations = Parent::pass->man->root->getFunctionSpecializations(nameCallee); //Extern function if(specializations.size() == 0){ return Parent::findFunction(opCall); } //No other specializations. Check if it has no guard if(specializations.size() == 1){ if(!specializations.front()->guard.isValid()){ return Parent::findFunction(opCall); } } //Several specializations PolymorphQuery* query = dynamic_cast ( Parent::pass->man->transcend->getQuery(QueryId::PolymorphQuery)); const latereasoning::LateAnnotation& selector = query->get(opCall); compilation::Context ctx{this, Parent::function, Parent::pass}; interpretation::InterpretationScope* scopeIntrpr = Parent::pass->targetInterpretation->transformContext(ctx); latereasoning::LateReasoningCompiler* compiler - = new latereasoning::LateReasoningCompiler(scopeIntrpr, ctx); + = new latereasoning::LateReasoningCompiler(dynamic_cast(scopeIntrpr->function), ctx); return new PolymorphFnInvocation(selector, specializations, Parent::pass, query, Parent::pass->man->llvm, compiler); } }; } } //end of xreate::polymorph #endif /* POLYMORPHCOMPILER_H */ diff --git a/cpp/src/compilation/scopedecorators.h b/cpp/src/compilation/scopedecorators.h index 9dfe62d..cf26986 100644 --- a/cpp/src/compilation/scopedecorators.h +++ b/cpp/src/compilation/scopedecorators.h @@ -1,157 +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/. * * File: scopedecorators.h * Author: pgess * * Created on February 24, 2017, 11:35 AM */ /** * \file scopedecorators.h * \brief Basic code block compilation xreate::compilation::ICodeScopeUnit decorators */ #ifndef SCOPEDECORATORS_H #define SCOPEDECORATORS_H #include "ast.h" #include "compilation/targetinterpretation.h" #include "compilation/versions.h" #include "compilation/transformations.h" #include "compilation/polymorph.h" +#include "compilation/latex.h" +#include "analysis/typeinference.h" #include namespace xreate { class CompilePass; namespace compilation { class ICodeScopeUnit; class IFunctionUnit; /**\brief Caching ability for code scope compilation * \extends xreate::compilation::ICodeScopeUnit */ template class CachedScopeDecorator: public Parent{ typedef CachedScopeDecorator SELF; public: CachedScopeDecorator(const CodeScope* const codeScope, IFunctionUnit* f, CompilePass* compilePass): Parent(codeScope, f, compilePass){} Symbol bindArg(llvm::Value* value, std::string&& alias) { //ensure existence of an alias assert(Parent::scope->__identifiers.count(alias)); //memorize new value for an alias ScopedSymbol id{Parent::scope->__identifiers.at(alias), versions::VERSION_NONE}; __rawVars[id] = value; return Symbol{id, Parent::scope}; } void bindArg(llvm::Value* value, const ScopedSymbol& s) { __rawVars[s] = value; } llvm::Value* compile(const std::string& hintBlockDecl="") override{ if (__rawVars.count(ScopedSymbol::RetSymbol)){ return __rawVars[ScopedSymbol::RetSymbol]; } return Parent::compile(hintBlockDecl); } llvm::Value* processSymbol(const Symbol& s, std::string hintRetVar) override{ const CodeScope* scope = s.scope; SELF* self = dynamic_cast(Parent::function->getScopeUnit(scope)); if (self->__rawVars.count(s.identifier)){ return self->__rawVars[s.identifier]; } //Declaration could be overriden /* Expression declaration = CodeScope::getDefinition(s, true); if (!declaration.isDefined()){ assert(__declarationsOverriden.count(s.identifier)); declaration = __declarationsOverriden[s.identifier]; } else { (false); //in case of binding there should be raws provided. } } */ llvm::Value* resultRaw = Parent::processSymbol(s, hintRetVar); self->__rawVars.emplace(s.identifier, resultRaw); return resultRaw; } void overrideDeclarations(std::list> bindings){ reset(); for (auto entry: bindings){ SELF* self = dynamic_cast(Parent::function->getScopeUnit(entry.first.scope)); assert(self == this); self->__declarationsOverriden.emplace(entry.first.identifier, entry.second); } } void registerChildScope(std::shared_ptr scope){ __childScopes.push_back(scope); } void reset(){ __rawVars.clear(); __declarationsOverriden.clear(); __childScopes.clear(); } private: std::unordered_map __declarationsOverriden; std::unordered_map __rawVars; std::list> __childScopes; }; +template +class TypeConversionScopeDecorator: public Parent { +public: + TypeConversionScopeDecorator(const CodeScope* const codeScope, IFunctionUnit* f, CompilePass* compilePass): Parent(codeScope, f, compilePass){} + + llvm::Value* process(const Expression& expr, const std::string& hintVarDecl="") override { + llvm::Value* resultR = Parent::process(expr, hintVarDecl); + + if(!expr.type.isValid()) { + return resultR; + } + + ExpandedType exprT = Parent::pass->man->root->getType(expr); + llvm::Type* exprTR = Parent::pass->man->llvm->toLLVMType(exprT); + return typeinference::doAutomaticTypeConversion(resultR, exprTR, Parent::pass->man->llvm->builder); + } +}; + /**\brief Default code scope compilation functionality*/ typedef CachedScopeDecorator< + TypeConversionScopeDecorator< + latex::LatexBruteScopeDecorator< polymorph::PolymorphCodeScopeUnit< - ::xreate::compilation::TransformationsScopeDecorator< + compilation::TransformationsScopeDecorator< interpretation::InterpretationScopeDecorator< - versions::VersionsScopeDecorator>>>> + versions::VersionsScopeDecorator>>>>>> DefaultCodeScopeUnit; } //end of compilation namespace struct CachedScopeDecoratorTag; struct VersionsScopeDecoratorTag; template<> struct DecoratorsDict{ typedef compilation::CachedScopeDecorator< + compilation::TypeConversionScopeDecorator< + latex::LatexBruteScopeDecorator< polymorph::PolymorphCodeScopeUnit< compilation::TransformationsScopeDecorator< interpretation::InterpretationScopeDecorator< - versions::VersionsScopeDecorator>>>> result; + versions::VersionsScopeDecorator>>>>>> + + result; }; template<> struct DecoratorsDict{ typedef versions::VersionsScopeDecorator< compilation::BasicCodeScopeUnit> result; }; } //end of xreate #endif /* SCOPEDECORATORS_H */ diff --git a/cpp/src/compilation/targetinterpretation.cpp b/cpp/src/compilation/targetinterpretation.cpp index 9314a6c..31da3ea 100644 --- a/cpp/src/compilation/targetinterpretation.cpp +++ b/cpp/src/compilation/targetinterpretation.cpp @@ -1,597 +1,628 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * File: targetinterpretation.cpp * Author: pgess * * Created on June 29, 2016, 6:45 PM */ /** * \file targetinterpretation.h * \brief Interpretation support. See more [details on Interpretation](/w/concepts/dsl/) */ #include "compilation/targetinterpretation.h" #include "pass/interpretationpass.h" #include "analysis/typeinference.h" #include "llvmlayer.h" #include "compilation/scopedecorators.h" #include "compilation/interpretation-instructions.h" #include #include #include using namespace std; using namespace xreate::compilation; -namespace xreate{ namespace interpretation{ +namespace xreate{ +namespace interpretation{ const Expression EXPRESSION_FALSE = Expression(Atom(0)); const Expression EXPRESSION_TRUE = Expression(Atom(1)); CodeScope* -InterpretationScope::processOperatorIf(const Expression& expression){ +InterpretationScope::processOperatorIf(const Expression& expression) { const Expression& exprCondition = process(expression.getOperands()[0]); - if (exprCondition == EXPRESSION_TRUE){ + if (exprCondition == EXPRESSION_TRUE) { return expression.blocks.front(); } return expression.blocks.back(); } CodeScope* InterpretationScope::processOperatorSwitch(const Expression& expression) { const Expression& exprCondition = process(expression.operands[0]); bool flagHasDefault = expression.operands[1].op == Operator::CASE_DEFAULT; //TODO check that one and only one case variant is appropriate - for (size_t size = expression.operands.size(), i= flagHasDefault? 2: 1; igetScope((const CodeScope*) exprCase.blocks.front())->processScope() == exprCondition){ + if (function->getScope((const CodeScope*) exprCase.blocks.front())->processScope() == exprCondition) { return exprCase.blocks.back(); } } - if (flagHasDefault){ + if (flagHasDefault) { const Expression& exprCaseDefault = expression.operands[1]; return exprCaseDefault.blocks.front(); } assert(false && "Switch has no appropriate variant"); return nullptr; } CodeScope* -InterpretationScope::processOperatorSwitchVariant(const Expression& expression){ +InterpretationScope::processOperatorSwitchVariant(const Expression& expression) { const Expression& condition = process(expression.operands.at(0)); assert(condition.op == Operator::VARIANT); const string& identCondition = expression.bindings.front(); Expression opExpected(Atom(condition.getValueDouble())); auto itFoundValue = std::find(++expression.operands.begin(), expression.operands.end(), opExpected); assert(itFoundValue != expression.operands.end()); - int indexBlock = itFoundValue - expression.operands.begin() -1; + int indexBlock = itFoundValue - expression.operands.begin() - 1; auto blockFound = expression.blocks.begin(); std::advance(blockFound, indexBlock); InterpretationScope* scopeI12n = function->getScope(*blockFound); - if(condition.operands.size()){ - const Expression& value=condition.operands.at(0); + if(condition.operands.size()) { + const Expression& value = condition.operands.at(0); scopeI12n->overrideBindings({ - {value, identCondition}}); - } + {value, identCondition} + }); + } return *blockFound; } llvm::Value* -InterpretationScope::compileHybrid(const InterpretationOperator& op, const Expression& expression, const Context& context){ - switch(op){ - case IF_INTERPRET_CONDITION: { - CodeScope* scopeResult = processOperatorIf(expression); +InterpretationScope::processLate(const InterpretationOperator& op, const Expression& expression, const Context& context) { + switch(op) { + case IF_INTERPRET_CONDITION: + { + CodeScope* scopeResult = processOperatorIf(expression); + + llvm::Value* result = context.function->getScopeUnit(scopeResult)->compile(); + return result; + } - llvm::Value* result = context.function->getScopeUnit(scopeResult)->compile(); - return result; - } + case SWITCH_INTERPRET_CONDITION: + { + CodeScope* scopeResult = processOperatorSwitch(expression); - case SWITCH_INTERPRET_CONDITION:{ - CodeScope* scopeResult = processOperatorSwitch(expression); + llvm::Value* result = context.function->getScopeUnit(scopeResult)->compile(); + return result; + } - llvm::Value* result = context.function->getScopeUnit(scopeResult)->compile(); - return result; + case SWITCH_VARIANT: + { + CodeScope* scopeResult = processOperatorSwitchVariant(expression); + const Expression& condition = expression.operands.at(0); + const Expression& valueCondition = process(condition); + + const string identCondition = expression.bindings.front(); + auto scopeCompilation = Decorators::getInterface(context.function->getScopeUnit(scopeResult)); + + if(valueCondition.operands.size()) { + //override value + Symbol symbCondition{ScopedSymbol{scopeResult->__identifiers.at(identCondition), versions::VERSION_NONE}, scopeResult}; + scopeCompilation->overrideDeclarations({ + {symbCondition, Expression(valueCondition.operands.at(0))}} + ); + + //set correct type for binding: + TypeAnnotation typeVariant = typeinference::getType(condition, *function->man->ast); + int conditionIndex = valueCondition.getValueDouble(); + ScopedSymbol symbolInternal = scopeResult->getSymbol(identCondition); + scopeResult->__declarations[symbolInternal].bindType(typeVariant.__operands.at(conditionIndex)); } - case SWITCH_VARIANT: { - CodeScope* scopeResult = processOperatorSwitchVariant(expression); - const Expression& condition = expression.operands.at(0); - const Expression& valueCondition = process(condition); - - const string identCondition = expression.bindings.front(); - auto scopeCompilation = Decorators::getInterface(context.function->getScopeUnit(scopeResult)); - - if(valueCondition.operands.size()){ - //override value - Symbol symbCondition{ScopedSymbol{scopeResult->__identifiers.at(identCondition), versions::VERSION_NONE}, scopeResult}; - scopeCompilation->overrideDeclarations( - {{symbCondition, Expression(valueCondition.operands.at(0))}} - ); - - //set correct type for binding: - TypeAnnotation typeVariant = typeinference::getType(condition, *function->man->ast); - int conditionIndex = valueCondition.getValueDouble(); - ScopedSymbol symbolInternal = scopeResult->getSymbol(identCondition); - scopeResult->__declarations[symbolInternal].bindType(typeVariant.__operands.at(conditionIndex)); - } - - llvm::Value* result = context.function->getScopeUnit(scopeResult)->compile(); - return result; - } - - case SWITCH_LATE: { - latereasoning::LateReasoningCompiler compiler(this, context); - return compiler.processSwitchLateStatement(expression, ""); - } + llvm::Value* result = context.function->getScopeUnit(scopeResult)->compile(); + return result; + } - case FOLD_INTERPRET_INPUT: { - //initialization - const Expression& exprInput = process(expression.getOperands()[0]); - assert(exprInput.op == Operator::LIST); + case SWITCH_LATE: + { + latereasoning::LateReasoningCompiler compiler(dynamic_cast(this->function), context); + return compiler.processSwitchLateStatement(expression, ""); + } - CodeScope* scopeBody = expression.blocks.front(); + case FOLD_INTERPRET_INPUT: + { + //initialization + const Expression& exprInput = process(expression.getOperands()[0]); + assert(exprInput.op == Operator::LIST); - const string& nameEl = expression.bindings[0]; - Symbol symbEl{ScopedSymbol{scopeBody->__identifiers.at(nameEl), versions::VERSION_NONE}, scopeBody}; - const std::string& idAccum = expression.bindings[1]; - llvm::Value* rawAccum = context.scope->process(expression.getOperands()[1]); + CodeScope* scopeBody = expression.blocks.front(); - InterpretationScope* intrBody = function->getScope(scopeBody); - auto unitBody = Decorators::getInterface(context.function->getScopeUnit(scopeBody)); + const string& nameEl = expression.bindings[0]; + Symbol symbEl{ScopedSymbol{scopeBody->__identifiers.at(nameEl), versions::VERSION_NONE}, scopeBody}; + const std::string& idAccum = expression.bindings[1]; + llvm::Value* rawAccum = context.scope->process(expression.getOperands()[1]); - const std::vector elementsInput= exprInput.getOperands(); + InterpretationScope* intrBody = function->getScope(scopeBody); + auto unitBody = Decorators::getInterface(context.function->getScopeUnit(scopeBody)); - for(size_t i=0; i elementsInput = exprInput.getOperands(); - intrBody->overrideBindings({ - {exprElement, nameEl}}); - unitBody->overrideDeclarations({ - {symbEl, exprElement}}); //resets unitBody - unitBody->bindArg(rawAccum, string(idAccum)); + for(size_t i = 0; i < elementsInput.size(); ++i) { + const Expression& exprElement = elementsInput[i]; - rawAccum=unitBody->compile(); - } + intrBody->overrideBindings({ + {exprElement, nameEl} + }); + unitBody->overrideDeclarations({ + {symbEl, exprElement} + }); //resets unitBody + unitBody->bindArg(rawAccum, string(idAccum)); - return rawAccum; + rawAccum = unitBody->compile(); } - /* - case FOLD_INF_INTERPRET_INOUT{ - } - */ + return rawAccum; + } + +// case FOLD_INF_INTERPRET_INOUT: +// { +// } //TODO refactor as InterpretationCallStatement class - case CALL_INTERPRET_PARTIAL: { - const std::string &calleeName = expression.getValueString(); - ICodeScopeUnit* scopeUnitSelf = context.scope; - ManagedFnPtr callee = this->function->man->ast->findFunction(calleeName); - const FunctionInterpretationData& calleeData = FunctionInterpretationHelper::getSignature(callee); - std::vector argsActual; - PIFSignature sig; - sig.declaration = callee; - - for(size_t no=0, size = expression.operands.size(); no < size; ++no){ - const Expression& op = expression.operands[no]; - - if (calleeData.signature.at(no) == INTR_ONLY){ - sig.bindings.push_back(process(op)); - continue; - } - - argsActual.push_back(scopeUnitSelf->process(op)); + case CALL_INTERPRET_PARTIAL: + { + const std::string &calleeName = expression.getValueString(); + ICodeScopeUnit* scopeUnitSelf = context.scope; + ManagedFnPtr callee = this->function->man->ast->findFunction(calleeName); + const FunctionInterpretationData& calleeData = FunctionInterpretationHelper::getSignature(callee); + std::vector argsActual; + PIFSignature sig; + sig.declaration = callee; + + for(size_t no = 0, size = expression.operands.size(); no < size; ++no) { + const Expression& op = expression.operands[no]; + + if (calleeData.signature.at(no) == INTR_ONLY) { + sig.bindings.push_back(process(op)); + continue; } - TargetInterpretation* man = dynamic_cast(this->function->man); - PIFunction* pifunction = man->getFunction(move(sig)); - - llvm::Function* raw = pifunction->compile(); - boost::scoped_ptr statement(new RawFnInvocation(raw, man->pass->man->llvm)); - return (*statement)(move(argsActual)); + argsActual.push_back(scopeUnitSelf->process(op)); } - default: break; + TargetInterpretation* man = dynamic_cast (this->function->man); + PIFunction* pifunction = man->getFunction(move(sig)); + + llvm::Function* raw = pifunction->compile(); + boost::scoped_ptr statement(new RawFnInvocation(raw, man->pass->man->llvm)); + return (*statement)(move(argsActual)); + } + + case QUERY_LATE: + { + return IntrinsicQueryInstruction( + dynamic_cast(this->function)) + .processLate(expression, context); } - assert(false&& "Unknown hybrid operator"); + default: break; + } + + assert(false && "Unknown late interpretation operator"); return nullptr; } llvm::Value* -InterpretationScope::compile(const Expression& expression, const Context& context){ +InterpretationScope::compile(const Expression& expression, const Context& context) { const InterpretationData& data = Attachments::get(expression); - if (data.op != InterpretationOperator::NONE){ - return compileHybrid(data.op, expression, context); + if (data.op != InterpretationOperator::NONE) { + return processLate(data.op, expression, context); } Expression result = process(expression); return context.scope->process(result); } Expression InterpretationScope::process(const Expression& expression) { #ifndef NDEBUG - if (expression.tags.count("bpoint")){ + if (expression.tags.count("bpoint")) { std::raise(SIGINT); } #endif PassManager* man = (static_cast (function->man))->pass->man; - switch (expression.__state){ - case Expression::INVALID: - assert(false); + switch (expression.__state) { + case Expression::INVALID: + assert(false); - case Expression::NUMBER: - case Expression::STRING: - return expression; + case Expression::NUMBER: + case Expression::STRING: + return expression; - case Expression::IDENT:{ - Symbol s = Attachments::get(expression); - return Parent::processSymbol(s); - } + case Expression::IDENT: + { + Symbol s = Attachments::get(expression); + return Parent::processSymbol(s); + } - case Expression::COMPOUND: - break; + case Expression::COMPOUND: + break; - default: assert(false); + default: assert(false); } switch (expression.op) { - case Operator::EQU: { - const Expression& left = process(expression.operands[0]); - const Expression& right = process(expression.operands[1]); + case Operator::EQU: + { + const Expression& left = process(expression.operands[0]); + const Expression& right = process(expression.operands[1]); - if (left == right) return EXPRESSION_TRUE; - return EXPRESSION_FALSE; - } + if (left == right) return EXPRESSION_TRUE; + return EXPRESSION_FALSE; + } - case Operator::NE: { - const Expression& left = process(expression.operands[0]); - const Expression& right = process(expression.operands[1]); + case Operator::NE: + { + const Expression& left = process(expression.operands[0]); + const Expression& right = process(expression.operands[1]); - if (left == right) return EXPRESSION_FALSE; - return EXPRESSION_TRUE; - } + if (left == right) return EXPRESSION_FALSE; + return EXPRESSION_TRUE; + } - case Operator::LOGIC_AND: { - assert(expression.operands.size() == 1); - return process (expression.operands[0]); - } + case Operator::LOGIC_AND: + { + assert(expression.operands.size() == 1); + return process (expression.operands[0]); + } -// case Operator::LOGIC_OR: - case Operator::CALL: { - const std::string &fnName = expression.getValueString(); - ManagedFnPtr fnAst = this->function->man->ast->findFunction(fnName); - InterpretationFunction* fnUnit = this->function->man->getFunction(fnAst); + // case Operator::LOGIC_OR: + case Operator::CALL: + { + const std::string &fnName = expression.getValueString(); + ManagedFnPtr fnAst = this->function->man->ast->findFunction(fnName); + InterpretationFunction* fnUnit = this->function->man->getFunction(fnAst); - vector args; - args.reserve(expression.getOperands().size()); + vector args; + args.reserve(expression.getOperands().size()); - for(size_t i=0, size = expression.getOperands().size(); iprocess(args); + for(size_t i = 0, size = expression.getOperands().size(); i < size; ++i) { + args.push_back(process(expression.getOperands()[i])); } - case Operator::CALL_INTRINSIC: { - std::string nameFunction = expression.getValueString(); - - if(nameFunction=="query"){ - return IntrinsicQueryInstruction(this).process(expression); - - } else if(nameFunction=="query_scope"){ - ScopePacked scopeId = man->transcend->pack(scope); - Expression result(Operator::VARIANT, {Expression(scopeId)}); - result.setValueDouble(0); - return result; + return fnUnit->process(args); + } - } else { - assert(false && "Unknown intrinsic"); - } - } + case Operator::CALL_INTRINSIC: + { + assert(false && "Unknown intrinsic"); + } - case Operator::IF:{ - CodeScope* scopeResult = processOperatorIf(expression); - return function->getScope(scopeResult)->processScope(); - } + case Operator::QUERY: + { + return IntrinsicQueryInstruction(dynamic_cast(this->function)) + .process(expression); + } + + case Operator::QUERY_LATE: + { + assert(false && "Can't be interpretated"); + return Expression(); + } - case Operator::SWITCH: { - CodeScope* scopeResult = processOperatorSwitch(expression); - return function->getScope(scopeResult)->processScope(); - } + case Operator::IF: + { + CodeScope* scopeResult = processOperatorIf(expression); + return function->getScope(scopeResult)->processScope(); + } - case Operator::SWITCH_VARIANT: { - CodeScope* scopeResult = processOperatorSwitchVariant(expression); - return function->getScope(scopeResult)->processScope(); - } + case Operator::SWITCH: + { + CodeScope* scopeResult = processOperatorSwitch(expression); + return function->getScope(scopeResult)->processScope(); + } - case Operator::VARIANT: { - if(!expression.operands.size()) return expression; + case Operator::SWITCH_VARIANT: + { + CodeScope* scopeResult = processOperatorSwitchVariant(expression); + return function->getScope(scopeResult)->processScope(); + } - Expression variantData = process(expression.operands[0]); - Expression result{Operator::VARIANT, {variantData}}; - result.setValueDouble(expression.getValueDouble()); - return result; - } + case Operator::VARIANT: + { + if(!expression.operands.size()) return expression; - case Operator::INDEX: { - Expression exprData = process(expression.operands[0]); + Expression variantData = process(expression.operands[0]); + Expression result{Operator::VARIANT, {variantData}}; + result.setValueDouble(expression.getValueDouble()); + return result; + } - for (size_t keyId=1; keyIdgetScope(expression.blocks.front()); + const std::string& argEl = expression.bindings[0]; + const std::string& argAccum = expression.bindings[1]; - Expression accum = exprInit; - for(size_t size=exprInput.getOperands().size(), i=0; ioverrideBindings({ - {exprInput.getOperands()[i], argEl}, - {accum, argAccum} - }); + InterpretationScope* body = function->getScope(expression.blocks.front()); - accum = body->processScope(); - } + Expression accum = exprInit; + for(size_t size = exprInput.getOperands().size(), i = 0; i < size; ++i) { + body->overrideBindings({ + {exprInput.getOperands()[i], argEl}, + {accum, argAccum} + }); - return accum; - } + accum = body->processScope(); + } - case Operator::LIST: - case Operator::LIST_NAMED: - case Operator::LIST_RANGE: - { - Expression result(expression.op,{}); - result.operands.resize(expression.operands.size()); - result.bindings=expression.bindings; - result.__indexBindings=expression.__indexBindings; + return accum; + } - int keyId=0; - for(const Expression& opCurrent : expression.operands) { - result.operands[keyId++]=process(opCurrent); - } + case Operator::LIST: + case Operator::LIST_NAMED: + case Operator::LIST_RANGE: + { + Expression result(expression.op,{}); + result.operands.resize(expression.operands.size()); + result.bindings = expression.bindings; + result.__indexBindings = expression.__indexBindings; + + int keyId = 0; + for(const Expression& opCurrent : expression.operands) { + result.operands[keyId++] = process(opCurrent); + } - return result; - } + return result; + } -// case Operator::MAP: { -// break; -// } + // case Operator::MAP: { + // break; + // } - default: break; + default: break; } return expression; } InterpretationFunction* -TargetInterpretation::getFunction(IFunctionUnit* unit){ +TargetInterpretation::getFunction(IFunctionUnit* unit) { if (__dictFunctionsByUnit.count(unit)) { return __dictFunctionsByUnit.at(unit); } InterpretationFunction* f = new InterpretationFunction(unit->function, this); __dictFunctionsByUnit.emplace(unit, f); assert(__functions.emplace(unit->function.id(), f).second); return f; } PIFunction* -TargetInterpretation::getFunction(PIFSignature&& sig){ +TargetInterpretation::getFunction(PIFSignature&& sig) { auto f = __pifunctions.find(sig); - if (f != __pifunctions.end()){ + if (f != __pifunctions.end()) { return f->second; } PIFunction* result = new PIFunction(PIFSignature(sig), __pifunctions.size(), this); __pifunctions.emplace(move(sig), result); assert(__dictFunctionsByUnit.emplace(result->functionUnit, result).second); return result; } InterpretationScope* -TargetInterpretation::transformContext(const Context& c){ +TargetInterpretation::transformContext(const Context& c) { return this->getFunction(c.function)->getScope(c.scope->scope); } llvm::Value* -TargetInterpretation::compile(const Expression& expression, const Context& ctx){ +TargetInterpretation::compile(const Expression& expression, const Context& ctx) { return transformContext(ctx)->compile(expression, ctx); } InterpretationFunction::InterpretationFunction(const ManagedFnPtr& function, Target* target) - : Function(function, target) -{} +: Function(function, target) { } Expression -InterpretationFunction::process(const std::vector& args){ +InterpretationFunction::process(const std::vector& args) { InterpretationScope* body = getScope(__function->__entry); list> bindings; - for(size_t i=0, size=args.size(); iscope->__bindings.at(i))); } body->overrideBindings(bindings); return body->processScope(); } // Partial function interpretation typedef BasicFunctionUnit PIFunctionUnitParent; -class PIFunctionUnit : public PIFunctionUnitParent { +class PIFunctionUnit : public PIFunctionUnitParent{ public: PIFunctionUnit(ManagedFnPtr f, std::set&& arguments, size_t id, CompilePass* p) : PIFunctionUnitParent(f, p), argumentsActual(move(arguments)), __id(id) { } protected: - std::vector prepareArguments(){ + + std::vector + prepareArguments() { LLVMLayer* llvm = PIFunctionUnitParent::pass->man->llvm; AST* ast = PIFunctionUnitParent::pass->man->root; CodeScope* entry = PIFunctionUnitParent::function->__entry; std::vector signature; - for(size_t no: argumentsActual){ + for(size_t no : argumentsActual) { VNameId argId = entry->__identifiers.at(entry->__bindings.at(no)); ScopedSymbol arg{argId, versions::VERSION_NONE}; signature.push_back(llvm->toLLVMType(ast->expandType(entry->__declarations.at(arg).type))); } return signature; } - llvm::Function::arg_iterator prepareBindings(){ + llvm::Function::arg_iterator + prepareBindings() { CodeScope* entry = PIFunctionUnitParent::function->__entry; ICodeScopeUnit* entryCompilation = PIFunctionUnitParent::getScopeUnit(entry); llvm::Function::arg_iterator fargsI = PIFunctionUnitParent::raw->arg_begin(); - for(size_t no: argumentsActual){ + for(size_t no : argumentsActual) { ScopedSymbol arg{entry->__identifiers.at(entry->__bindings.at(no)), versions::VERSION_NONE}; entryCompilation->bindArg(&*fargsI, arg); fargsI->setName(entry->__bindings.at(no)); ++fargsI; } return fargsI; } - virtual std::string prepareName(){ + virtual std::string + prepareName() { return PIFunctionUnitParent::prepareName() + "_" + std::to_string(__id); } private: std::set argumentsActual; size_t __id; -}; +} ; PIFunction::PIFunction(PIFSignature&& sig, size_t id, TargetInterpretation* target) : InterpretationFunction(sig.declaration, target), signatureInstance(move(sig)) { const FunctionInterpretationData& functionData = FunctionInterpretationHelper::getSignature(signatureInstance.declaration); std::set argumentsActual; - for (size_t no=0, size=functionData.signature.size(); no < size; ++no){ - if (functionData.signature.at(no) != INTR_ONLY){ + for (size_t no = 0, size = functionData.signature.size(); no < size; ++no) { + if (functionData.signature.at(no) != INTR_ONLY) { argumentsActual.insert(no); } } functionUnit = new PIFunctionUnit(signatureInstance.declaration, move(argumentsActual), id, target->pass); CodeScope* entry = signatureInstance.declaration->__entry; auto entryUnit = Decorators::getInterface<>(functionUnit->getEntry()); InterpretationScope* entryIntrp = InterpretationFunction::getScope(entry); list> bindingsPartial; list> declsPartial; - for(size_t no=0, sigNo=0, size=entry->__bindings.size(); no__bindings.size(); no < size; ++no) { + if(functionData.signature.at(no) == INTR_ONLY) { bindingsPartial.push_back({signatureInstance.bindings[sigNo], entry->__bindings[no]}); - VNameId argId=entry->__identifiers.at(entry->__bindings[no]); + VNameId argId = entry->__identifiers.at(entry->__bindings[no]); Symbol argSymbol{ScopedSymbol {argId, versions::VERSION_NONE}, entry}; declsPartial.push_back({argSymbol, signatureInstance.bindings[sigNo]}); ++sigNo; } } entryIntrp->overrideBindings(bindingsPartial); entryUnit->overrideDeclarations(declsPartial); } llvm::Function* -PIFunction::compile(){ +PIFunction::compile() { llvm::Function* raw = functionUnit->compile(); return raw; } -bool operator<(const PIFSignature& lhs, const PIFSignature& rhs){ +bool operator<(const PIFSignature& lhs, const PIFSignature& rhs) { if (lhs.declaration.id() != rhs.declaration.id()) { return lhs.declaration.id() < rhs.declaration.id(); } return lhs.bindings < rhs.bindings; } -bool operator<(const PIFSignature& lhs, PIFunction* const rhs){ +bool operator<(const PIFSignature& lhs, PIFunction * const rhs) { return lhs < rhs->signatureInstance; } -bool operator<(PIFunction* const lhs, const PIFSignature& rhs){ +bool operator<(PIFunction * const lhs, const PIFSignature& rhs) { return lhs->signatureInstance < rhs; } -}} +} +} /** \class xreate::interpretation::InterpretationFunction * * Holds list of xreate::interpretation::InterpretationScope 's focused on interpretation of individual code scopes * * There is particulat subclass PIFunction intended to represent partially interpreted functions *\sa TargetInterpretation, [Interpretation Concept](/w/concepts/dfa) */ /** \class xreate::interpretation::TargetInterpretation * * Executed during compilation and intented to preprocess eligible parts of code. * Established on [Targets Infrastructure](\ref compilation::Target) * * Holds list of InterpretationFunction / PIFunction to represent interpretation process for individual functions * * In order to be activated during compilation process there is * InterpretationScopeDecorator implementation of ICodeScopeUnit * \sa InterpretationPass, compilation::Target, [Interpretation Concept](/w/concepts/dfa) * */ diff --git a/cpp/src/compilation/targetinterpretation.h b/cpp/src/compilation/targetinterpretation.h index ad9db20..867b2f4 100644 --- a/cpp/src/compilation/targetinterpretation.h +++ b/cpp/src/compilation/targetinterpretation.h @@ -1,130 +1,130 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * File: targetstatic.h * Author: pgess * * Created on July 2, 2016, 1:25 PM */ #ifndef TARGETSTATIC_H #define TARGETSTATIC_H #include "ast.h" #include "pass/compilepass.h" #include "compilation/targets.h" #include "pass/interpretationpass.h" #include "transcendlayer.h" namespace xreate{ namespace interpretation{ class TargetInterpretation; class InterpretationScope; class InterpretationFunction; }} namespace xreate{ namespace compilation{ template <> struct TargetInfo { typedef Expression Result; typedef interpretation::InterpretationScope Scope; typedef interpretation::InterpretationFunction Function; }; }} namespace xreate{ namespace interpretation{ /** \brief Encapsulates interpretation of a single Code Scope */ class InterpretationScope: public compilation::Scope{ typedef Scope Parent; public: InterpretationScope(const CodeScope* scope, compilation::Function* f): Parent(scope, f) {} Expression process(const Expression& expression) override; llvm::Value* compile(const Expression& expression, const compilation::Context& context); private: - llvm::Value* compileHybrid(const InterpretationOperator& op, const Expression& expression, const compilation::Context& context); + llvm::Value* processLate(const InterpretationOperator& op, const Expression& expression, const compilation::Context& context); //llvm::Value* compilePartialFnCall(const Expression& expression, const Context& context); CodeScope* processOperatorIf(const Expression& expression); CodeScope* processOperatorSwitch(const Expression& expression); CodeScope* processOperatorSwitchVariant(const Expression& expression); }; /** \brief Encapsulates interpretation of a single %Function */ class InterpretationFunction: public compilation::Function{ public: InterpretationFunction(const ManagedFnPtr& function, compilation::Target* target); Expression process(const std::vector& args); }; /** \brief Signature of a partially interpreted function */ struct PIFSignature{ ManagedFnPtr declaration; std::vector bindings; }; class PIFunctionUnit; /** \brief Partially interpreted function */ class PIFunction: public InterpretationFunction{ public: PIFunctionUnit* functionUnit; PIFSignature signatureInstance; PIFunction(PIFSignature&& sig, size_t id, TargetInterpretation* target); llvm::Function* compile(); }; bool operator<(const PIFSignature& lhs, PIFunction* const rhs); bool operator<(PIFunction* const lhs, const PIFSignature& rhs); /** \brief Encapsulates actual [Interpretation](/w/concepts/dfa) based on InterpretationPass analysis results */ class TargetInterpretation: public compilation::Target{ public: TargetInterpretation(AST* root, CompilePass* passCompilation): Target(root), pass(passCompilation){} //target: public: InterpretationFunction* getFunction(compilation::IFunctionUnit* unit); PIFunction* getFunction(PIFSignature&& sig); private: std::map __pifunctions; std::map __dictFunctionsByUnit; //self: public: CompilePass* pass; llvm::Value* compile(const Expression& expression, const compilation::Context& ctx); InterpretationScope* transformContext(const compilation::Context& c); private: }; /**\brief Interpretation-aware Code Scope decorator * \extends xreate::compilation::ICodeScopeUnit */ template class InterpretationScopeDecorator: public Parent{ public: InterpretationScopeDecorator(const CodeScope* const codeScope, compilation::IFunctionUnit* f, CompilePass* compilePass): Parent(codeScope, f, compilePass){} virtual llvm::Value* process(const Expression& expr, const std::string& hintVarDecl){ const InterpretationData& data = Attachments::get(expr, {ANY, NONE}); bool flagInterpretationEligible = (data.resolution == INTR_ONLY || data.op != InterpretationOperator::NONE); if (flagInterpretationEligible){ compilation::Context ctx{this, this->function, this->pass}; return Parent::pass->targetInterpretation->compile(expr, ctx); } return Parent::process(expr, hintVarDecl); } }; }} //end of xreate:: interpretation #endif /* TARGETSTATIC_H */ \ No newline at end of file diff --git a/cpp/src/llvmlayer.cpp b/cpp/src/llvmlayer.cpp index 5b59ffa..eb4228b 100644 --- a/cpp/src/llvmlayer.cpp +++ b/cpp/src/llvmlayer.cpp @@ -1,244 +1,244 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * llvmlayer.cpp * * Author: pgess */ /** * \file llvmlayer.h * \brief Wrapper over LLVM */ #include "ast.h" #include "llvmlayer.h" #include "ExternLayer.h" #include "llvm/ExecutionEngine/ExecutionEngine.h" #include "llvm/ExecutionEngine/MCJIT.h" #include "llvm/Support/TargetSelect.h" #include #include using namespace llvm; using namespace xreate; using namespace std; LLVMLayer::LLVMLayer(AST* root) : llvmContext(), builder(llvmContext), ast(root), module(new llvm::Module(root->getModuleName(), llvmContext)) { layerExtern = new ExternLayer(this); layerExtern->init(root); } 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() ); } void LLVMLayer::print() { llvm::PassManager PM; PM.addPass(llvm::PrintModulePass(llvm::outs(), "banner")); llvm::AnalysisManager aman; PM.run(*module.get(), aman); } void LLVMLayer::moveToGarbage(void *o) { __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: { 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_NAMED: { std::vector pack_; pack_.reserve(t.__operands.size()); std::transform(t.__operands.begin(), t.__operands.end(), std::inserter(pack_, pack_.end()), [this, &conjuctions](const TypeAnnotation & t) { return toLLVMType(ExpandedType(TypeAnnotation(t)), conjuctions); }); 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_NAMED) { return true; } if (t.__operator != TypeOperator::CUSTOM) { return false; } clang::QualType tqual = llvm->layerExtern->lookupType(t.__valueCustom); const clang::Type * raw = tqual.getTypePtr(); // TODO skip ALL the pointers until non-pointer type found 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_NAMED) ? t.get().fields : llvm->layerExtern->getStructFields( llvm->layerExtern->lookupType(t.get().__valueCustom)); } diff --git a/cpp/src/pass/compilepass.cpp b/cpp/src/pass/compilepass.cpp index 9d011d6..4ca0142 100644 --- a/cpp/src/pass/compilepass.cpp +++ b/cpp/src/pass/compilepass.cpp @@ -1,717 +1,737 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * Author: pgess * * compilepass.cpp */ /** * \file compilepass.h * \brief Compilation pass */ #include "compilepass.h" #include "transcendlayer.h" #include #include "llvmlayer.h" #include "query/containers.h" #include "compilation/containers.h" #include "ExternLayer.h" #include "compilation/targetinterpretation.h" #include "pass/versionspass.h" #include "compilation/scopedecorators.h" #include "compilation/operators.h" +#include "compilation/latex.h" #include "analysis/typeinference.h" #include #include #include using namespace std; using namespace llvm; -namespace xreate { namespace compilation{ +namespace xreate{ +namespace compilation{ std::string -BasicFunctionUnit::prepareName(){ +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; + 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)); + [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)); - }); + ScopedSymbol argid{entry->__identifiers.at(arg), versions::VERSION_NONE}; + return llvm->toLLVMType(ast->expandType(entry->__declarations.at(argid).type)); + }); return signature; } llvm::Type* BasicFunctionUnit::prepareResult() { LLVMLayer* llvm = IFunctionUnit::pass->man->llvm; AST* ast = IFunctionUnit::pass->man->root; CodeScope* entry = IFunctionUnit::function->__entry; return llvm->toLLVMType(ast->expandType(entry->__declarations.at(ScopedSymbol::RetSymbol).type)); } llvm::Function::arg_iterator BasicFunctionUnit::prepareBindings() { CodeScope* entry = IFunctionUnit::function->__entry; ICodeScopeUnit* entryCompilation = IFunctionUnit::getScopeUnit(entry); llvm::Function::arg_iterator fargsI = IFunctionUnit::raw->arg_begin(); for (std::string &arg : entry->__bindings) { ScopedSymbol argid{entry->__identifiers[arg], versions::VERSION_NONE}; entryCompilation->bindArg(&*fargsI, argid); fargsI->setName(arg); ++fargsI; } return fargsI; } - //DEBT compiler rigidly depends on exact definition of DefaultFunctionUnit -typedef BasicFunctionUnit BruteFunctionDefault; +//DEBT compiler rigidly depends on exact definition of DefaultFunctionUnit +typedef latex::LatexBruteFunctionDecorator< + compilation::BasicFunctionUnit> -ICodeScopeUnit::ICodeScopeUnit(const CodeScope* const codeScope, IFunctionUnit* f, CompilePass* compilePass) -: pass(compilePass), function(f), scope(codeScope), currentBlockRaw(nullptr) { -} + BruteFunctionDefault; + +ICodeScopeUnit::ICodeScopeUnit(const CodeScope * const codeScope, IFunctionUnit* f, CompilePass* compilePass) +: pass(compilePass), function(f), scope(codeScope), currentBlockRaw(nullptr) { } llvm::Value* RawFnInvocation::operator()(std::vector&& args, const std::string& hintDecl) { llvm::Function* calleeInfo = dyn_cast(__callee); if (calleeInfo) { auto argsFormal = calleeInfo->args(); - - int pos = 0; - //SECTIONTAG types/convert function ret value - for (auto argFormal = argsFormal.begin(); argFormal != argsFormal.end(); ++argFormal, ++pos) { - args[pos] = typeinference::doAutomaticTypeConversion(args[pos], argFormal->getType(), llvm->builder); + 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()){ + if (calleeInfo->getReturnType()->isVoidTy()) { nameStatement.clear(); } return llvm->builder.CreateCall(__calleeTy, __callee, args, nameStatement); } - //DESABLEDFEATURE implement inlining -class CallStatementInline : public IFnInvocation { +//DESABLEDFEATURE implement inlining + +class CallStatementInline : public IFnInvocation{ public: + CallStatementInline(IFunctionUnit* caller, IFunctionUnit* callee, LLVMLayer* l) - : __caller(caller), __callee(callee), llvm(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() { + 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) { -} +BasicCodeScopeUnit::BasicCodeScopeUnit(const CodeScope * const codeScope, IFunctionUnit* f, CompilePass* compilePass) +: ICodeScopeUnit(codeScope, f, compilePass) { } llvm::Value* BasicCodeScopeUnit::processSymbol(const Symbol& s, std::string hintRetVar) { Expression declaration = CodeScope::getDefinition(s); - const CodeScope* scope = s.scope; - ICodeScopeUnit* scopeExternal = ICodeScopeUnit::function->getScopeUnit(scope); - + const CodeScope* scopeExternal = s.scope; + ICodeScopeUnit* scopeBruteExternal = ICodeScopeUnit::function->getScopeUnit(scopeExternal); + assert(scopeBruteExternal->currentBlockRaw); + llvm::Value* resultRaw; - if (scopeExternal == this){ - resultRaw = process(declaration, hintRetVar); - currentBlockRaw = pass->man->llvm->builder.GetInsertBlock(); + 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 { - assert(scopeExternal->currentBlockRaw); - - llvm::BasicBlock* blockOwn = pass->man->llvm->builder.GetInsertBlock(); - pass->man->llvm->builder.SetInsertPoint(scopeExternal->currentBlockRaw); - resultRaw = scopeExternal->processSymbol(s, hintRetVar); + pass->man->llvm->builder.SetInsertPoint(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 RawFnInvocation(external, llvm); } //There should be only one specialization without any valid guards at this point return new RawFnInvocation(pass->getFunctionUnit( pass->man->root->findFunction(calleeName))->compile(), llvm); } //DISABLEDFEATURE transformations // if (pass->transformations->isAcceptable(expr)){ // return pass->transformations->transform(expr, result, ctx); // } llvm::Value* BasicCodeScopeUnit::process(const Expression& expr, const std::string& hintVarDecl) { - #define DEFAULT(x) (hintVarDecl.empty()? x: hintVarDecl) +#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); + 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]); + left = process(expr.operands[0]); + right = process(expr.operands[1]); - //SECTIONTAG types/convert binary operation - right = typeinference::doAutomaticTypeConversion(right, left->getType(), l.builder); - break; + break; - default:; + 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; + case Operator::ADD: + { + left = process(expr.operands[0]); + Context context{this, function, pass}; - right = process(expr.operands[1]); + llvm::Value* resultSU = StructUpdate::add(expr.operands[0], left, expr.operands[1], context, DEFAULT("tmp_add")); + if (resultSU) return resultSU; - llvm::Value* resultAddPA = pointerarithmetic::PointerArithmetic::add(left, right, context, DEFAULT("tmp_add")); - if (resultAddPA) { - return resultAddPA; - } + right = process(expr.operands[1]); - return l.builder.CreateAdd(left, right, DEFAULT("tmp_add")); - break; + llvm::Value* resultAddPA = pointerarithmetic::PointerArithmetic::add(left, right, context, DEFAULT("tmp_add")); + if (resultAddPA) { + return resultAddPA; } - case Operator::SUB: - return l.builder.CreateSub(left, right, DEFAULT("tmp_sub")); - break; - - case Operator::MUL: - return l.builder.CreateMul(left, right, DEFAULT("tmp_mul")); - break; - - case Operator::DIV: - return l.builder.CreateSDiv(left, right, DEFAULT("tmp_div")); - break; - - case Operator::EQU: - if (left->getType()->isIntegerTy()) return l.builder.CreateICmpEQ(left, right, DEFAULT("tmp_equ")); - if (left->getType()->isFloatingPointTy()) return l.builder.CreateFCmpOEQ(left, right, DEFAULT("tmp_equ")); - break; + return l.builder.CreateAdd(left, right, DEFAULT("tmp_add")); + break; + } - case Operator::NE: - return l.builder.CreateICmpNE(left, right, DEFAULT("tmp_ne")); - break; + case Operator::SUB: + return l.builder.CreateSub(left, right, DEFAULT("tmp_sub")); + break; + + case Operator::MUL: + return l.builder.CreateMul(left, right, DEFAULT("tmp_mul")); + break; + + case Operator::DIV: + return l.builder.CreateSDiv(left, right, DEFAULT("tmp_div")); + break; + + case Operator::EQU: + if (left->getType()->isIntegerTy()) return l.builder.CreateICmpEQ(left, right, DEFAULT("tmp_equ")); + if (left->getType()->isFloatingPointTy()) return l.builder.CreateFCmpOEQ(left, right, DEFAULT("tmp_equ")); + break; + + case Operator::NE: + return l.builder.CreateICmpNE(left, right, DEFAULT("tmp_ne")); + break; + + case Operator::LSS: + return l.builder.CreateICmpSLT(left, right, DEFAULT("tmp_lss")); + break; + + case Operator::LSE: + return l.builder.CreateICmpSLE(left, right, DEFAULT("tmp_lse")); + break; + + case Operator::GTR: + return l.builder.CreateICmpSGT(left, right, DEFAULT("tmp_gtr")); + break; + + case Operator::GTE: + return l.builder.CreateICmpSGE(left, right, DEFAULT("tmp_gte")); + break; + + case Operator::NEG: + left = process(expr.operands[0]); + return l.builder.CreateNeg(left, DEFAULT("tmp_neg")); + break; + + case Operator::CALL: + { + assert(expr.__state == Expression::COMPOUND); + shared_ptr callee(findFunction(expr)); + const std::string& nameCallee = expr.getValueString(); + + //prepare arguments + std::vector args; + args.reserve(expr.operands.size()); + + std::transform(expr.operands.begin(), expr.operands.end(), std::inserter(args, args.end()), + [this](const Expression & operand) { + return process(operand); + } + ); - case Operator::LSS: - return l.builder.CreateICmpSLT(left, right, DEFAULT("tmp_lss")); - break; + return (*callee)(move(args), DEFAULT("res_" + nameCallee)); + } - case Operator::LSE: - return l.builder.CreateICmpSLE(left, right, DEFAULT("tmp_lse")); - break; + case Operator::IF: + { + return instructions.compileIf(expr, DEFAULT("tmp_if")); + } - case Operator::GTR: - return l.builder.CreateICmpSGT(left, right, DEFAULT("tmp_gtr")); - break; + case Operator::SWITCH: + { + return instructions.compileSwitch(expr, DEFAULT("tmp_switch")); + } - case Operator::GTE: - return l.builder.CreateICmpSGE(left, right, DEFAULT("tmp_gte")); - break; + case Operator::LOGIC_AND: + { + assert(expr.operands.size() == 1); + return process(expr.operands[0]); + } - case Operator::NEG: - left = process(expr.operands[0]); - return l.builder.CreateNeg(left, DEFAULT("tmp_neg")); - break; + case Operator::LIST: + { + return instructions.compileListAsSolidArray(expr, DEFAULT("tmp_list")); + }; - case Operator::CALL: - { - assert(expr.__state == Expression::COMPOUND); - shared_ptr callee(findFunction(expr)); - const std::string& nameCallee = expr.getValueString(); + case Operator::LIST_RANGE: + { + assert(false); //no compilation phase for a range list + // return InstructionList(this).compileConstantArray(expr, l, hintRetVar); + }; - //prepare arguments - std::vector args; - args.reserve(expr.operands.size()); + case Operator::LIST_NAMED: + { + typedef Expanded ExpandedType; - std::transform(expr.operands.begin(), expr.operands.end(), std::inserter(args, args.end()), - [this](const Expression & operand) { - return process(operand); - } - ); + ExpandedType tyStructLiteral = l.ast->getType(expr); - return (*callee)(move(args), DEFAULT("res_" + nameCallee)); - } + const std::vector fieldsFormal = (tyStructLiteral.get().__operator == TypeOperator::CUSTOM) ? + l.layerExtern->getStructFields(l.layerExtern->lookupType(tyStructLiteral.get().__valueCustom)) + : tyStructLiteral.get().fields; - case Operator::IF: - { - return instructions.compileIf(expr, DEFAULT("tmp_if")); + std::map indexFields; + for (size_t i = 0, size = fieldsFormal.size(); i < size; ++i) { + indexFields.emplace(fieldsFormal[i], i); } - case Operator::SWITCH: - { - return instructions.compileSwitch(expr, DEFAULT("tmp_switch")); - } + llvm::StructType* tyLiteralRaw = llvm::cast(l.toLLVMType(tyStructLiteral)); + llvm::Value* record = llvm::UndefValue::get(tyLiteralRaw); - case Operator::LOGIC_AND: - { - assert(expr.operands.size() == 1); - return process(expr.operands[0]); + 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})); } - case Operator::LIST: - { - return instructions.compileListAsSolidArray(expr, DEFAULT("tmp_list")); - }; - - case Operator::LIST_RANGE: - { - assert(false); //no compilation phase for a range list - // return InstructionList(this).compileConstantArray(expr, l, hintRetVar); - }; - - case Operator::LIST_NAMED: - { - typedef Expanded ExpandedType; + return record; + }; - ExpandedType tyStructLiteral = l.ast->getType(expr); + case Operator::MAP: + { + assert(expr.blocks.size()); + return instructions.compileMapSolidOutput(expr, DEFAULT("map")); + }; - const std::vector fieldsFormal = (tyStructLiteral.get().__operator == TypeOperator::CUSTOM) ? - l.layerExtern->getStructFields(l.layerExtern->lookupType(tyStructLiteral.get().__valueCustom)) - : tyStructLiteral.get().fields; + case Operator::FOLD: + { + return instructions.compileFold(expr, DEFAULT("fold")); + }; - std::map indexFields; - for (size_t i = 0, size = fieldsFormal.size(); i < size; ++i) { - indexFields.emplace(fieldsFormal[i], i); - } + case Operator::FOLD_INF: + { + return instructions.compileFoldInf(expr, DEFAULT("fold")); + }; - llvm::StructType* tyLiteralRaw = llvm::cast(l.toLLVMType(tyStructLiteral)); - llvm::Value* record = llvm::UndefValue::get(tyLiteralRaw); + case Operator::INDEX: + { + //TASK allow multiindex compilation + assert(expr.operands.size() == 2); + assert(expr.operands[0].__state == Expression::IDENT); - 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})); - } + 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]); - return record; - }; + llvm::Value* aggr = processSymbol(s, hintIdent); - case Operator::MAP: + switch (t2.get().__operator) { + case TypeOperator::LIST_NAMED: case TypeOperator::CUSTOM: { - assert(expr.blocks.size()); - return instructions.compileMapSolidOutput(expr, DEFAULT("map")); - }; + 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"); + } - case Operator::FOLD: - { - return instructions.compileFold(expr, DEFAULT("fold")); + return instructions.compileStructIndex(aggr, t2, idxField); }; - case Operator::FOLD_INF: + case TypeOperator::LIST: { - return instructions.compileFoldInf(expr, DEFAULT("fold")); - }; + std::vector indexes; + std::transform(++expr.operands.begin(), expr.operands.end(), std::inserter(indexes, indexes.end()), + [this] (const Expression & op) { + return process(op); + } + ); - case Operator::INDEX: - { - //TASK allow multiindex compilation - assert(expr.operands.size() == 2); - assert(expr.operands[0].__state == Expression::IDENT); - - const std::string& hintIdent = expr.operands[0].getValueString(); - Symbol s = Attachments::get(expr.operands[0]); - const ExpandedType& t2 = pass->man->root->getType(expr.operands[0]); - - llvm::Value* aggr = processSymbol(s, hintIdent); - - switch (t2.get().__operator) { - case TypeOperator::LIST_NAMED: case TypeOperator::CUSTOM: - { - std::string idxField; - const Expression& idx = expr.operands.at(1); - switch (idx.__state) { - - //named struct field - case Expression::STRING: - idxField = idx.getValueString(); - break; - - //anonymous struct field - case Expression::NUMBER: - idxField = to_string((int) idx.getValueDouble()); - break; - - default: - assert(false && "Wrong index for a struct"); - } - - return instructions.compileStructIndex(aggr, t2, idxField); - }; - - case TypeOperator::LIST: - { - std::vector indexes; - std::transform(++expr.operands.begin(), expr.operands.end(), std::inserter(indexes, indexes.end()), - [this] (const Expression & op) { - return process(op); - } - ); - - return instructions.compileArrayIndex(aggr, indexes, DEFAULT(string("el_") + hintIdent)); - }; - - default: - assert(false); - } + return instructions.compileArrayIndex(aggr, indexes, DEFAULT(string("el_") + hintIdent)); }; - case Operator::CALL_INTRINSIC: - { - const std::string op = expr.getValueString(); + default: + assert(false); + } + }; - if (op == "copy") { - llvm::Value* result = process(expr.getOperands().at(0)); + case Operator::CALL_INTRINSIC: + { + const std::string op = expr.getValueString(); - auto decoratorVersions = Decorators::getInterface(this); - llvm::Value* storage = decoratorVersions->processIntrinsicInit(result->getType()); - decoratorVersions->processIntrinsicCopy(result, storage); + if (op == "copy") { + llvm::Value* result = process(expr.getOperands().at(0)); - return l.builder.CreateLoad(storage, hintVarDecl); - } + auto decoratorVersions = Decorators::getInterface(this); + llvm::Value* storage = decoratorVersions->processIntrinsicInit(result->getType()); + decoratorVersions->processIntrinsicCopy(result, storage); - assert(false && "undefined intrinsic"); + return l.builder.CreateLoad(storage, hintVarDecl); } - 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})); - } + assert(false && "undefined intrinsic"); + } - return variantRaw; - } + case Operator::QUERY: + case Operator::QUERY_LATE: + { + assert(false && "Should be processed by interpretation"); + } - case Operator::SWITCH_VARIANT: { - return instructions.compileSwitchVariant(expr, DEFAULT("tmpswitch")); + 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})); } - case Operator::SWITCH_LATE: { - assert(false && "Instruction's compilation should've been redirected to interpretation"); - return nullptr; - } + return variantRaw; + } - case Operator::SEQUENCE: { - return instructions.compileSequence(expr); - } + case Operator::SWITCH_VARIANT: + { + return instructions.compileSwitchVariant(expr, DEFAULT("tmpswitch")); + } - case Operator::UNDEF: { - llvm::Type* typExprUndef = l.toLLVMType(typeinference::getType(expr, *pass->man->root)); - return llvm::UndefValue::get(typExprUndef); - } + case Operator::SWITCH_LATE: + { + assert(false && "Instruction's compilation should've been redirected to interpretation"); + return nullptr; + } - case Operator::INVALID: - assert(expr.__state != Expression::COMPOUND); + case Operator::SEQUENCE: + { + return instructions.compileSequence(expr); + } - switch (expr.__state) { - case Expression::IDENT: - { - Symbol s = Attachments::get(expr); - return processSymbol(s, expr.getValueString()); - } + case Operator::UNDEF: + { + llvm::Type* typExprUndef = l.toLLVMType(typeinference::getType(expr, *pass->man->root)); + return llvm::UndefValue::get(typExprUndef); + } - case Expression::NUMBER: - { - llvm::Type* typConst = l.toLLVMType(typeinference::getType(expr, *pass->man->root)); - int literal = expr.getValueDouble(); + case Operator::INVALID: + assert(expr.__state != Expression::COMPOUND); - return llvm::ConstantInt::get(typConst, literal); - } + switch (expr.__state) { + case Expression::IDENT: + { + Symbol s = Attachments::get(expr); + return processSymbol(s, expr.getValueString()); + } - case Expression::STRING: - { - return instructions.compileConstantStringAsPChar(expr.getValueString(), DEFAULT("tmp_str")); - }; + case Expression::NUMBER: + { + llvm::Type* typConst = l.toLLVMType(typeinference::getType(expr, *pass->man->root)); + int literal = expr.getValueDouble(); - default: - { - break; - } - }; + return llvm::ConstantInt::get(typConst, literal); + } + + case Expression::STRING: + { + return instructions.compileConstantStringAsPChar(expr.getValueString(), DEFAULT("tmp_str")); + }; + default: + { break; + } + }; + + break; - default: 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() { -} +ICodeScopeUnit::~ICodeScopeUnit() { } -IFunctionUnit::~IFunctionUnit() { -} +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)); 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){ +CompilePassCustomDecorators +::buildFunctionUnit(const ManagedFnPtr& function) { return new BruteFunctionDefault(function, this); } template<> compilation::ICodeScopeUnit* -CompilePassCustomDecorators::buildCodeScopeUnit(const CodeScope* const scope, IFunctionUnit* function){ +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 Encapsulates all compilation activities * * xreate::CompilePass iterates over xreate::AST tree and produces executable code fed by data(via xreate::Attachments) gathered by previous passes as well as data via queries(xreate::IQuery) from xreate:TranscendLayer reasoner. * Compilation's done using xreate::LLVMLayer(wrapper over LLVM toolchain) and based on following aspects: * - Containers support. See \ref compilation/containers.h * - Late Conext compilation. See xreate::context::LateContextCompiler2 * - Interpretation support. See xreate::interpretation::TargetInterpretation * - Loop saturation support. See xreate::compilation::TransformerSaturation * - External Code access. See xreate::ExternLayer(wrapper over Clang library) * * \section adaptability_sect Adaptability * xreate::CompilePass's architecture provides adaptability by employing: * - %Function Decorators to alter function-level compilation. See xreate::compilation::IFunctionUnit * - Code Block Decorators to alter code block level compilation. See xreate::compilation::ICodeScopeUnit * Default functionality defined by \ref xreate::compilation::DefaultCodeScopeUnit * - Targets to allow more versitile extensions. * Currently only xreate::interpretation::TargetInterpretation use Targets infrastructure. See xreate::compilation::Target * - %Altering Function invocation. xreate::compilation::ICallStatement * * Client able to construct compiler with desired decorators using xreate::compilation::CompilePassCustomDecorators. * As a handy alias, `CompilePassCustomDecorators` constructs default compiler * */ diff --git a/cpp/src/pass/interpretationpass.cpp b/cpp/src/pass/interpretationpass.cpp index 1e4d33e..2b440f8 100644 --- a/cpp/src/pass/interpretationpass.cpp +++ b/cpp/src/pass/interpretationpass.cpp @@ -1,533 +1,555 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * File: interpretationpass.cpp * Author: pgess * * Created on July 5, 2016, 5:21 PM */ /** * \file interpretationpass.h * \brief Interpretation analysis: determines what parts of code could be interpreted */ #include "pass/interpretationpass.h" #include #include #include "ast.h" //DEBT implement InterpretationPass purely in transcend //DEBT represent InterpretationPass as general type inference using namespace std; namespace xreate { template<> interpretation::InterpretationResolution defaultValue() { return interpretation::CMPL_ONLY; } namespace interpretation { enum InterpretationQuery { QUERY_INTR_ONLY, QUERY_CMPL_ONLY }; namespace details { template bool checkConstraints(InterpretationResolution flag) { return( (flag==INTR_ONLY&&FLAG_REQUIRED==QUERY_INTR_ONLY) ||(flag==CMPL_ONLY&&FLAG_REQUIRED==QUERY_CMPL_ONLY)); } InterpretationResolution recognizeTags(const map& tags) { auto i=tags.find("interpretation"); if(i==tags.end()){ return ANY; } assert(i->second.op==Operator::CALL); const string& cmd=i->second.operands.at(0).getValueString(); //TODO make consistent names of annotation and resolution if(cmd=="force"){ return INTR_ONLY; } else if(cmd=="suppress"){ return CMPL_ONLY; } return ANY; } } InterpretationResolution unify(InterpretationResolution flag) { return flag; } template InterpretationResolution unify(FLAG_A flagA, FLAG_B flagB, FLAGS... flags) { if(flagA==ANY){ return unify(flagB, flags...); } if(flagB==ANY){ return unify(flagA, flags...); } assert(flagA==flagB); return flagA; } template bool checkConstraints(std::vector&& flags) { assert(flags.size()); InterpretationResolution flag=flags.front(); return details::checkConstraints(flag); } template bool checkConstraints(std::vector&& flags) { assert(flags.size()); InterpretationResolution flag=flags.front(); flags.pop_back(); if(details::checkConstraints(flag)){ return checkConstraints(move(flags)); } return false; } bool InterpretationData::isDefault() const { return(resolution==ANY&&op==NONE); } void recognizeTags(const Expression& e) { InterpretationData tag{details::recognizeTags(e.tags), NONE}; if(!tag.isDefault()) Attachments::put(e, tag); } InterpretationResolution recognizeTags(const ManagedFnPtr& f) { return details::recognizeTags(f->getTags()); } InterpretationPass::InterpretationPass(PassManager* manager) : AbstractPass(manager) { Attachments::init(); Attachments::init(); } void InterpretationPass::run() { ManagedFnPtr f=man->root->begin(); auto& visitedSymbols=getSymbolCache(); while(f.isValid()) { const Symbol&symbolFunction{ScopedSymbol::RetSymbol, f->getEntryScope()}; if(!visitedSymbols.isCached(symbolFunction)){ visitedSymbols.setCachedValue(symbolFunction, process(f)); } ++f; } } InterpretationResolution InterpretationPass::process(const Expression& expression, PassContext context, const std::string& decl) { recognizeTags(expression); InterpretationResolution resolution=ANY; - InterpretationOperator op=NONE; + InterpretationOperator opNo=NONE; switch(expression.__state) { case Expression::NUMBER: case Expression::STRING: { break; } case Expression::IDENT: { resolution=Parent::processSymbol(Attachments::get(expression), context); break; } case Expression::COMPOUND: break; default: { resolution=CMPL_ONLY; break; } } if(expression.__state==Expression::COMPOUND) switch(expression.op) { case Operator::EQU: case Operator::NE: { InterpretationResolution left=process(expression.operands[0], context); InterpretationResolution right=process(expression.operands[1], context); resolution=unify(left, right); break; } case Operator::LOGIC_AND: { assert(expression.operands.size()==1); resolution=process(expression.operands[0], context); break; } case Operator::CALL: { + size_t sizeOperands = expression.operands.size(); + std::vector operands; + operands.reserve(sizeOperands); + + for(size_t opNo=0; opNo callees=man->root->getFunctionSpecializations(expression.getValueString()); if(callees.size()!=1){ resolution=CMPL_ONLY; break; } ManagedFnPtr callee=callees.front(); const Symbol& symbCalleeFunc{ScopedSymbol::RetSymbol, callee->getEntryScope()}; //recursion-aware processing: // - skip self recursion const Symbol&symbSelfFunc{ScopedSymbol::RetSymbol, context.function->getEntryScope()}; if(!(symbSelfFunc==symbCalleeFunc)){ InterpretationResolution resCallee=processFnCall(callee, context); assert(resCallee!=FUNC_POSTPONED&&"Indirect recursion detected: can't decide on interpretation resolution"); resolution=unify(resolution, resCallee); } //check arguments compatibility const FunctionInterpretationData& calleeSignature=FunctionInterpretationHelper::getSignature(callee); - for(size_t op=0, size=expression.operands.size(); op__identifiers.at(argName), versions::VERSION_NONE}, + exprBody + }; + getSymbolCache().setCachedValue(argS, INTR_ONLY); + Parent::process(expression.blocks.front(), context); + resolution = CMPL_ONLY; - op = SWITCH_LATE; + opNo=QUERY_LATE; break; } + case Operator::SWITCH_LATE: + { + resolution = CMPL_ONLY; + opNo = SWITCH_LATE; + break; + } case Operator::IF: { InterpretationResolution flagCondition=process(expression.getOperands()[0], context); InterpretationResolution flagScope1=Parent::process(expression.blocks.front(), context); InterpretationResolution flagScope2=Parent::process(expression.blocks.back(), context); //special case: IF_INTERPRET_CONDITION if(checkConstraints({flagCondition})){ - op=IF_INTERPRET_CONDITION; + opNo=IF_INTERPRET_CONDITION; flagCondition=ANY; } resolution=unify(flagCondition, flagScope1, flagScope2); break; } case Operator::FOLD: { InterpretationResolution flagInput=process(expression.getOperands()[0], context); InterpretationResolution flagAccumInit=process(expression.getOperands()[1], context); CodeScope* scopeBody=expression.blocks.front(); const std::string& nameEl=expression.bindings[0]; Symbol symbEl{ScopedSymbol {scopeBody->__identifiers.at(nameEl), versions::VERSION_NONE}, scopeBody}; getSymbolCache().setCachedValue(symbEl, InterpretationResolution(flagInput)); const std::string& nameAccum=expression.bindings[1]; Symbol symbAccum{ScopedSymbol {scopeBody->__identifiers.at(nameAccum), versions::VERSION_NONE}, scopeBody}; getSymbolCache().setCachedValue(symbAccum, InterpretationResolution(flagAccumInit)); InterpretationResolution flagBody=Parent::process(expression.blocks.front(), context); //special case: FOLD_INTERPRET_INPUT if(checkConstraints({flagInput})){ - op=FOLD_INTERPRET_INPUT; + opNo=FOLD_INTERPRET_INPUT; flagInput=ANY; } resolution=unify(flagInput, flagAccumInit, flagBody); break; } case Operator::INDEX: { - for(const Expression &op : expression.getOperands()) { - resolution=unify(resolution, process(op, context)); + for(const Expression &opNo : expression.getOperands()) { + resolution=unify(resolution, process(opNo, context)); } break; } case Operator::SWITCH: { InterpretationResolution flagCondition=process(expression.operands[0], context); bool hasDefaultCase=expression.operands[1].op==Operator::CASE_DEFAULT; //determine conditions resolution InterpretationResolution flagHeaders=flagCondition; for(size_t size=expression.operands.size(), i=hasDefaultCase?2:1; i({flagHeaders})){ - op=SWITCH_INTERPRET_CONDITION; + opNo=SWITCH_INTERPRET_CONDITION; flagHeaders=ANY; } //determine body resolutions resolution=flagHeaders; for(size_t size=expression.operands.size(), i=1; i({resolution})){ - op=SWITCH_VARIANT; + opNo=SWITCH_VARIANT; resolution=ANY; } const string identCondition=expression.bindings.front(); for(auto scope : expression.blocks) { //set binding resolution ScopedSymbol symbolInternal=scope->getSymbol(identCondition); getSymbolCache().setCachedValue(Symbol{symbolInternal, scope}, InterpretationResolution(resolutionCondition)); resolution=unify(resolution, Parent::process(scope, context)); } for(auto scope : expression.blocks) { resolution=unify(resolution, Parent::process(scope, context)); } break; } case Operator::LIST: case Operator::LIST_NAMED: { - for(const Expression &op : expression.getOperands()) { - resolution=unify(resolution, process(op, context)); + for(const Expression &opNo : expression.getOperands()) { + resolution=unify(resolution, process(opNo, context)); } break; } case Operator::VARIANT: { if(expression.getOperands().size()){ resolution=process(expression.getOperands().front(), context); } else { resolution=ANY; } break; } default: { resolution=CMPL_ONLY; - for(const Expression &op : expression.getOperands()) { - process(op, context); + for(const Expression &opNo : expression.getOperands()) { + process(opNo, context); } for(CodeScope* scope : expression.blocks) { Parent::process(scope, context); } break; } } InterpretationData dataExpected= Attachments::get(expression,{ANY, NONE}); resolution=unify(resolution, dataExpected.resolution); - if(resolution!=dataExpected.resolution || op != dataExpected.op ){ - Attachments::put(expression,{resolution, op}); + if(resolution!=dataExpected.resolution || opNo != dataExpected.op ){ + Attachments::put(expression,{resolution, opNo}); } return resolution; } InterpretationResolution InterpretationPass::processFnCall(ManagedFnPtr function, PassContext context) { return process(function); } InterpretationResolution InterpretationPass::process(ManagedFnPtr function) { CodeScope* entry=function->getEntryScope(); std::vector arguments=entry->__bindings; const Symbol&symbSelfFunc{ScopedSymbol::RetSymbol, function->getEntryScope()}; auto& cache=getSymbolCache(); if(cache.isCached(symbSelfFunc)) return cache.getCachedValue(symbSelfFunc); const FunctionInterpretationData& fnSignature=FunctionInterpretationHelper::getSignature(function); InterpretationResolution fnResolutionExpected=details::recognizeTags(function->getTags()); //mark preliminary function resolution as expected if(fnResolutionExpected!=ANY){ cache.setCachedValue(symbSelfFunc, move(fnResolutionExpected)); } else { // - in order to recognize indirect recursion mark this function resolution as POSTPONED cache.setCachedValue(symbSelfFunc, FUNC_POSTPONED); } //set resolution for function arguments as expected for(int argNo=0, size=arguments.size(); argNo__identifiers.at(arguments[argNo]), versions::VERSION_NONE}, entry}; cache.setCachedValue(symbArg, InterpretationResolution(fnSignature.signature[argNo])); } PassContext context; context.function=function; context.scope=entry; InterpretationResolution resActual=process(CodeScope::getDefinition(symbSelfFunc), context); resActual=unify(resActual, fnResolutionExpected); return cache.setCachedValue(symbSelfFunc, move(resActual)); } const FunctionInterpretationData FunctionInterpretationHelper::getSignature(ManagedFnPtr function) { if(Attachments::exists(function)){ return Attachments::get(function); } FunctionInterpretationData&& data=recognizeSignature(function); Attachments::put(function, data); return data; } FunctionInterpretationData FunctionInterpretationHelper::recognizeSignature(ManagedFnPtr function) { CodeScope* entry=function->__entry; FunctionInterpretationData result; result.signature.reserve(entry->__bindings.size()); bool flagPartialInterpretation=false; for(size_t no=0, size=entry->__bindings.size(); no__bindings[no]; Symbol symbArg{ScopedSymbol {entry->__identifiers.at(argName), versions::VERSION_NONE}, entry}; const Expression& arg=CodeScope::getDefinition(symbArg); InterpretationResolution argResolution=details::recognizeTags(arg.tags); flagPartialInterpretation|=(argResolution==INTR_ONLY); result.signature.push_back(argResolution); } result.flagPartialInterpretation=flagPartialInterpretation; return result; } bool FunctionInterpretationHelper::needPartialInterpretation(ManagedFnPtr function) { const FunctionInterpretationData& data=getSignature(function); return data.flagPartialInterpretation; } } } //end of namespace xreate::interpretation /** \class xreate::interpretation::InterpretationPass * * Encapsulates *Interpretation Analysis* to support [Interpretation Concept](/w/concepts/dfa) * * Recognizes program functions, expressions, instructions eligible for interpretation * and stores output in Attachments and Attachments * * There are number of instructions currently able to be interpreted: * - Basic literals: numbers and strings * - Compounds: lists, structs, variants * - Non-versioned identifiers * - Comparison and logic operators * - %Function calls * - `query` intrinsic function calls * - Branching: `if`, `loop fold`, `switch`, `switch variant` statements * - * Some of those instructions are eligibile for *hybrid interpretation* to allow coupling + * Some of those instructions are eligibile for *late interpretation* to allow coupling * of compiled instructions with interpreted ones, those are: * - Partial function calls * - Branching: `if`, `loop fold`, `switch`, `switch variant` statements * * \sa xreate::interpretation::TargetInterpretation, [Interpretation Concept](/w/concepts/dfa) */ diff --git a/cpp/src/pass/interpretationpass.h b/cpp/src/pass/interpretationpass.h index 21da1d3..1f47aa2 100644 --- a/cpp/src/pass/interpretationpass.h +++ b/cpp/src/pass/interpretationpass.h @@ -1,96 +1,96 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * File: interpretationpass.h * Author: pgess * * Created on July 5, 2016, 5:21 PM */ #ifndef INTERPRETATIONPASS_H #define INTERPRETATIONPASS_H #include "abstractpass.h" #include #ifndef FRIENDS_INTERPRETATION_TESTS #define FRIENDS_INTERPRETATION_TESTS #endif -//TODO refactor interpretation. Get rid of InterpretationOperator, put only one operator - Hybrid. +//TODO refactor interpretation. Get rid of InterpretationOperator, put only one operator - Hybrid/Late. namespace xreate{ namespace interpretation{ enum InterpretationResolution{ANY, INTR_ONLY, CMPL_ONLY, FUNC_POSTPONED}; enum InterpretationOperator{ - NONE, IF_INTERPRET_CONDITION, FOLD_INTERPRET_INPUT, + NONE, IF_INTERPRET_CONDITION, FOLD_INTERPRET_INPUT, QUERY_LATE, SWITCH_INTERPRET_CONDITION, SWITCH_VARIANT, SWITCH_LATE, CALL_INTERPRET_PARTIAL }; struct InterpretationData{ InterpretationResolution resolution; InterpretationOperator op; bool isDefault() const; }; struct FunctionInterpretationData{ typedef std::vector Signature; Signature signature; bool flagPartialInterpretation; }; class FunctionInterpretationHelper { public: static const FunctionInterpretationData getSignature(ManagedFnPtr function); static bool needPartialInterpretation(ManagedFnPtr function); private: static FunctionInterpretationData recognizeSignature(ManagedFnPtr function); }; /** \brief Determines parts of program eligible for Interpretation. */ class InterpretationPass: public AbstractPass { typedef AbstractPass Parent; public: InterpretationResolution process(const Expression& expression, PassContext context, const std::string& varDecl="") override; InterpretationResolution process(ManagedFnPtr function); InterpretationResolution processFnCall(ManagedFnPtr function, PassContext context); InterpretationPass(PassManager* manager); void run(); }; namespace details { InterpretationResolution recognizeTags(const std::map& tags); } } //end of namespace interpretation template<> interpretation::InterpretationResolution defaultValue(); template<> struct AttachmentsDict { typedef interpretation::FunctionInterpretationData Data; static const unsigned int key = 5; }; template<> struct AttachmentsDict { typedef interpretation::InterpretationData Data; static const unsigned int key = 3; }; } //end of namespace xreate #endif /* INTERPRETATIONPASS_H */ diff --git a/cpp/src/query/latex.cpp b/cpp/src/query/latex.cpp index 5fc0816..04a7826 100644 --- a/cpp/src/query/latex.cpp +++ b/cpp/src/query/latex.cpp @@ -1,94 +1,98 @@ /* * 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: Subject, Decision + //schema: latex_registered_subjects(Subject, Decision) data = __transcend->query("latex_registered_subjects"); for(const auto& entry : data) { string subject; Gringo::Symbol decision; tie(subject, decision) = __transcend->parse(entry.second); __domains[subject].push_back(decision); } - //schema: Scope, Subject, Decision + //schema: latex_decision(Scope, Subject, Decision) data = __transcend->query("latex_decision"); for(const auto& entry : data) { ScopePacked scope; string subject; Gringo::Symbol decision; tie(scope, subject, decision) = __transcend->parse(entry.second); __decisions[make_pair(scope, subject)] = entry.second; } + //schema: latex_parameters_group_offset(int) + data = __transcend->query("latex_parameters_group_offset"); + 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 LatexQuery::getSubjectDomain(const std::string& subject) { assert(__domains.count(subject)); return __domains.at(subject); } } } \ No newline at end of file diff --git a/cpp/src/query/latex.h b/cpp/src/query/latex.h index 89ccf56..1239ae9 100644 --- a/cpp/src/query/latex.h +++ b/cpp/src/query/latex.h @@ -1,44 +1,46 @@ /* * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ /** * \file query/context.h * \brief Represents reasoner's solution on [Context](/w/concepts/context) * * \class xreate::latex::LatexQuery */ #ifndef LATEXQUERY_H #define LATEXQUERY_H #include "transcendlayer.h" #include "aux/latereasoning.h" #include namespace xreate{ namespace latex{ typedef std::vector Demand; class LatexQuery: public IQuery{ public: + VNameId LatexParametersOffset; + Demand getFnDemand(const std::string& fnName); latereasoning::LateAnnotation getDecision(const std::string& subject, const CodeScope* scopeCaller); std::list getSubjectDomain(const std::string& subject); void init(TranscendLayer* transcend); private: TranscendLayer* __transcend; std::map __demand; std::map, Gringo::Symbol> __decisions; std::map, latereasoning::LateAnnotation> __decisionsLate; std::map> __domains; }; } } #endif \ No newline at end of file diff --git a/cpp/src/utils.h b/cpp/src/utils.h index c98e03e..b45173b 100644 --- a/cpp/src/utils.h +++ b/cpp/src/utils.h @@ -1,164 +1,167 @@ /* 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/. * * utils.cpp * * Author: pgess */ #ifndef UTILS_H #define UTILS_H #include "jeayeson/jeayeson.hpp" namespace xreate { template struct AddTag { explicit AddTag(const Source &src) : __src(src) { } explicit AddTag(Source &&src) : __src(std::move(src)) { } operator const Source&() const{ return __src; } const Source& get() const{ return __src; } const Source* operator->() const { return &__src; } private: Source __src; }; struct Expand_t{}; template using Expanded = AddTag; //DEBT move to resources compiler. https://github.com/markusfisch/cpprc class Config { private: json_map __storage; static Config __self; Config(); public: static std::string get(std::string key) { return __self.__storage.get_for_path(key).get(); } }; /** \brief Decorators support */ template struct DecoratorsDict{ //typedef ConcreteDecoratorForTag result; }; template struct Decorators{ typedef typename DecoratorsDict::result Instance; template static Instance* getInterface(Base* obj){ - return dynamic_cast< Instance* > (obj); + Instance* result = dynamic_cast< Instance* > (obj); + assert(result); + + return result; } }; template struct ManagedPtr { static ManagedPtr Invalid() { return ManagedPtr(); } ManagedPtr() : __storage(0) { } ManagedPtr(unsigned int id, const std::vector* storage) : __id(id), __storage(storage) { } Target& operator*() const { assert(isValid() && "Invalid Ptr"); return *__storage->at(__id); } void operator=(const ManagedPtr& other) { __id = other.__id; __storage = other.__storage; } bool operator==(const ManagedPtr& other) { return isValid() && (__id == other.__id); } Target* operator->() const noexcept { assert(isValid() && "Invalid Ptr"); return __storage->at(__id); } inline bool isValid() const { return (__storage) && (0 <= __id) && (__id < __storage->size()); } inline operator bool() const { return isValid(); } ManagedPtr& operator++() { ++__id; return *this; } inline unsigned int id() const { return __id; } private: unsigned int __id = 0; const std::vector * __storage = 0; }; } std::wstring utf8_to_wstring(const std::string& str); std::string wstring_to_utf8(const std::wstring& str); #define RST "\x1B[0m" #define KRED "\x1B[31m" #define KGRN "\x1B[32m" #define KYEL "\x1B[33m" #define KBLU "\x1B[34m" #define KMAG "\x1B[35m" #define KCYN "\x1B[36m" #define KWHT "\x1B[37m" #define FRED(x) KRED << x << RST #define FGRN(x) KGRN < * Created on August 12, 2017, 9:28 PM */ #include "xreatemanager.h" #include "transcendlayer.h" +#include "pass/interpretationpass.h" #include +using namespace xreate::interpretation; using namespace xreate; using namespace std; -TEST(Association, test1) { - std::string controller = - R"Code( - program(add). -)Code"; - - std::string script = - R"Code( -Annotation = type variant { - Num:: int, - String:: string, - Func:: {name::string, arguments::[Annotation]} -}. - -extractCmd = function(program::Annotation):: Annotation; interpretation(force){ - switch variant(program)::Annotation - case (Num){String("wrong expression")} - case (String){String("wrong expression")} - case (Func){program["arguments"][0]} -} - -main= function:: int; entry{ - x= 5::int. - y = 6::int. - - program = intrinsic query("program")[0]::Annotation. - cmd = extractCmd(program)::Annotation; interpretation(force). - - answer = switch variant(cmd)::int - case (Num) {0} - case (String){0} - case (Func){ - switch(cmd["name"])::int - case("add"){x + y} - case default {0} - }. - - answer -} -)Code"; - - std::unique_ptr man(XreateManager::prepare(std::move(script))); - man->transcend->addRawScript(move(controller)); - int (*main)() = (int (*)())man->run(); - int result = main(); - - ASSERT_EQ(11, result); -} - -TEST(Association, QueryScope1) { - std::string script = R"Code( - Annotation = type variant { - Num:: int, - String:: string, - Func:: {name::string, arguments::[Annotation]} - }. - - func = function::int{10} //aux func in order to have few scopes - - main = function:: int; entry { - scope = intrinsic query_scope()::Annotation. - - answer = switch variant(scope):: int - case (Num) {scope} - case (String){-1} - case (Func){-1}. - - answer - } - -)Code"; - - std::unique_ptr man(XreateManager::prepare(std::move(script))); - int (*main)() = (int (*)())man->run(); - int result = main(); - - ASSERT_EQ(1, result); -} - TEST(Association, TypedQuery_1) { - auto man = details::tier1::XreateManager::prepare(R"Code( + auto man = ::xreate::details::tier1::XreateManager::prepare(R"Code( AtomNumT = type slave atomNumT. AtomStrT = type slave atomStrT. CompListT = type slave compListT. CompArithT = type slave compArithT. test = function:: num; entry { query1 = intrinsic query("atomNumT")::[AtomNumT]. query2 = intrinsic query("atomStrT")::[AtomStrT]. query3 = intrinsic query("compListT")::[CompListT]. query4 = intrinsic query("compArithT")::[CompArithT]. test1 = query1[0] == 5:: bool. test2 = query2[1] == "y":: bool. test3 = query3[0, 1] == "x" :: bool. test4 = query4[0, 0, 0] == 1:: bool. test1 + test2 + test3 + test4 } )Code"); man->transcend->addRawScript(R"RAW( atomNumT(5; 8). atomStrT("x"; "y"). compListT(5, "x"). compListT(8, "y"). compArithT(add(1, 2)). compArithT(mul(5, 6)). )RAW"); man->analyse(); int (*test)() = (int (*)())man->run(); int result = test(); ASSERT_EQ(4, result); } +TEST(Association, QueryLate_ast_1){ + auto man = XreateManager::prepare( +R"Code( + test = function:: num; entry + { + intrinsic query late("dict"->x:: bool)::bool + { + (x == true) + } + } +)Code"); +} + +TEST(Association, QueryLate_pass_1){ + auto man = ::xreate::details::tier1::XreateManager::prepare( +R"Code( + test = function:: num; entry + { + intrinsic query late("dict"->x:: bool)::bool + { + (x == true) + } + } +)Code"); + man->analyse(); + + Expression instructionE = man->root->findFunction("test")->getEntryScope()->getBody(); + InterpretationData instructionData = Attachments::get(instructionE); + ASSERT_EQ(QUERY_LATE, instructionData.op); +} + +TEST(Association, QueryLate_target_1){ + auto man = ::xreate::details::tier1::XreateManager::prepare( +R"Code( + Equipment = type variant {dresser, sink, stove}. + Room = type variant{kitchen, bedroom, bathroom}. + + test = function:: num; entry + { + room = bedroom() :: Room; room. + equipment = intrinsic query late("whatshere"->x:: Equipment)::int; equipment + { if (x == dresser()):: int {1} else {0} }. + + equipment + (room::int) + } +)Code"); + + man->transcend->addRawScript( +R"RAW( + room(kitchen; bedroom; bathroom). + equipment(dresser;sink;stove). + interior(kitchen, stove). + interior(bedroom, dresser). + interior(bathroom, sink). + + late(VarTarget, VarRoom, Room, whatshere(Equipment)):- + bind(VarTarget, equipment); + bind(VarRoom, room); + interior(Room, Equipment); + equipment(Equipment); + room(Room). +)RAW"); + + man->analyse(); + int (*result)() = (int (*)()) man->run(); + ASSERT_EQ(2, result()); +} + diff --git a/cpp/tests/types.cpp b/cpp/tests/types.cpp index d71319c..73f8349 100644 --- a/cpp/tests/types.cpp +++ b/cpp/tests/types.cpp @@ -1,236 +1,248 @@ /* Any copyright is dedicated to the Public Domain. * http://creativecommons.org/publicdomain/zero/1.0/ * * types.cpp * * Created on: Jun 4, 2015 * Author: pgess */ #include "gtest/gtest.h" #include "xreatemanager.h" #include "llvmlayer.h" #include "main/Parser.h" #include "transcendlayer.h" #include "analysis/typeinference.h" #include "analysis/interpretation.h" using namespace std; using namespace xreate; using namespace xreate::grammar::main; TEST(Types, DependantTypes1) { string&& code = "XmlNode = type {\n" " tag:: string,\n" " attrs:: [string], \n" " content:: string\n" "}.\n"; std::unique_ptr program(XreateManager::prepare(move(code))); ExpandedType typeXmlNode = program->root->findType("XmlNode"); ASSERT_EQ(TypeOperator::LIST_NAMED, typeXmlNode->__operator); ASSERT_EQ(3, typeXmlNode->__operands.size()); ASSERT_EQ(TypePrimitive::String, typeXmlNode->__operands.at(0).__value); ASSERT_EQ(TypeOperator::LIST, typeXmlNode->__operands.at(1).__operator); ASSERT_EQ(TypePrimitive::String, typeXmlNode->__operands.at(2).__value); } TEST(Types, ast_ParameterizedTypes_FeatureTypeIndex_1) { string&& code = "XmlNode = type {\n" " tag:: string,\n" " attrs:: [string],\n" " content:: string\n" "}.\n" "" "Template = type(Leaf) {Leaf, [Leaf[content]]}." "Concrete = type Template(XmlNode)."; std::unique_ptr program(XreateManager::prepare(move(code))); ExpandedType typeConcrete = program->root->findType("Concrete"); ASSERT_EQ(TypeOperator::LIST_NAMED, typeConcrete->__operator); ASSERT_EQ(2, typeConcrete->__operands.size()); ASSERT_EQ(TypeOperator::LIST_NAMED, typeConcrete->__operands.at(0).__operator); ASSERT_EQ(TypeOperator::LIST, typeConcrete->__operands.at(1).__operator); ASSERT_EQ(TypePrimitive::String, typeConcrete->__operands.at(1).__operands.at(0).__value); } TEST(Types, TreeType1) { string&& code = "XmlNode = type {\n" " tag:: string,\n" " attrs:: [string],\n" " content:: string\n" "}.\n" "" "Tree = type(Leaf) {Leaf, [Tree(Leaf)]}." "Concrete = type Tree(XmlNode)."; std::unique_ptr program(XreateManager::prepare(move(code))); ExpandedType typeConcrete = program->root->findType("Concrete"); ASSERT_EQ(TypeOperator::LIST_NAMED, typeConcrete->__operator); ASSERT_EQ(2, typeConcrete->__operands.size()); ASSERT_EQ(TypeOperator::LIST_NAMED, typeConcrete->__operands.at(0).__operator); ASSERT_EQ(TypeOperator::LIST, typeConcrete->__operands.at(1).__operator); auto typeLink = typeConcrete->__operands.at(1).__operands.at(0); ASSERT_EQ(TypeOperator::LINK, typeLink.__operator); ASSERT_EQ(typeConcrete->conjuctionId, typeLink.conjuctionId); } TEST(Types, TreeType1LLvm) { string&& code = "XmlNode = type {\n" " tag:: string,\n" " /* attrs:: [string],*/\n" " content:: string\n" "}.\n" "" "Tree = type(Leaf) {Leaf, [Tree(Leaf)]}." "Concrete = type Tree(XmlNode)."; std::unique_ptr program(XreateManager::prepare(move(code))); ExpandedType typeConcrete = program->root->findType("Concrete"); llvm::Type* raw = program->llvm->toLLVMType(typeConcrete); } TEST(Types, ArrayOfExternal1) { FILE* input = fopen("scripts/containers/Containers_Implementation_LinkedList1.xreate", "r"); assert(input != nullptr); Scanner scanner(input); Parser parser(&scanner); parser.Parse(); AST* ast = parser.root->finalize(); CodeScope* body = ast->findFunction("test")->getEntryScope(); const ExpandedType& t2 = ast->getType(body->getDefinition(body->getSymbol("childrenRaw"))); EXPECT_EQ(t2->__operator, TypeOperator::LIST); } TEST(Types, ExternType1) { FILE* input = fopen("scripts/containers/Containers_Implementation_LinkedList1.xreate", "r"); assert(input != nullptr); Scanner scanner(input); Parser parser(&scanner); parser.Parse(); AST* ast = parser.root->finalize(); CodeScope* body = ast->findFunction("test")->getEntryScope(); const ExpandedType& t2 = ast->getType(body->getDefinition(body->getSymbol("tree"))); EXPECT_EQ(t2->__operator, TypeOperator::CUSTOM); } TEST(Types, ast_VariantType1) { string&& code = " colors = type variant {RED, BLUE, GREEN}.\n" " test = function:: colors; entry {GREEN()}"; std::unique_ptr program(XreateManager::prepare(move(code))); ExpandedType typ = program->root->findType("colors"); EXPECT_EQ(TypeOperator::VARIANT, typ->__operator); Expression eRed = program->root->findFunction("test")->getEntryScope()->getBody(); EXPECT_EQ(Operator::VARIANT, eRed.op); const ExpandedType& typ2 = program->root->getType(eRed); EXPECT_EQ(TypeOperator::VARIANT, typ2->__operator); } TEST(Types, full_VariantType_Switch1) { string&& code = "colors = type variant{RED, BLUE, GREEN}. \n" " test = function:: colors {GREEN()} \n" "main = function:: int; entry { \n" " switch(test()):: int \n" " case (GREEN()) {0} \n" " case default {1} \n" "}"; XreateManager* man = XreateManager::prepare(move(code)); int (*main)() = (int (*)()) man->run(); EXPECT_EQ(0, main()); } TEST(Types, ast_VariantType2) { std::string script = R"Code( Annotation = type variant { Num:: int, String:: string, Func:: {name::string, arguments::[Expression]} }. )Code"; std::unique_ptr program(XreateManager::prepare(move(script))); ExpandedType typ = program->root->findType("Annotation"); ASSERT_EQ(3, typ.get().fields.size()); } TEST(Types, SlaveTypes_UnwrapSlaveType1) { auto man = details::tier1::XreateManager::prepare(R"Code( AtomNumT = type slave atomNumT. AtomStrT = type slave atomStrT. CmpndIntStrT = type slave cmpndIntStrT. VariantT = type slave variantT. VariantComplicatedT = type slave variantComplicatedT. )Code"); man->transcend->addRawScript(R"RAW( atomNumT(5). atomNumT(8). atomStrT("a"). atomStrT("b"). cmpndIntStrT(1, "a"). cmpndIntStrT(2, "b"). variantT(first). variantT(second). variantT(third). variantComplicatedT(first(1, "a")). variantComplicatedT(second("b")). )RAW"); man->analyse(); ExpandedType AtomNumT = man->root->findType("AtomNumT"); ASSERT_EQ(AtomNumT->__operator, TypeOperator::SLAVE); ExpandedType ContentAtomNumT = interpretation::dereferenceSlaveType(AtomNumT, man->transcend); ASSERT_EQ(TypePrimitive::Num, ContentAtomNumT->__value); ExpandedType AtomStrT = man->root->findType("AtomStrT"); ExpandedType ContentAtomStrT = interpretation::dereferenceSlaveType(AtomStrT, man->transcend); ASSERT_EQ(TypePrimitive::String, ContentAtomStrT->__value); ExpandedType CmpndIntStrT = man->root->findType("CmpndIntStrT"); ExpandedType ContentCmpndIntStrT = interpretation::dereferenceSlaveType(CmpndIntStrT, man->transcend); ASSERT_EQ(TypeOperator::LIST_NAMED, ContentCmpndIntStrT->__operator); ASSERT_EQ(2, ContentCmpndIntStrT->__operands.size()); ExpandedType VariantT = man->root->findType("VariantT"); ExpandedType ContentVariantT = interpretation::dereferenceSlaveType(VariantT, man->transcend); ASSERT_EQ(TypeOperator::VARIANT, ContentVariantT->__operator); ASSERT_EQ(3, ContentVariantT->fields.size()); ExpandedType VariantComplicatedT = man->root->findType("VariantComplicatedT"); ExpandedType ContentVariantComplicatedT = interpretation::dereferenceSlaveType(VariantComplicatedT, man->transcend); ASSERT_EQ(TypeOperator::VARIANT, ContentVariantComplicatedT->__operator); ASSERT_EQ(2, ContentVariantComplicatedT->fields.size()); ASSERT_EQ(2, ContentVariantComplicatedT->__operands.at(0).__operands.size()); +} + +TEST(Types, IndexNumber_1) +{ + string&& code = +R"CODE( + Tuple = type {string, int}. + Int = type Tuple[1]. +)CODE"; + + std::unique_ptr program(XreateManager::prepare(move(code))); + ExpandedType typeInt = program->root->findType("Int"); } \ No newline at end of file diff --git a/cpp/tests/virtualization.cpp b/cpp/tests/virtualization.cpp index d5c10ec..fe6bc53 100644 --- a/cpp/tests/virtualization.cpp +++ b/cpp/tests/virtualization.cpp @@ -1,24 +1,60 @@ /* Any copyright is dedicated to the Public Domain. * http://creativecommons.org/publicdomain/zero/1.0/ * * virtualization.cpp * * Author: pgess * Created on February 24, 2018, 4:30 PM */ #include "xreatemanager.h" +#include "ast.h" +#include "analysis/interpretation.h" #include "gtest/gtest.h" using namespace xreate; +using namespace std; -TEST(Virtualization, test1){ - FILE* input = fopen("scripts/virtualization/test1.xreate","r"); +TEST(Virtualization, UniqueSizoPrefix_1) { + FILE* input = fopen("scripts/virtualization/test1.xreate", "r"); assert(input != nullptr); - std::unique_ptr man(XreateManager::prepare(input)); + std::unique_ptr man(details::tier1::XreateManager::prepare(input)); + man->analyse(); + + ExpandedType typeDictSizoS = man->root->findType("DictSizo"); + ExpandedType typeDictSizo = interpretation::dereferenceSlaveType(typeDictSizoS, man->transcend); + ASSERT_EQ(TypeOperator::LIST_NAMED, typeDictSizo->__operator); + int (*main)() = (int (*)())man->run(); + + testing::internal::CaptureStdout(); + main(); + std::string outputActual = testing::internal::GetCapturedStdout(); + cout << outputActual << endl; + ASSERT_STREQ("file opened: /0/test1 file opened: /1/test1 ", outputActual.c_str()); +} +TEST(Virtualization, GlobalDereferenceStrategy_1) { + FILE* input = fopen("scripts/virtualization/test2.xreate", "r"); + assert(input != nullptr); + std::unique_ptr man(XreateManager::prepare(input)); int (*main)() = (int (*)())man->run(); - int result = main(); + + testing::internal::CaptureStdout(); + main(); + std::string outputActual = testing::internal::GetCapturedStdout(); + cout << outputActual << endl; + ASSERT_STREQ("file opened: test1 file opened: test1 ", outputActual.c_str()); +} - ASSERT_EQ(1, result); -} \ No newline at end of file +TEST(Virtualization, LocalDereferenceStrategy_1) { +FILE* input = fopen("scripts/virtualization/test3.xreate", "r"); + assert(input != nullptr); + std::unique_ptr man(XreateManager::prepare(input)); + int (*main)() = (int (*)())man->run(); + + testing::internal::CaptureStdout(); + main(); + std::string outputActual = testing::internal::GetCapturedStdout(); + cout << outputActual << endl; + ASSERT_STREQ("file opened: test1 file opened: 1/test1 ", outputActual.c_str()); +} diff --git a/documentation-api/AST-correspondence.fods b/documentation-api/AST-correspondence.fods index 159b180..fb51aa6 100644 --- a/documentation-api/AST-correspondence.fods +++ b/documentation-api/AST-correspondence.fods @@ -1,558 +1,556 @@ - 2018-08-02T18:59:05.238218130LibreOffice/6.0.4.2$Linux_X86_64 LibreOffice_project/00m0$Build-22018-08-15T21:01:52.425281983PT4H11M37S4 + 2018-08-02T18:59:05.238218130LibreOffice/6.0.5.2$Linux_X86_64 LibreOffice_project/00m0$Build-22018-09-19T18:48:14.346688728PT4H42M8S7 0 0 38555 - 17596 + 18048 view1 1 - 21 + 25 0 0 0 0 2 0 0 0 - 0 + 9 0 100 60 true false Sheet1 - 585 + 1241 0 100 60 false true true true 12632256 true true true true false false false 1270 1270 1 1 true false 7 true false false 0 true - sgH+/0xleG1hcmstWDY1NmRlAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQ1VQUzpMZXhtYXJrLVg2NTZkZQAAAAAAAAAAAAAAAAAWAAMA0wAAAAAAAAAIAFZUAAAkbQAASm9iRGF0YSAxCnByaW50ZXI9TGV4bWFyay1YNjU2ZGUKb3JpZW50YXRpb249UG9ydHJhaXQKY29waWVzPTEKY29sbGF0ZT1mYWxzZQptYXJnaW5kYWp1c3RtZW50PTAsMCwwLDAKY29sb3JkZXB0aD0yNApwc2xldmVsPTAKcGRmZGV2aWNlPTEKY29sb3JkZXZpY2U9MApQUERDb250ZXhEYXRhCklucHV0U2xvdDpUcmF5MQBEdXBsZXg6Tm9uZQBQYWdlU2l6ZTpMZXR0ZXIAABIAQ09NUEFUX0RVUExFWF9NT0RFDwBEdXBsZXhNb2RlOjpPZmY= + sgH+/0xleG1hcmstWDY1NmRlAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQ1VQUzpMZXhtYXJrLVg2NTZkZQAAAAAAAAAAAAAAAAAWAAMA0wAAAAAAAAAIAFZUAAAkbQAASm9iRGF0YSAxCnByaW50ZXI9TGV4bWFyay1YNjU2ZGUKb3JpZW50YXRpb249UG9ydHJhaXQKY29waWVzPTEKY29sbGF0ZT1mYWxzZQptYXJnaW5kYWp1c3RtZW50PTAsMCwwLDAKY29sb3JkZXB0aD0yNApwc2xldmVsPTAKcGRmZGV2aWNlPTEKY29sb3JkZXZpY2U9MApQUERDb250ZXhEYXRhClBhZ2VTaXplOkxldHRlcgBEdXBsZXg6Tm9uZQBJbnB1dFNsb3Q6VHJheTEAABIAQ09NUEFUX0RVUExFWF9NT0RFDwBEdXBsZXhNb2RlOjpPZmY= Lexmark-X656de true 3 true false true true 12632256 true true true false true false true 1 false 1270 1270 false 1 true - - - + ??? Page 1 ???(???) - 00/00/0000, 00:00:00 + 00/00/0000, 00:00:00 Page 1/ 99 AST Current Transcend Proposition 1 Types Tests Expr op id state bindings operands type tags bind(var, annotation) blocks value CodeScope scope(scopeId) ast_scope(scopeId) bindings ast_scope_binding(scopeId, BindingId, ScopeBindName) ast_scope_binding(scopeId, BindingId, ScopeBindName) LIST CFA.ASTCorrespondence_Scope_Bindings_1 identifiers ast_scope_identifier(scopeId, Var) LIST parent cfa_parent(scopeCurrent, scope(scopeParent)) ast_scope_parent(ScopeId, ScopeParentId) SINGLE declarations LIST tags bind_scope(scopeId, tag, strong/weak(..)) LIST contextRules Function entry cfa_parent(scopeEntry, functon(name)) SINGLE name function(name) SINGLE guard cfa_function_specializations(funcName, tag) SINGLE tags - bind_function(name, tag) + bind_func(name, tag) LIST - + Special Expressions CALL cfa_call(scopeFrom, functionTo)dfa_callfn(SymbRet, FnName)weak/dfa_callargs(SymbRet, argFormal, argActual)weak/dfa_alias(aliasFormal, Actual) OTHER var: s(id, version, scope), a(Num) v(var1) dfa_fnret(fnName, symbRet) \ No newline at end of file diff --git a/documentation-api/latereasoning.graphml b/documentation-api/latereasoning.graphml index 481aca0..25c65a6 100644 --- a/documentation-api/latereasoning.graphml +++ b/documentation-api/latereasoning.graphml @@ -1,545 +1,552 @@ - Late Reasonng Diagram - Pass - Interpretation + Late Reasonng Diagram + Pass + Interpretation - Transcend + Transcend - LateReasoning + LateReasoning Scope - fvffdfd - vdffldkjfd + fvffdfd + vdffldkjfd fdfdfd - + - LateReasoning + LateReasoning DFAPass Decorator - fvffdfd - vdffldkjfd + fvffdfd + vdffldkjfd fdfdfd registerLateScope processAnnotations - DFAPass + DFAPass - ICodeScope + ICodeScope - LateSymbol + LateSymbol Recognized - DFAGraph + DFAGraph - + - LateReasoning + LateReasoning Compiler processSwitchLateStatement compileAutoExpand - +findKeys - + - LateReasoning + LateReasoning Transcend Decorator - findKeys + queryLate +processSolution - Transcend + Transcend Layer - + - LateAnnotations + LateAnnotations Group select() - Late + Late Annotation - Transcend + Transcend program - DFA + DFA PassDec - Interpretation + Interpretation Scope - LR + LR Trans Dec - AST + AST getType - fvffdfd - vdffldkjfd + fvffdfd + vdffldkjfd fdfdfd - dereferenceSlaveType + dereferenceSlaveType - + + + + - + + + + diff --git a/documentation-api/latex.graphml b/documentation-api/latex.graphml index 7c0447f..818a882 100644 --- a/documentation-api/latex.graphml +++ b/documentation-api/latex.graphml @@ -1,834 +1,819 @@ Latex Compilation Transcend Interpretation ExtraArgs FnInvocation Latex BruteScope Dec ICodeScopeUnit Latex BruteFunction Dec IFunctionUnit getSubjectDomain Latex Query IQuery collapseColumn Latex Query represent Trans Expression Latex script Latex script Latex Output Processing Input - + Demand upstream scope_demand latex_registered_subjects scope_demand(1) fn_demand decision scope_demand(2) late(decision) scope_fn - + - fn_signature_size + fn_demand_ordered - + - fn_demand_ordered + latex_symbol - - - - - - - - - - - - - - + - + - + - - + - diff --git a/documentation-api/polymorphism.graphml b/documentation-api/polymorphism.graphml index 43eea1f..baa6ea4 100644 --- a/documentation-api/polymorphism.graphml +++ b/documentation-api/polymorphism.graphml @@ -1,309 +1,338 @@ - + - Polymorphism - Compilation - Transcend + Polymorphism + Compilation + Transcend - + - + - + - Polymorph + Polymorph Query - + - IQuery + IQuery - Polymorph + Polymorph CodeScopeUnit findFunction - + - ICodeScopeUnit + ICodeScopeUnit - Polymorph + Polymorph FnInvocation - P.Query + P.Query - + - PSCU + PSCU + + + + + + + + IFnInvocation + + + + + + + - InterpretationScope + InterpretationScope - LateReasoningCompiler + LateReasoningCompiler - + + + + + + + + + + + + + + + diff --git a/grammar/gen-grammar b/grammar/gen-grammar index f387d59..8d1c31c 100755 --- a/grammar/gen-grammar +++ b/grammar/gen-grammar @@ -1,9 +1,11 @@ +#!/bin/bash + COCO_EXECUTABLE=${2:-cococpp} COCO_FRAMES_PATH=${3:-/usr/share/coco-cpp/} echo "Run coco generator: " case $1 in main) $COCO_EXECUTABLE ./xreate.ATG -frames $COCO_FRAMES_PATH -o main -namespace xreate::grammar::main;; modules) $COCO_EXECUTABLE ./modules.ATG -frames $COCO_FRAMES_PATH -o modules -namespace xreate::modules;; esac diff --git a/grammar/xreate.ATG b/grammar/xreate.ATG index a880168..5342343 100644 --- a/grammar/xreate.ATG +++ b/grammar/xreate.ATG @@ -1,676 +1,708 @@ //TODO add ListLiteral //TODO ExprTyped: assign default(none) type #include "ast.h" #include "ExternLayer.h" #include #include #define wprintf(format, ...) \ char __buffer[100]; \ wcstombs(__buffer, format, 100); \ fprintf(stderr, __buffer, __VA_ARGS__) using namespace std; COMPILER Xreate details::inconsistent::AST* root = nullptr; // current program unit void ensureInitalizedAST(){ if (root == nullptr) root = new details::inconsistent::AST(); } struct { std::stack scopesOld; CodeScope* scope = nullptr; } context; void pushContextScope(CodeScope* scope){ context.scopesOld.push(context.scope); context.scope = scope; } void popContextScope(){ context.scope = context.scopesOld.top(); context.scopesOld.pop(); } int nextToken() { scanner->ResetPeek(); return scanner->Peek()->kind; } bool checkTokenAfterIdent(int key){ if (la->kind != _ident) return false; return nextToken() == key; } bool checkParametersList() { return la->kind == _ident && nextToken() == _lparen; } bool checkInfix() { return la->kind == _ident && nextToken() == _ident; } bool checkIndex() { return la->kind == _ident && nextToken() == _lbrack; } bool checkFuncDecl() { if (la->kind != _ident) return false; int token2 = nextToken(); int token3 = scanner->Peek()->kind; return token2 == _assign && (token3 == _function || token3 == _pre); } bool checkAssignment() { if (la->kind != _ident) return false; scanner->ResetPeek(); int token2 = scanner->Peek()->kind; if (token2 == _lcurbrack) { scanner->Peek(); int token3 = scanner->Peek()->kind; if (token3 != _rcurbrack) return false; int token4 = scanner->Peek()->kind; return token4 == _assign; } return token2 == _assign; } void recognizeIdentifier(Expression& i){ if (!context.scope->recognizeIdentifier(i)){ root->postponeIdentifier(context.scope, i); } } enum SwitchKind{SWITCH_NORMAL, SWITCH_META}; CHARACTERS letter = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz". any = ANY - '"'. digit = "0123456789". cr = '\r'. lf = '\n'. tab = '\t'. TOKENS ident = (letter | '_') {letter | digit | '_'}. number = (digit | '-' digit) {digit}. string = '"' { any } '"'. function = "function". pre = "pre". comma = ','. period = '.'. lparen = '('. rparen = ')'. lbrack = '['. rbrack = ']'. lcurbrack = '{'. rcurbrack = '}'. equal = "==". assign = '='. implic = '-' '>'. colon = ':'. context = "context". tagcolon = "::". lse = "<=". lss = "<". gte = ">=". gtr = ">". ne1 = "!=". ne2= "<>". COMMENTS FROM "/*" TO "*/" NESTED COMMENTS FROM "//" TO lf IGNORE cr + lf + tab PRODUCTIONS Xreate = (. Function* function; ensureInitalizedAST(); .) {( RuleDecl | InterfaceData | Imprt | GuardSection | IF(checkFuncDecl()) FDecl (. root->add(function); .) | TDecl | SkipModulesSection )} (. .) . Ident = ident (. name = t->val; .). VarIdent = ident (. e = Expression(Atom(t->val)); .) [ lcurbrack ( ident (. SemErr(coco_string_create("var version as ident is not implemented yet")); .) | number (. Attachments::put(e, Atom(t->val).get()); .) ) rcurbrack ] . FDecl = (. std::wstring fname; std::wstring argName; TypeAnnotation typIn; TypeAnnotation typOut; bool flagIsPrefunct = false; Expression binding; .) Ident assign [pre (. flagIsPrefunct = true; .)] function (. f = new Function(fname); f->isPrefunction = flagIsPrefunct; CodeScope* entry = f->getEntryScope(); .) [lparen Ident tagcolon ExprAnnotations (. f->addBinding(Atom(argName), move(binding)); .) {comma Ident tagcolon ExprAnnotations (. f->addBinding(Atom (argName), move(binding));.) } rparen] [ tagcolon ( IF(flagIsPrefunct) FnTag | Type ) {';' FnTag }] BDecl (. const_cast(entry->getBody()).bindType(move(typOut));.) . GuardSection<>= (. Expression guard; Function* f; .) "guard" tagcolon MetaSimpExpr lcurbrack { FDecl (. f->guard = guard; root->add(f); .) } rcurbrack. /** * TYPES * */ TypeTerm = (. std::wstring tid; .) ("string" (. typ = TypePrimitive::String;.) | "num" (. typ = TypePrimitive::Num;.) | "int" (. typ = TypePrimitive::Int;.) | "float" (. typ = TypePrimitive::Float;.) | "bool" (. typ = TypePrimitive::Bool; .) | "i8" (. typ = TypePrimitive::I8; .) | "i32" (. typ = TypePrimitive::I32; .) | "i64" (. typ = TypePrimitive::I64; .) ). -Type = (. TypeAnnotation typ2; TypePrimitive typ3; std::wstring tid, field; .) +Type = (. TypeAnnotation typ2; TypePrimitive typ3; std::wstring tid; std::string field; .) ( TList | TStruct | TVariant | TSlave | TypeTerm (. typ = typ3; .) | IF (checkIndex()) Ident lbrack - Ident (. typ = TypeAnnotation(TypeOperator::ACCESS, {}); typ.__valueCustom = Atom(tid).get(); typ.fields.push_back(Atom(field).get()); .) - {comma Ident (. typ.fields.push_back(Atom(field).get()); .) - } rbrack + TypeIndex (. typ = TypeAnnotation(TypeOperator::ACCESS, {}); typ.__valueCustom = Atom(tid).get(); typ.fields.push_back(field); .) + {comma TypeIndex (. typ.fields.push_back(field); .) + } rbrack | Ident (. typ = TypeAnnotation(TypeOperator::CUSTOM, {}); typ.__valueCustom = Atom(tid).get(); .) [lparen Type (. typ.__operator = TypeOperator::CALL; typ.__operands.push_back(typ2); .) {comma Type (. typ.__operands.push_back(typ2); .) } rparen] ) . +TypeIndex = +( + number (. name = Atom(t->val).get(); .) + | string (. name = Atom(t->val).get(); .) +) +. + TList = (. TypeAnnotation ty; .) lbrack Type rbrack (. typ = TypeAnnotation(TypeOperator::LIST, {ty}); .) . TStruct = (. TypeAnnotation t; std::wstring key; size_t keyCounter=0; .) lcurbrack ( IF(checkTokenAfterIdent(_tagcolon)) Ident tagcolon Type | Type (. key = to_wstring(keyCounter++); .) ) (. typ = TypeAnnotation(TypeOperator::LIST_NAMED, {t}); typ.fields.push_back(Atom(key).get()); .) {comma ( IF(checkTokenAfterIdent(_tagcolon)) Ident tagcolon Type | Type (. key = to_wstring(keyCounter++); .) ) (. typ.__operands.push_back(t); typ.fields.push_back(Atom(key).get()); .) } rcurbrack. TVariant= (. TypeAnnotation t, typVoid; std::vector operands; std::vector> keys; std::wstring variant; .) "variant" lcurbrack Ident (. t=typVoid; .) [tagcolon Type] (. keys.push_back(Atom(variant)); operands.push_back(t); .) {comma Ident (. t=typVoid; .) [tagcolon Type] (. keys.push_back(Atom(variant)); operands.push_back(t); .) } rcurbrack (. typ = TypeAnnotation(TypeOperator::VARIANT, {}); typ.__operands = operands; typ.addFields(std::move(keys)); .) . TSlave= (. std::wstring identMaster; .) "slave" Ident (. typ = TypeAnnotation(TypeOperator::SLAVE, {}); typ.__valueCustom = Atom(identMaster).get(); .) . TDecl = (. TypeAnnotation t; std::wstring tname, arg; std::vector> args; .) Ident assign "type" [lparen Ident (. args.push_back(Atom(arg)); .) {comma Ident (. args.push_back(Atom(arg)); .) } rparen] Typeperiod (. t.addBindings(move(args)); root->add(move(t), Atom(tname)); .) . ContextDecl = (. Expression tag; .) context tagcolon MetaSimpExpr (. scope->tags.push_back(tag); .) {';' MetaSimpExpr (. scope->tags.push_back(tag); .) }. VDecl = (. std::wstring vname; Expression var, value;.) VarIdent assign ExprTyped (. Symbol identSymbol = f->addDefinition(move(var), move(value)); Attachments::put(value, identSymbol); .) . BDecl = lcurbrack (. Expression body; pushContextScope(scope); .) {(IF(checkAssignment()) VDecl period | RuleContextDecl | ContextDeclperiod | ExprTyped (. scope->setBody(body); Attachments::put(body, Symbol{ScopedSymbol::RetSymbol, scope});.) )} rcurbrack (. popContextScope(); .) . IfDecl = (. Expression cond; ManagedScpPtr blockTrue = root->add(new CodeScope(context.scope)); ManagedScpPtr blockFalse = root->add(new CodeScope(context.scope)); .) "if" lparen Expr rparen (. e = Expression(Operator::IF, {cond}); .) tagcolon ExprAnnotations BDecl<&*blockTrue> "else" BDecl<&*blockFalse> (. e.addBlock(blockTrue); e.addBlock(blockFalse); .) . LoopDecl = (. Expression eIn, eAcc, eFilters; std::wstring varEl, varAcc, contextClass; Expression tagsEl; ManagedScpPtr block = root->add(new CodeScope(context.scope)); .) "loop" ("map" lparen Expr implic Ident (. e = Expression(Operator::MAP, {eIn}); .) tagcolon ExprAnnotations rparen tagcolon ExprAnnotations (. e.addBindings({Atom(varEl)}); block->addBinding(Atom(varEl), move(tagsEl)); .) BDecl<&*block> (. e.addBlock(block); .) |"fold" ("inf" lparen Expr implic Ident rparen (. e = Expression(Operator::FOLD_INF, {eAcc}); e.addBindings({Atom(varAcc)}); block->addBinding(Atom(varAcc), Expression()); .) tagcolon ExprAnnotations BDecl<&*block> (. e.addBlock(block); .) | lparen Expr implic Ident tagcolon ExprAnnotations ['|' Expr ] comma Expr implic Identrparen (. e = Expression(Operator::FOLD, {eIn, eAcc}); e.addBindings({Atom(varEl), Atom(varAcc)}); .) tagcolon ExprAnnotations (. block->addBinding(Atom(varEl), move(tagsEl)); block->addBinding(Atom(varAcc), Expression()); .) BDecl<&*block> (. e.addBlock(block); .) ) ). // Switches SwitchDecl = (. TypeAnnotation typ; eSwitch = Expression(Operator::SWITCH, {}); Expression eCondition; Expression tag;.) "switch" ( SwitchVariantDecl | SwitchLateDecl | lparen ExprTyped rparen tagcolon ExprAnnotations (. eSwitch.operands.push_back(eCondition);.) CaseDecl {CaseDecl} ) . CaseDecl = (. ManagedScpPtr scope = root->add(new CodeScope(context.scope)); Expression condition; .) "case" ( IF(flagSwitchKind == SWITCH_META) lparen MetaSimpExpr rparen BDecl<&*scope> (. Expression exprCase(Operator::CASE, {}); exprCase.addTags({condition}); exprCase.addBlock(scope); outer.addArg(move(exprCase));.) | "default" BDecl<&*scope> (. Expression exprCase(Operator::CASE_DEFAULT, {}); exprCase.addBlock(scope); outer.operands.insert(++outer.operands.begin(), exprCase); .) | lparen CaseParams<&*scope> rparen (. ManagedScpPtr scopeBody = root->add(new CodeScope(&*scope)); Expression exprCase(Operator::CASE, {}); .) BDecl<&*scopeBody> (. exprCase.addBlock(scope); exprCase.addBlock(scopeBody); outer.addArg(move(exprCase)); .) ). CaseParams = (. Expression condition; Expression guard(Operator::LOGIC_AND, {}); pushContextScope(scope); .) ExprTyped (. guard.addArg(Expression(condition)); .) {comma ExprTyped (. guard.addArg(Expression(condition)); .) } (. scope->setBody(guard); popContextScope(); .) . SwitchLateDecl = (. std::wstring aliasCondition; Expression exprCondition, aliasAnns; expr = Expression(Operator::SWITCH_LATE, {}); ManagedScpPtr scope = root->add(new CodeScope(context.scope)); .) "late" lparen Expr [implic Ident] [tagcolon ExprAnnotations] rparen tagcolon ExprAnnotations BDecl<&*scope> (. expr.addArg(Expression(exprCondition)); expr.addBlock(scope); std::string alias; if(aliasCondition.empty()){ if(exprCondition.__state != Expression::IDENT){ SemErr(coco_string_create("An identifier expected in the short form")); return; } //Use exprCondition as identifier alias = exprCondition.getValueString(); } else { //Use aliasCondition alias = Atom(move(aliasCondition)).get(); } expr.addBindings({Atom(string(alias))}); scope->addBinding(Atom(move(alias)), move(aliasAnns)); .) . SwitchVariantDecl = (. Expression varTested; std::wstring varAlias; bool flagAliasFound = false; expr = Expression(Operator::SWITCH_VARIANT, {}); .) "variant" lparen Expr [implic Ident (. flagAliasFound = true; .) ] [tagcolon ExprAnnotations] rparen tagcolon ExprAnnotations (. expr.addArg(std::move(varTested)); if (flagAliasFound) { expr.addBindings({Atom(varAlias)}); } else { if(varTested.__state == Expression::IDENT){ expr.addBindings({Atom(string(varTested.getValueString()))}); } } .) CaseVariantDecl {CaseVariantDecl} . CaseVariantDecl = (. ManagedScpPtr scope = root->add(new CodeScope(context.scope)); std::wstring key; scope->addBinding(Atom(string(expr.bindings.front())), Expression()); .) "case" lparen Ident rparen (. expr.addArg(root->recognizeVariantConstructor(Atom(std::move(key)))); .) BDecl<&*scope> (. expr.addBlock(scope); .) . IntrinsicDecl= (. std::wstring name; .) -"intrinsic" Ident< name> (. outer = Expression(Operator::CALL_INTRINSIC, {}); outer.setValue(Atom(name)); .) -lparen [CalleeParams] rparen . + "intrinsic" +( + Ident< name> lparen [CalleeParams] rparen + (. outer = Expression(Operator::CALL_INTRINSIC, {}); outer.setValue(Atom(name)); .) + | "query" (. outer = Expression(Operator::QUERY, {}); .) + ( + "late" IntrinsicQueryLateDecl + | lparen [CalleeParams] rparen + ) +). + +IntrinsicQueryLateDecl = + (. + std::wstring predicateAlias; Expression predicateE, predicateAnns; + expr = Expression(Operator::QUERY_LATE, {}); + ManagedScpPtr scope = root->add(new CodeScope(context.scope)); + .) + + lparen Expr implic Ident tagcolon ExprAnnotations rparen + tagcolon ExprAnnotations BDecl<&*scope> + (. + expr.addArg(move(predicateE)); + expr.addBindings({Atom(wstring(predicateAlias))}); + scope->addBinding(Atom(move(predicateAlias)), move(predicateAnns)); + expr.addBlock(scope); + .) +. SequenceDecl = (. sequence = Expression(); sequence.setOp(Operator::SEQUENCE); ManagedScpPtr scope = root->add(new CodeScope(context.scope)); .) "seq" BDecl<&*scope> (. sequence.blocks.push_back(&*scope); scope = root->add(new CodeScope(&*scope)); .) { (. scope = root->add(new CodeScope(&*scope)); .) BDecl<&*scope> (. sequence.blocks.push_back(&*scope); .) }. /*============================ INTERFACES ===============================*/ Imprt<> = "import" "raw" lparen string (. root->__rawImports.push_back(Atom(t->val).get()); .) rparen period. InterfaceData<> = "interface" lparen ( "dfa" rparen InterfaceDFA | "extern-c" rparen InterfaceExternC | "cfa" rparen InterfaceCFA ). InterfaceExternC<> = (. ExternData data; .) lcurbrack {IncludeExternDecl | LibExternDecl } rcurbrack (. root->addExternData(move(data)); .) . LibExternDecl = (. std::wstring pkgname, libname; .) Ident assign "library" tagcolon "pkgconfig" lparen string (. pkgname = t->val; .) rparen period (. data.addLibrary(Atom(libname), Atom(pkgname)); .) . IncludeExternDecl = (. Expression inc; .) "include" StructLiteral period (. data.addIncludeDecl(move(inc)); .) . InterfaceDFA<> = lcurbrack { InstructDecl } rcurbrack . InstructDecl = (.Operator op; Expression tag; Expression scheme; std::vector& tags = scheme.operands; tags.push_back(Expression()); /* return value */ .) "operator" InstructAlias tagcolon lparen (.scheme.setOp(op); .) [ MetaSimpExpr (. tags.push_back(tag); .) { comma MetaSimpExpr (. tags.push_back(tag); .) } ] rparen [ implic MetaSimpExpr (. tags[0] = tag; .) ] (. root->addDFAData(move(scheme)); .) period. InstructAlias = ( "map" (. op = Operator::MAP; .) | "list_range" (. op = Operator::LIST_RANGE; .) | "list" (. op = Operator::LIST; .) | "fold" (. op = Operator::FOLD; .) | "index" (. op = Operator::INDEX; .) ). InterfaceCFA<> = lcurbrack { InstructCFADecl } rcurbrack . InstructCFADecl<> = (.Operator op; Expression tag; Expression scheme; std::vector& tags = scheme.operands; .) "operator" InstructAlias tagcolon (. scheme.setOp(op); .) [ MetaSimpExpr (. tags.push_back(tag); .) { comma MetaSimpExpr (. tags.push_back(tag); .) } ] period (. root->addInterfaceData(CFA, move(scheme)); .). /*============================ METAPROGRAMMING ===============================*/ // TagsDecl = (. Expression tag; TagModifier mod = TagModifier::NONE; .) // ':' { MetaSimpExpr (. /*f.addTag(std::move(tag), mod); */ .) // }. FnTag = (. Expression tag; TagModifier mod = TagModifier::NONE; .) MetaSimpExpr ['-' TagMod] (. f->addTag(std::move(tag), mod); .). TagMod = ( "assert" (. mod = TagModifier::ASSERT; .) | "require" (. mod = TagModifier::REQUIRE; .) ). RuleDecl<> = "rule" tagcolon (. RuleArguments args; RuleGuards guards; DomainAnnotation typ; std::wstring arg; .) lparen Ident tagcolon Domain (. args.add(arg, typ); .) {comma Ident tagcolon Domain (. args.add(arg, typ); .) } rparen ["case" RGuard {comma RGuard}] lcurbrack RBody rcurbrack . /* - TODO use RGuard for guards-*/ RuleContextDecl = (.Expression eHead, eGuards, eBody; .) "rule" "context" tagcolon MetaSimpExpr "case" lparen MetaSimpExpr rparen lcurbrack MetaSimpExpr rcurbrack (.scope->contextRules.push_back(Expression(Operator::CONTEXT_RULE, {eHead, eGuards, eBody})); .). Domain = ( "function" (. dom = DomainAnnotation::FUNCTION; .) | "variable" (. dom = DomainAnnotation::VARIABLE; .) ). RGuard= (. Expression e; .) MetaExpr (. guards.add(std::move(e)); .). MetaExpr= (.Operator op; Expression e2; .) MetaExpr2 [MetaOp MetaExpr2 (. e = Expression(op, {e, e2}); .) ]. MetaExpr2= ( lparen MetaExpr rparen | MetaSimpExpr ). MetaSimpExpr= (. std::wstring i1, infix; Expression e2; .) ( '-' MetaSimpExpr (. e = Expression(Operator::NEG, {e2}); .) | IF(checkParametersList()) Ident (. e = Expression(Operator::CALL, {Expression(Atom(i1))}); .) lparen [ MetaCalleeParams ] rparen | IF(checkInfix()) Ident Ident MetaSimpExpr (. e = Expression(Operator::CALL, {Expression(Atom(infix))}); e.addArg(Expression(Atom(i1))); e.addArg(std::move(e2)); .) | Ident (. e = Expression(Operator::CALL, {Atom(i1)}); .) ). MetaCalleeParams = (. Expression e2; .) MetaSimpExpr (. e.addArg(Expression(e2)); .) {comma MetaSimpExpr (. e.addArg(Expression(e2)); .) }. RBody = (. Expression e; std::wstring msg; .) "warning" MetaExpr ["message" string (. msg = t->val; .) ] (. root->add(new RuleWarning(RuleArguments(args), RuleGuards(guards), std::move(e), Atom(msg))); .) . MetaOp< Operator& op> = implic (. op = Operator::IMPL; .) . /*============================ Expressions ===============================*/ ExprAnnotations = (. TypeAnnotation typ; std::list tags; Expression tag; e.tags.clear();.) Type (. e.bindType(move(typ)); .) {';' MetaSimpExpr (. tags.push_back(tag); .) } (. e.addTags(tags); .) . ExprTyped = Expr [tagcolon ExprAnnotations]. Expr< Expression& e> (. Operator op; Expression e2; .) = ExprArithmAdd [ RelOp ExprArithmAdd (. e = Expression(op, {e, e2}); .) ]. ExprArithmAdd< Expression& e>= (. Operator op; Expression e2; .) ExprArithmMul< e> [ AddOp< op> ExprArithmAdd< e2> (. e = Expression(op, {e, e2});.) ]. ExprArithmMul< Expression& e> (. Operator op; Expression e2; .) = ExprPostfix< e> [ MulOp< op> ExprArithmMul< e2> (. e = Expression(op, {e, e2}); .) ]. ExprPostfix = Term [ (. e = Expression(Operator::INDEX, {e}); .) {lbrack CalleeParams rbrack } ]. Term< Expression& e> (. std::wstring name; e = Expression(); .) = (IF (checkParametersList()) Ident< name> (. e = Expression(Operator::CALL, {Atom(name)}); root->recognizeVariantConstructor(e); .) lparen [CalleeParams] rparen | VarIdent (. recognizeIdentifier(e); .) | ListLiteral (. /* tuple */.) | StructLiteral (. /* struct */.) | LoopDecl | IfDecl | SwitchDecl | IntrinsicDecl | SequenceDecl | number (. e = Expression(Atom(t->val)); .) | string (. e = Expression(Atom(t->val)); .) | "true" (. e = Expression(Atom(1)); e.bindType(TypePrimitive::Bool); .) | "false" (. e = Expression(Atom(0)); e.bindType(TypePrimitive::Bool); .) | "undef" (. e = Expression(Operator::UNDEF, {}); .) | '-' Term (. e = Expression(Operator::NEG, {e}); .) | lparen ExprTyped rparen ). StructLiteral = (. std::wstring key; Expression val; std::list> keys; size_t keyCounter=0; .) lcurbrack (IF(checkTokenAfterIdent(_assign)) Ident assign Expr | Expr (. key = to_wstring(keyCounter++); .) ) (. keys.push_back(Atom(key)); e = Expression(Operator::LIST_NAMED, {val}); .) {comma (IF(checkTokenAfterIdent(_assign)) Ident assign Expr | Expr (. key = to_wstring(keyCounter++); .) ) (. e.addArg(Expression(val)); keys.push_back(Atom(key)); .) } rcurbrack (. e.addBindings(keys.begin(), keys.end()); .) . ListLiteral = (. Expression eFrom, eTo; .) lbrack (. e.setOp(Operator::LIST); .) [ Expr (. e.addArg(Expression(eFrom)); .) ( ".." Expr (. e.addArg(Expression(eTo)); e.setOp(Operator::LIST_RANGE); .) |{comma Expr (. e.addArg(Expression(eFrom)); .) } ) ] rbrack. CalleeParams = (. Expression e2; .) ExprTyped (. e.addArg(Expression(e2)); .) {comma ExprTyped (. e.addArg(Expression(e2)); .) }. AddOp< Operator& op> = (. op = Operator::ADD; .) ( '+' | '-' (. op = Operator::SUB; .) ). MulOp< Operator& op> = (. op = Operator::MUL; .) ( '*' | '/' (. op = Operator::DIV; .) ). RelOp< Operator& op> = (. op = Operator::EQU; .) ( equal | (ne1 | ne2) (. op = Operator::NE; .) | lse (. op = Operator::LSE; .) | lss (. op = Operator::LSS; .) | gte (. op = Operator::GTE; .) | gtr (. op = Operator::GTR; .) ). SkipModulesSection = "module" lcurbrack {ANY} rcurbrack. END Xreate. diff --git a/scripts/cfa/context.lp b/scripts/cfa/context.lp index eb6c9ef..b8167e0 100644 --- a/scripts/cfa/context.lp +++ b/scripts/cfa/context.lp @@ -1,106 +1,106 @@ % This Source Code Form is subject to the terms of the Mozilla Public % License, v. 2.0. If a copy of the MPL was not distributed with this % file, You can obtain one at http://mozilla.org/MPL/2.0/. %% INPUT: %% - latex_scope_demand(Scope, Subject) %% Initial demand from clients %% %% - latex_registered_subjects(Subject, PossibleDecision) %% Clients register possible decisions for respective subjects %% %% - latex_fn_signature %% %% OUTPUT: %% - latex_fn_demand(Fn, Subject) %% Which functions demand hidden latex arguments %% %% - latex_decision(Scope, Subject, Decision) %% Provided decisions, values for hidden latex arguments %% %% SIGNATURES: %% -Subject: string %% % CONTEXT PROPAGATION %=========================================================== % nested scope propagation: bind_scope(Scope, Context, Info):- bind_scope(ScopeParent, Context, Info); cfa_parent(Scope, scope(ScopeParent)). % Strong or Uniform inter-function propagation: bind_scope(Scope, Context, Info):- bind_scope(ScopeParent, Context, Info): cfa_call(ScopeParent, FnCurrent); cfa_parent(Scope, function(FnCurrent)); cfa_call(_, FnCurrent); bind_scope(_, Context, Info); scope(Scope). % weak inter-function propagation bind_scope(Scope, Context, weak(ScopeParent)):- not bind_scope(Scope, Context, strong); bind_scope(ScopeParent, Context, strong); cfa_call(ScopeParent, FnCurrent); cfa_parent(Scope, function(FnCurrent)). % DEMAND %=========================================================== %demand propagations: scope level latex_scope_demand(Scope, Subject):- latex_scope_demand(ScopeChild, Subject); cfa_parent(ScopeChild, scope(Scope)). %propagation: fn level latex_fn_demand(Fn, Subject):- latex_scope_demand(ScopeFnBody, Subject); cfa_parent(ScopeFnBody, function(Fn)). latex_fn_demand_ordered(Fn, Subject, Id):- Id= #sum{ 1, SubjLess : latex_fn_demand(Fn, SubjLess), SubjLess < Subject}; latex_fn_demand(Fn, Subject). %propagation: inter-fn level latex_scope_demand(Scope, Subject):- latex_fn_demand(FnCallee, Subject); not latex_decision(Scope, Subject, _); cfa_call(Scope, FnCallee). % DECISIONS %=========================================================== latex_decision(Scope, Subject, Decision):- latex_fn_demand(FnCallee, Subject); bind_scope(Scope, Decision, strong); cfa_call(Scope, FnCallee); latex_registered_subjects(Subject, Decision). -latex_fn_signature_size(Fn, IdMax + 1):- - IdMax = #max{ Id, Id : ast_scope_binding(FnBody, Id, _) }; - cfa_parent(FnBody, function(Fn)). - -latex_fn_signature_size(Fn, 0):- - not ast_scope_binding(FnBody, _, _); - cfa_parent(FnBody, function(Fn)). - %late decision -late((ScopeCaller, Subject), s(Size + SubjOrder+1, -2, FnCallerBody), (AnyDecision), latex_decision(ScopeCaller, Subject, AnyDecision)):- +late((ScopeCaller, Subject), SubjectS, (AnyDecision), latex_decision(ScopeCaller, Subject, AnyDecision)):- scope_fn(ScopeCaller, FnCaller); cfa_parent(FnCallerBody, function(FnCaller)); - latex_fn_signature_size(FnCaller, Size); - latex_fn_demand_ordered(FnCaller, Subject, SubjOrder); + latex_symbol(FnCaller, Subject, SubjectS); cfa_call(ScopeCaller, FnCallee); latex_fn_demand(FnCallee, Subject); latex_registered_subjects(Subject, AnyDecision). +% UTILITY +%=========================================================== +latex_symbol(Fn, Topic, s(TopicsOffset + TopicId, -2, FnBody)):- + cfa_parent(FnBody, function(Fn)); + latex_parameters_group_offset(TopicsOffset); + latex_fn_demand_ordered(Fn, Topic, TopicId). + % IMPLEMENTATION %=========================================================== scope_fn(Scope, Fn):-cfa_parent(Scope, function(Fn)). scope_fn(Scope, Fn):- scope_fn(ScopeParent, Fn); cfa_parent(Scope, scope(ScopeParent)). + +latex_parameters_group_offset(1000). diff --git a/scripts/containers/Containers_Implementation_LinkedList1.xreate b/scripts/containers/Containers_Implementation_LinkedList1.xreate index 510191f..6e26185 100644 --- a/scripts/containers/Containers_Implementation_LinkedList1.xreate +++ b/scripts/containers/Containers_Implementation_LinkedList1.xreate @@ -1,50 +1,50 @@ /* Any copyright is dedicated to the Public Domain. * http://creativecommons.org/publicdomain/zero/1.0/ */ // EXTERN INCLUDES interface(extern-c){ xml2 = library:: pkgconfig("libxml-2.0"). include { xml2 = ["libxml/tree.h"] }. } // CONTAINERS interface(dfa) { operator map:: (op(seqaccess)) -> impl(solid). operator list_range:: ()->impl(on_the_fly). operator list:: ()->impl(solid). operator fold:: (op(seqaccess)). /* operator index:: (op(randaccess)). - BREAKS THE ANALYSIS. MAKE tree VIEWED AS COLLECTION */ /* operator map: (op(seqaccess)) -> impl(llvm_array | on_the_fly); */ } -import raw("core/containers.lp"). +import raw("scripts/containers/containers.lp"). // PROGRAM XmlNode = type { tag:: string, /* attrs:: [string],*/ content:: string }. Tree = type {Leaf, [Tree(Leaf)]}. XmlTree = type Tree(XmlNode). test= function:: num; entry { filename = "scripts/containers/Containers_Implementation_LinkedList1-data.xml" :: string. docRaw = xmlParseFile(filename) :: xmlDocPtr. tree= xmlDocGetRootElement(docRaw) :: xmlNodePtr. childrenRaw = tree["children"]:: [xmlNodePtr]; linkedlist(next, null). size = loop fold(childrenRaw->child:: xmlNodePtr, 0->count):: int { count +1::int }. size } diff --git a/scripts/virtualization/test1.assembly.lp b/scripts/virtualization/test1.assembly.lp index 3762dae..91f2ae1 100644 --- a/scripts/virtualization/test1.assembly.lp +++ b/scripts/virtualization/test1.assembly.lp @@ -1,2 +1,35 @@ -virtDomain(domainA). -virtDomain(domainB). +% INPUT +%----------------------------------- +% sizo(..). + +sizo(Sizo):- + bind_scope(_, attachedSizo(Sizo), strong). + +dict_sizo(Sizo, Id):- + Id= #sum{ 1, SizoLess : sizo(SizoLess), SizoLess < Sizo}; + sizo(Sizo). + +% connect to latex +%----------------------------------- +latex_registered_subjects(sizo, Sizo):- sizo(Sizo). + +latex_scope_demand(ScopeDemandSizo, sizo):- + bind(Target, demand(sizo)); + Target = s(_, _, ScopeDemandSizo). + +bind_scope(Scope, Sizo, strong):- + bind_scope(Scope, attachedSizo(Sizo), strong). + +% register late query +%----------------------------------- +late(Target, SymbolSizo, (SizoAny), sizo_current(SizoAny)):- + bind(Target, demand(sizo)); + Target=s(_, _, TargetS); + scope_fn(TargetS, Fn); + cfa_parent(FnBody, function(Fn)); + latex_symbol(Fn, sizo, SymbolSizo); + sizo(SizoAny). + + +% IMPLEMENTATION +%=========================================================== . diff --git a/scripts/virtualization/test1.h b/scripts/virtualization/test1.h new file mode 100644 index 0000000..9c5417d --- /dev/null +++ b/scripts/virtualization/test1.h @@ -0,0 +1,4 @@ +#include +#include + +typedef FILE* FILEP; diff --git a/scripts/virtualization/test1.xreate b/scripts/virtualization/test1.xreate index 35c05b1..c2cbe11 100644 --- a/scripts/virtualization/test1.xreate +++ b/scripts/virtualization/test1.xreate @@ -1,72 +1,47 @@ interface(extern-c){ externalLibs = library:: pkgconfig("libxml-2.0"). include { - externalLibs = ["stdio.h"] + externalLibs = ["scripts/virtualization/test1.h"] }. } import raw ("scripts/virtualization/test1.assembly.lp"). -import raw ("scripts/virtualization/virtualization.lp"). +import raw ("scripts/cfa/context.lp"). -Annotation = type variant { - Num:: int, - String:: string, - Func:: {name::string, arguments::[Annotation]} -}. +DictSizo = type slave dict_sizo. +Sizo = type slave sizo. -DictEntry = type {Annotation, Id}. - -extractDictEntry = function(entry:: Annotation):: DictEntry; interpretation(force){ - resultWrong = { String("wrong"), 0 }:: DictEntry. - - switch variant (entry):: DictEntry - case (Num) { resultWrong } - case (String) { resultWrong } - case (Func){ - domAnn = entry["arguments"][0]:: Annotation. - - switch variant ( entry["arguments"][1]->id ):: Annotation - case (Num) { {domAnn, id} } - case (String) { resultWrong } - case (Func) { resultWrong } - } -} +virt_getPrefix = function:: string +{ + dictSizo = intrinsic query("dict_sizo")::[DictSizo]. -encodeDomain = function(key::Annotation):: int; interpretation(force){ - dict = intrinsic query("virtDictDomains")::[Annotation]. - - id = loop fold(dict->entryAnn::Annotation, 0->id):: int { - entry = extractDictEntry(entryAnn):: DictEntry. - - if(entry[0] == key):: int { entry[1] } else { id } + sizoId = intrinsic query late("sizo_current"->sizoCurrent:: Sizo):: int; demand(sizo) + { + loop fold(dictSizo->entry::DictSizo, 0->id):: int { + if(entry[0] == sizoCurrent):: int { entry[1] } else { id } + } }. - id - - /* buf = "000000000"::string. seq - { sprintf(buf, "%d", id).} - { buf} - */ + { sprintf(buf, "%d", sizoId) } + { buf } } - -main = function:: int; entry { - encodeDomain(Func({"domainB", []})) -} - -/* -openfile = function(fileName::string, prefixPackedAnn:: Annotation) { - prefixStr = encodeDomain(prefixPackedAnn):: string. - - fopen(prefixStr + fileName) +openFile = function(filename::string):: int +{ + buf = "0000000000":: string. + prefix = virt_getPrefix():: string. + seq + {sprintf(buf, "/%s/%s", prefix, filename)} + {printf("file opened: %s ", buf)} } -main = function:: entry ( +main = function:: int; entry +{ seq - { context::virtualization(domainA). openFile("test1", intrinsic query("openFileAdditionalArgsDomA")[0]) } - { context::virtualization(domainB). openFile("test1", intrinsic query("openFileAdditionalArgsDomB")[0]) } -) -*/ + { context::attachedSizo(domainA). openFile("test1") } + { context::attachedSizo(domainB). openFile("test1") } + { 0 } +} diff --git a/scripts/virtualization/test2.assembly.lp b/scripts/virtualization/test2.assembly.lp new file mode 100644 index 0000000..8ce61dc --- /dev/null +++ b/scripts/virtualization/test2.assembly.lp @@ -0,0 +1,45 @@ +% INPUT +%----------------------------------- +% assign_sizo(..). + +sizo(Sizo):- + bind_scope(_, assign_sizo(Sizo), strong). + +dict_sizo(Sizo, Id):- + Id= #sum{ 1, SizoLess : sizo(SizoLess), SizoLess < Sizo}; + sizo(Sizo). + +% connect to latex +%----------------------------------- +latex_registered_subjects(sizo, Sizo):- sizo(Sizo). + +latex_scope_demand(ScopeDemandSizo, sizo):- + bind(Target, demand(sizo)); + Target = s(_, _, ScopeDemandSizo). + +bind_scope(Scope, Sizo, strong):- + bind_scope(Scope, assign_sizo(Sizo), strong). + +% register late query +%----------------------------------- +late(Target, SymbolSizo, (SizoAny), sizo_current(SizoAny)):- + bind(Target, demand(sizo)); + Target=s(_, _, TargetS); + scope_fn(TargetS, Fn); + latex_symbol(Fn, sizo, SymbolSizo); + sizo(SizoAny). + +% polymorphism based on virtualizaion strategy +%----------------------------------- +dfa_callguard(SymbRet, strategy(Strategy)):- + dfa_callfn(SymbRet, FnName); + bind_func(FnName, requires(virt_dereference_strategy)); + virt_dereference_strategy(Strategy). + + +% IMPLEMENTATION +%=========================================================== . +virt_dereference_strategy(prefix) :- 2 #count{Sizo: sizo(Sizo)}. +virt_dereference_strategy(none) :- not virt_dereference_strategy(prefix). + + diff --git a/scripts/virtualization/test2.xreate b/scripts/virtualization/test2.xreate index 83d68ef..47856be 100644 --- a/scripts/virtualization/test2.xreate +++ b/scripts/virtualization/test2.xreate @@ -1,39 +1,57 @@ - -// Different sizos get different prefixes +interface(extern-c){ + externalLibs = library:: pkgconfig("libxml-2.0"). -SIZO = type slave sizo. - -findSizoId = function(key::Annotation):: int; interpretation(force){ - dict = intrinsic query("dictSizos")::[Annotation]. - - id = loop fold(dict->entryAnn::Annotation, 0->id):: int { - entry = extractDictEntry(entryAnn):: DictEntry. - - if(entry[0] == key):: int { entry[1] } else { id } + include { + externalLibs = ["scripts/virtualization/test1.h"] }. - - id } -findSizoPrefx = function(sizo:: SIZO):: string +import raw ("scripts/virtualization/test2.assembly.lp"). +import raw ("scripts/cfa/context.lp"). + +DictSizo = type slave dict_sizo. +Sizo = type slave sizo. + +guard:: strategy(prefix) { - id = findSizoId(sizo). - - buf = "0000"::string. - seq - { sprintf(buf, "%d", id).} - { buf } + virt_dereferenceFilename = function(filename:: string):: string; requires(virt_dereference_strategy) + { + dictSizo = intrinsic query("dict_sizo")::[DictSizo]. + + sizoId = intrinsic query late("sizo_current"->sizoCurrent:: Sizo):: int; demand(sizo) + { + loop fold(dictSizo->entry::DictSizo, 0->id):: int + { + if(entry[0] == sizoCurrent):: int { entry[1] } else { id } + } + }. + + buf = "000000000"::string. + seq + { sprintf(buf, "%d/%s", sizoId, filename) } + { buf } + } } -openfile = function +guard:: strategy(none) { - domCurrent = query context:: SIZO. - prefix = findSizoPrefx(domCurrent):: string. - - fopen(prefixStr + fileName) + virt_dereferenceFilename = function(filename:: string):: string; requires(virt_dereference_strategy) + { + filename + } } -writefile = function +virt_openFile = function(filename:: string):: int { + filenameReal = virt_dereferenceFilename(filename):: string. + seq{printf("file opened: %s ", filenameReal)} +} +main = function:: int; entry +{ + seq + { context::assign_sizo(domainA). virt_openFile("test1") } + { context::assign_sizo(domainA). virt_openFile("test1") } + { 0 } } + diff --git a/scripts/virtualization/test3.assembly.lp b/scripts/virtualization/test3.assembly.lp new file mode 100644 index 0000000..cb7af52 --- /dev/null +++ b/scripts/virtualization/test3.assembly.lp @@ -0,0 +1,63 @@ +% INPUT +%----------------------------------- +% assign_sizo(..). + +sizo(Sizo):- + bind_scope(_, assign_sizo(Sizo), strong). + +dict_sizo(Sizo, Id):- + Id= #sum{ 1, SizoLess : sizo(SizoLess), SizoLess < Sizo}; + sizo(Sizo). + +% connect to latex +%----------------------------------- +latex_registered_subjects(sizo, Sizo):- sizo(Sizo). + +latex_scope_demand(ScopeDemandSizo, sizo):- + bind(Target, demand(sizo)); + Target = s(_, _, ScopeDemandSizo). + +bind_scope(Scope, Sizo, strong):- + bind_scope(Scope, assign_sizo(Sizo), strong). + +% register late query +%----------------------------------- +late(Target, SymbolSizo, (SizoAny), sizo_current(SizoAny)):- + bind(Target, demand(sizo)); + Target=s(_, _, TargetS); + scope_fn(TargetS, Fn); + latex_symbol(Fn, sizo, SymbolSizo); + sizo(SizoAny). + +% polymorphism based on virtualizaion strategy +%----------------------------------- +late(SymbRet, SymbolSizo, Sizo, dfa_callguard(SymbRet, strategy(Strategy))):- + dfa_callfn(SymbRet, FnName); + bind_func(FnName, requires(virt_dereference_strategy)); + SymbRet=s(_, _, ScopeCaller); + scope_fn(ScopeCaller, Fn); + latex_symbol(Fn, sizo, SymbolSizo); + sizo(Sizo); + virt_dereference_strategy(Sizo, Strategy). + + +% IMPLEMENTATION +%=========================================================== . + +sizo_properties(Sizo, Prop):- + bind_scope(Scope, define_sizo_prop(Prop), strong); + bind_scope(Scope, Sizo, strong); + sizo(Sizo). + +virt_dereference_strategy(SizoOther, prefix):- + sizo_properties(Sizo, inner); + SizoOther <> Sizo; + sizo(SizoOther). + +virt_dereference_strategy(Sizo, prefix):- + sizo_properties(Sizo, outer). + +virt_dereference_strategy(Sizo, none) :- + not virt_dereference_strategy(Sizo, prefix); + sizo(Sizo). + diff --git a/scripts/virtualization/test3.xreate b/scripts/virtualization/test3.xreate new file mode 100644 index 0000000..37d93f6 --- /dev/null +++ b/scripts/virtualization/test3.xreate @@ -0,0 +1,57 @@ +interface(extern-c){ + externalLibs = library:: pkgconfig("libxml-2.0"). + + include { + externalLibs = ["scripts/virtualization/test1.h"] + }. +} + +import raw ("scripts/virtualization/test3.assembly.lp"). +import raw ("scripts/cfa/context.lp"). + +DictSizo = type slave dict_sizo. +Sizo = type slave sizo. + +guard:: strategy(prefix) +{ + virt_dereferenceFilename = function(filename:: string):: string; requires(virt_dereference_strategy) + { + dictSizo = intrinsic query("dict_sizo")::[DictSizo]. + + sizoId = intrinsic query late("sizo_current"->sizoCurrent:: Sizo):: int; demand(sizo) + { + loop fold(dictSizo->entry::DictSizo, 0->id):: int + { + if(entry[0] == sizoCurrent):: int { entry[1] } else { id } + } + }. + + buf = "000000000"::string. + seq + { sprintf(buf, "%d/%s", sizoId, filename) } + { buf } + } +} + +guard:: strategy(none) +{ + virt_dereferenceFilename = function(filename:: string):: string; requires(virt_dereference_strategy) + { + filename + } +} + +virt_openFile = function(filename:: string):: int +{ + filenameReal = virt_dereferenceFilename(filename):: string. + printf("file opened: %s ", filenameReal) +} + +main = function:: int; entry +{ + seq + { context::assign_sizo(domainA); define_sizo_prop(inner). virt_openFile("test1") } + { context::assign_sizo(domainB); define_sizo_prop(outer). virt_openFile("test1") } + { 0 } +} + diff --git a/scripts/virtualization/virtualization.lp b/scripts/virtualization/virtualization.lp deleted file mode 100644 index 9aa3f5a..0000000 --- a/scripts/virtualization/virtualization.lp +++ /dev/null @@ -1,6 +0,0 @@ -% INPUT: -% virtDomain() - different virtualization domains - -virtDictDomains(Dom, Id):- Id = #sum{1, DomLess : virtDomain(DomLess), DomLess < Dom}; - virtDomain(Dom). -