diff --git a/config/default.json b/config/default.json index 09f405f..6cc02b4 100644 --- a/config/default.json +++ b/config/default.json @@ -1,73 +1,74 @@ { "containers": { "id": { "implementations": "containers_impl", "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": "troubleshooting", + "template": "documentation", "templates": { - "troubleshooting":"*", + "troubleshooting":"Loop.Doc_LoopLoopMap", + "documentation":"Modules.Doc_*:Interpretation.Doc_*:AST.Doc_*:Loop.Doc_*", "default": "*", "ast": "AST.*", "effects": "Effects.*", "basic": "Attachments.*", "compilation": "Compilation.*", "communication": "Communication.*", "cfa": "CFA.*", "containers": "Containers.*", "dfa": "DFA.*", "diagnostic": "Diagnostic.*", "dsl": "Association.*:Interpretation.*", "exploitation": "Exploitation.*", "ExpressionSerializer": "ExpressionSerializer.*", "externc": "InterfaceExternC.*", "loops": "Loop.*", "latereasoning": "LateReasoning.*", "latex": "Latex.*", "modules": "Modules.*", "polymorphs": "Polymorphs.*", "intrinsic-query": "Types.SlaveTypes*:Association.TypedQuery*", "types": "Types.*", "virtualization": "Virtualization.*", "vendorsAPI/clang": "ClangAPI.*", "vendorsAPI/xml2": "libxml2*" } } } diff --git a/cpp/src/CMakeLists.txt b/cpp/src/CMakeLists.txt index f9092a6..93ad47b 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 + modules.cpp analysis/DominatorsAnalysisProvider.cpp 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 analysis/typeinference.cpp xreatemanager.cpp transcendlayer.cpp analysis/dfagraph.cpp llvmlayer.cpp pass/compilepass.cpp analysis/utils.cpp pass/dfapass.cpp compilation/targetinterpretation.cpp pass/interpretationpass.cpp ast.cpp aux/xreatemanager-decorators.cpp compilation/operators.cpp compilation/transformations.cpp compilation/transformersaturation.cpp pass/versionspass.cpp attachments.cpp compilation/containers.cpp compilation/advancedinstructions.cpp utils.cpp pass/abstractpass.cpp 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 5c39308..81991bb 100644 --- a/cpp/src/ExternLayer.cpp +++ b/cpp/src/ExternLayer.cpp @@ -1,315 +1,337 @@ /* 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/CodeGen/ModuleBuilder.h" #include "clang/CodeGen/CodeGenABITypes.h" #include #include #include #include #include #include using namespace std; using namespace clang; using namespace clang::driver; using namespace clang::tooling; using namespace clang::ast_matchers; using namespace llvm; namespace xreate{ class FinderCallbackTypeDecl : public MatchFinder::MatchCallback{ public: QualType typeResult; virtual void run(const MatchFinder::MatchResult &Result) { if (const TypedefDecl * decl = Result.Nodes.getNodeAs("typename")) { typeResult = decl->getUnderlyingType(); } } } ; class FinderCallbackFunction : public MatchFinder::MatchCallback{ public: QualType typeResult; virtual void run(const MatchFinder::MatchResult &Result) { if (const FunctionDecl * decl = Result.Nodes.getNodeAs("function")) { typeResult = decl->getType(); } } } ; void ExternData::addLibrary(Atom&& name, Atom&& package) { __dictLibraries.emplace(name.get(), package.get()); } void ExternData::addIncludeDecl(Expression&& e) { - assert(e.op == Operator::LIST_NAMED); + assert(e.op == Operator::LIST); //TODO ?? implement Expression parsing(Array of Expr as vector); for(size_t i = 0, size = e.operands.size(); i < size; ++i) { std::string library = e.bindings.at(i); assert(__dictLibraries.count(library)); std::string package = __dictLibraries.at(library); Expression listHeaders = e.operands.at(i); assert(listHeaders.op == Operator::LIST); std::vector headers; std::transform(listHeaders.operands.begin(), listHeaders.operands.end(), std::inserter(headers, headers.end()), [](const Expression & o) { assert(o.__state == Expression::STRING); return o.getValueString(); }); entries.emplace_back(ExternEntry{package, std::move(headers)}); } } void ExternLayer::addExternalData(const std::vector& data) { entries.insert(entries.end(), data.begin(), data.end()); } ExternLayer::ExternLayer(LLVMLayer *llvm) : __llvm(llvm) { } std::vector ExternLayer::fetchPackageFlags(const ExternEntry& entry) { std::vector args; FILE* flags = popen((string("pkg-config --cflags ") + entry.package).c_str(), "r"); size_t linesize = 0; char* linebuf = 0; ssize_t linelen = 0; while ((linelen = getdelim(&linebuf, &linesize, ' ', flags)) > 0) { if (linebuf[0] == '\n') continue; if (linelen == 1 && linebuf[0] == ' ') continue; //cut unwanted symbols at the end char symbLast = linebuf[linelen - 1 ]; if (symbLast == ' ' || symbLast == '\n') linebuf[linelen - 1] = 0; //print header for debug purposes llvm::outs() << '<' << linebuf << "> "; args.push_back(linebuf); free(linebuf); linebuf = 0; } pclose(flags); return (args); } std::vector ExternLayer::fetchPackageLibs(const ExternEntry& entry) { std::vector libs; FILE* flags = popen((string("pkg-config --libs ") + entry.package).c_str(), "r"); size_t linesize = 0; char* linebuf = 0; ssize_t linelen = 0; while ((linelen = getdelim(&linebuf, &linesize, ' ', flags)) > 0) { if (linebuf[0] == '\n') continue; if (linelen == 1 && linebuf[0] == ' ') continue; //cut unwanted symbols at the end char symbLast = linebuf[linelen - 1 ]; if (symbLast == ' ' || symbLast == '\n') linebuf[linelen - 1] = 0; //cut unwanted symbols at the beginning if (linelen > 1 && linebuf[0] == '-' && linebuf[1] == 'l') { libs.push_back(linebuf + 2); } else { libs.push_back(linebuf); } //print lib name for debug purposes llvm::outs() << '<' << linebuf << "> "; free(linebuf); linebuf = 0; } pclose(flags); return (libs); } void ExternLayer::loadLibraries(vector&& libs) { string msgErr; for (const string& lib : libs) { const string& libName = string("lib") + lib + ".so"; if (!llvm::sys::DynamicLibrary::LoadLibraryPermanently(libName.c_str(), &msgErr)) { llvm::errs() << "\n" << "Loading library " << lib << ". " << msgErr << "\n"; } } } void ExternLayer::init(const AST* root) { addExternalData(root->__externdata); // TODO -EXTERN01.DIP, use default include path from 'clang -xc++ -E' list code; std::vector args{ "-I/usr/include" , "-I/usr/local/include" , "-I/usr/lib64/clang/5.0.1/include" // ,"-I/usr/lib/gcc/x86_64-linux-gnu/4.9/include" // ,"-I/usr/include/x86_64-linux-gnu" }; std::vector libs; boost::format formatInclude("#include \"%1%\""); for(const ExternEntry& entry : entries) { llvm::outs() << "[ExternC] Processing package: " << entry.package << "\n"; llvm::outs() << "[ExternC] args: "; vector&& args2 = fetchPackageFlags(entry); args.insert(args.end(), args2.begin(), args2.end()); for(const string arg : args2) { llvm::outs() << "<" << arg << "> "; } llvm::outs() << "\n[ExternC] libs: "; args2 = fetchPackageLibs(entry); for(const string arg : args2) { llvm::outs() << "<" << arg << "> "; } libs.insert(libs.end(), args2.begin(), args2.end()); llvm::outs() << "\n[ExternC] headers: "; std::transform(entry.headers.begin(), entry.headers.end(), std::inserter(code, code.begin()), [&formatInclude](const string header ) { string line = boost::str(formatInclude % header); llvm::outs() << "<" << line << "> "; return line; }); llvm::outs() << '\n'; } loadLibraries(move(libs)); ast = buildASTFromCodeWithArgs(boost::algorithm::join(code, "\n"), args); __llvm->module->setDataLayout(ast->getASTContext().getTargetInfo().getDataLayout()); __clang.reset(new CompilerInstance()); __clang->createDiagnostics(); __codegen.reset(CreateLLVMCodeGen( __clang->getDiagnostics(), __llvm->module->getName(), __clang->getHeaderSearchOpts(), __clang->getPreprocessorOpts(), clang::CodeGenOptions(), __llvm->llvmContext )); __codegen->Initialize(ast->getASTContext()); }; bool ExternLayer::isPointer(const clang::QualType &t) { const clang::Type * tInfo = t.getTypePtr(); assert(tInfo); return tInfo->isAnyPointerType(); } llvm::Type* ExternLayer::toLLVMType(const clang::QualType& t) { return CodeGen::convertTypeForMemory( __codegen->CGM(), t); } std::vector ExternLayer::getStructFields(const clang::QualType& ty) { clang::QualType t = ty; if (isPointer(ty)) { const clang::PointerType* tPtr = ty->getAs(); t = tPtr->getPointeeType(); } assert(t.getTypePtr()->isRecordType()); const RecordType *record = t->getAsStructureType(); assert(record); std::vector result; //FieldDecl* field: record->getDecl()->fields() for (auto i = record->getDecl()->field_begin(); i != record->getDecl()->field_end(); ++i) { result.push_back(i->getName()); } return result; } +bool +ExternLayer::isArrayType(const std::string& type){ + clang::QualType typeRaw = lookupType(type); + if (isPointer(typeRaw)) { + const clang::PointerType* typePtr = typeRaw->getAs(); + typeRaw = typePtr->getPointeeType(); + } + + return typeRaw->isArrayType(); +} + +bool +ExternLayer::isRecordType(const std::string& type){ + clang::QualType typeRaw = lookupType(type); + if (isPointer(typeRaw)) { + const clang::PointerType* typePtr = typeRaw->getAs(); + typeRaw = typePtr->getPointeeType(); + } + + return typeRaw->isRecordType(); +} + clang::QualType ExternLayer::lookupType(const std::string& id) { MatchFinder finder; FinderCallbackTypeDecl callbackTypeDecl; auto matcherTypeDecl = typedefDecl(hasName(id)).bind("typename"); finder.addMatcher(matcherTypeDecl, &callbackTypeDecl); finder.matchAST(ast->getASTContext()); assert(! callbackTypeDecl.typeResult.isNull()); return callbackTypeDecl.typeResult; } llvm::Function* ExternLayer::lookupFunction(const std::string& name) { if (__functions.count(name)) { return __functions.at(name); } MatchFinder finder; FinderCallbackFunction callback; auto matcher = functionDecl(hasName(name)).bind("function"); finder.addMatcher(matcher, &callback); finder.matchAST(ast->getASTContext()); if (callback.typeResult.isNull()) { cout << "[External Layer] " << "Unknown function: " << name << endl; assert(false && "Unknown external function"); } const QualType& tyFuncQual = callback.typeResult; llvm::Type *tyRaw = CodeGen::convertTypeForMemory(__codegen->CGM(), tyFuncQual); llvm::FunctionType* tyRawFunc = llvm::dyn_cast(tyRaw); llvm::Function* function = llvm::Function::Create( tyRawFunc, llvm::GlobalValue::ExternalLinkage, name, __llvm->module.get()); __functions.emplace(name, function); return function; } }//end of xreate namespace diff --git a/cpp/src/ExternLayer.h b/cpp/src/ExternLayer.h index 49fe4b3..d0f0c33 100644 --- a/cpp/src/ExternLayer.h +++ b/cpp/src/ExternLayer.h @@ -1,65 +1,67 @@ /* 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 xreate{ struct ExternData{ void addLibrary(Atom&& name, Atom&& package); void addIncludeDecl(Expression&& e); std::vector entries; std::map __dictLibraries; }; class ExternLayer{ public: ExternLayer(LLVMLayer* llvm); void init(const AST* root); llvm::Function* lookupFunction(const std::string& name); clang::QualType lookupType(const std::string& id); std::vector getStructFields(const clang::QualType& ty); llvm::Type* toLLVMType(const clang::QualType& t); bool isPointer(const clang::QualType& t); + bool isArrayType(const std::string& type); + bool isRecordType(const std::string& type); static std::vector fetchPackageFlags(const ExternEntry& entry); static std::vector fetchPackageLibs(const ExternEntry& entry); private: std::unique_ptr ast; std::unique_ptr __codegen; std::unique_ptr __clang; LLVMLayer* __llvm; std::vector entries; std::map __functions; void addExternalData(const std::vector& data); void loadLibraries(std::vector&& libs); }; } #endif //XREATE_EXTERNLAYER_H diff --git a/cpp/src/analysis/interpretation.cpp b/cpp/src/analysis/interpretation.cpp index f46027d..b841a8e 100644 --- a/cpp/src/analysis/interpretation.cpp +++ b/cpp/src/analysis/interpretation.cpp @@ -1,274 +1,274 @@ /* * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ /* * Author: pgess * Created on June 25, 2018, 3:25 PM * * \file interpretation.cpp * \brief interpretation */ #include "analysis/interpretation.h" using namespace std; namespace xreate{ namespace interpretation{ typedef vector InstancePacked; std::list generateAllInstancesInDomain2(const ExpandedType& domainT) { if(!domainT->isValid()) { return {Expression()}; } assert(domainT->__operator == TypeOperator::VARIANT); std::list results; int variantId = -1; bool flagDomainStateless = std::all_of(domainT->__operands.begin(), domainT->__operands.end(), [](const TypeAnnotation & subdomainT) { return !subdomainT.isValid(); }); for(const TypeAnnotation& subdomainT : domainT->__operands) { ++variantId; if(flagDomainStateless) { Expression result(Operator::VARIANT,{}); result.setValueDouble(variantId); results.push_back(result); continue; } std::list subresults = generateAllInstancesInDomain2(ExpandedType(subdomainT)); for (const Expression& subresult : subresults) { Expression result(Operator::VARIANT,{}); result.setValueDouble(variantId); result.operands.push_back(subresult); results.push_back(result); } } return results; } TypeAnnotation collapseFnGroup(const std::list& symbols) { Gringo::Symbol symbolAny = symbols.front(); size_t operandsCount = symbolAny.args().size; TypeAnnotation resultT; resultT.__operands.reserve(operandsCount); for(size_t operandId = 0; operandId < operandsCount; ++operandId) { std::list column; for(const Gringo::Symbol& row : symbols) { column.push_back(row.args()[operandId]); } TypeAnnotation operandT = collapseColumn(column); resultT.__operands.push_back(operandT); } if(resultT.__operands.size() == 1) { return resultT.__operands.front(); } if(resultT.__operands.size() > 1) { - resultT.__operator = TypeOperator::LIST_NAMED; + resultT.__operator = TypeOperator::LIST_RECORD; return resultT; } return resultT; } TypeAnnotation collapseColumn(const std::list& symbols) { TypeAnnotation resultT; if(!symbols.size()) return resultT; Gringo::Symbol symbolAny = symbols.front(); switch(symbolAny.type()) { case Gringo::SymbolType::Num: { return TypeAnnotation(TypePrimitive::Num); } case Gringo::SymbolType::Str: { return TypeAnnotation(TypePrimitive::String); } case Gringo::SymbolType::Fun: { map> fnGroups; for(const Gringo::Symbol& row : symbols) { fnGroups[row.name().c_str()].push_back(row); } TypeAnnotation resultT; resultT.__operands.reserve(fnGroups.size()); resultT.bindings.reserve(fnGroups.size()); for(const auto& group : fnGroups) { if(!group.second.size()) continue; TypeAnnotation variantT = collapseFnGroup(group.second); Gringo::Symbol symbolAny = group.second.front(); string variantName = symbolAny.name().c_str(); resultT.fields.push_back(variantName); resultT.__operands.push_back(variantT); } resultT.__operator = TypeOperator::VARIANT; // if(resultT.__operands.size() == 1) { // return resultT.__operands.front(); // } return resultT; } case Gringo::SymbolType::Inf: case Gringo::SymbolType::Special: case Gringo::SymbolType::Sup: { break; } } assert(false); return TypeAnnotation(); } ExpandedType dereferenceSlaveType(ExpandedType t, const TranscendLayer* transcend) { assert(t->__operator == TypeOperator::SLAVE); const string& domain = t->__valueCustom; StaticModel model = transcend->query(domain); if(!model.size()) return ExpandedType(TypeAnnotation()); std::list symbols; for(auto row : model) { symbols.push_back(row.second); } return ExpandedType(collapseFnGroup(symbols)); } Expression representTransExpression(const Gringo::Symbol& atom, ExpandedType schemaT, TranscendLayer* transcend) { atom.print(std::cout); std::cout<__operator) { case TypeOperator::NONE: { switch(schemaT->__value) { case TypePrimitive::I8: case TypePrimitive::I32: case TypePrimitive::I64: case TypePrimitive::Num: case TypePrimitive::Int: { return Expression(Atom(atom.num())); } case TypePrimitive::String: { return Expression(Atom(atom.string().c_str())); } case TypePrimitive::Invalid: case TypePrimitive::Bool: case TypePrimitive::Float: { assert(false); return Expression(); } } break; } case TypeOperator::SLAVE: { ExpandedType contentT = dereferenceSlaveType(schemaT, transcend); return representTransExpression(atom, contentT, transcend); } case TypeOperator::VARIANT: { map dictVariants; for(size_t variantId = 0; variantId < schemaT->fields.size(); ++variantId) { dictVariants.emplace(schemaT->fields.at(variantId), variantId); } string predicateName = atom.name().c_str(); assert(dictVariants.count(predicateName)); size_t predicateId = dictVariants.at(predicateName); Expression result(Operator::VARIANT,{}); result.op = Operator::VARIANT; result.setValueDouble(predicateId); if(!schemaT->__operands.size()) return result; ExpandedType contentT = schemaT->__operands.at(predicateId).__operator == TypeOperator::SLAVE ? dereferenceSlaveType(ExpandedType(schemaT->__operands.at(predicateId)), transcend) : ExpandedType(schemaT->__operands.at(predicateId)); //edge case, content's type is LIST_NAMED: - if (contentT->__operator == TypeOperator::LIST_NAMED) { + if (contentT->__operator == TypeOperator::LIST_RECORD) { result.operands.push_back(representTransExpression(atom, contentT, transcend)); } else if(!contentT->isValid()) { return result; } else { assert(atom.args().size); result.operands.push_back(representTransExpression(atom.args()[0], contentT, transcend)); } return result; } - case TypeOperator::LIST_NAMED: + case TypeOperator::LIST_RECORD: { const Gringo::SymSpan& operandsRaw = atom.args(); size_t opCount = operandsRaw.size; assert(opCount == schemaT->__operands.size()); size_t operandId = 0; std::vector operands; operands.reserve(opCount); for(const TypeAnnotation operandT : schemaT->__operands) { operands.push_back(representTransExpression(operandsRaw[operandId], ExpandedType(operandT), transcend)); ++operandId; } - Expression result(Operator::LIST_NAMED,{}); + Expression result(Operator::LIST,{}); result.operands = operands; result.type = schemaT; return result; } - case TypeOperator::LIST: + case TypeOperator::LIST_ARRAY: case TypeOperator::CALL: case TypeOperator::CUSTOM: case TypeOperator::ACCESS: case TypeOperator::LINK: { assert(false); return Expression(); } } assert(false); return Expression(); } } } //end of xreate namespace diff --git a/cpp/src/ast.cpp b/cpp/src/ast.cpp index 73dfef3..8b1cf6a 100644 --- a/cpp/src/ast.cpp +++ b/cpp/src/ast.cpp @@ -1,977 +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: + case TypeOperator::LIST_ARRAY: { assert(t.__operands.size() == 1); Expanded elTy = expandType(t.__operands.at(0)); return ExpandedType(TypeAnnotation(tag_array, elTy, 0)); } - case TypeOperator::LIST_NAMED: + case TypeOperator::LIST_RECORD: { std::vector&& packOperands = expandOperands(t.__operands); - auto typNew = TypeAnnotation(TypeOperator::LIST_NAMED, move(packOperands)); + auto typNew = TypeAnnotation(TypeOperator::LIST_RECORD, 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); + assert(tyAlias->__operator == TypeOperator::LIST_RECORD); 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}) { +: TypeAnnotation(TypeOperator::LIST_ARRAY,{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, const VNameId hintBindingId) { __entry->addBinding(move(name), move(argument), hintBindingId); } const std::string& Function::getName() const { return __name; } ScopedSymbol CodeScope::registerIdentifier(const Expression& identifier, const VNameId hintBindingId) { versions::VariableVersion version = Attachments::get(identifier, versions::VERSION_NONE); 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, const VNameId hintBindingId) { argument.__state = Expression::BINDING; __bindings.push_back(var.getValueString()); 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 768092f..59bdb5b 100644 --- a/cpp/src/ast.h +++ b/cpp/src/ast.h @@ -1,740 +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 + NONE, CALL, CUSTOM, VARIANT, LIST_ARRAY, LIST_RECORD, 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, + LIST_RANGE, CALL, CALL_INTRINSIC, QUERY, QUERY_LATE, IMPL/* implication */, MAP, - FOLD, FOLD_INF, INDEX, + 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, 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: 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, 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/aux/xreatemanager-modules.h b/cpp/src/aux/xreatemanager-modules.h index 5629527..003d780 100644 --- a/cpp/src/aux/xreatemanager-modules.h +++ b/cpp/src/aux/xreatemanager-modules.h @@ -1,126 +1,124 @@ /* 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: PassManagerModular.h * Author: pgess * * Created on June 22, 2017, 5:32 PM */ /** * \file xreatemanager-modules.h * \brief XreateManager's decorator to support [Modules](/w/concepts/modules/). */ #ifndef PASSMANAGERMODULAR_H #define PASSMANAGERMODULAR_H #include "ast.h" #include "modules.h" #include "modules/Parser.h" #include "main/Parser.h" namespace xreate{namespace modules { template /** \brief PassManager decorator to add [Modules Concept](/w/concepts/modules/) support * * Scanning of source file looking for other modules requirements. * Finds and connects other modules to satisfy module's requirements * * \sa ModulesSolver, ModulesRegistry, ModuleRecord */ class XreateManagerDecoratorModules: public Parent{ public: - XreateManagerDecoratorModules(): __registry(new ModulesRegistry()){} + XreateManagerDecoratorModules(){} void prepareCode(std::string&& code) override { Scanner scannerModules(reinterpret_cast(code.c_str()), code.size()); std::list listIncludedFiles; parseModulesGrammar(scannerModules, listIncludedFiles); grammar::main::Scanner scannerMain(reinterpret_cast(code.c_str()), code.size()); parseMainGrammar(scannerMain, listIncludedFiles); } void prepareCode(FILE* code) override { Scanner scannerModules(code); std::list listIncludedFiles; parseModulesGrammar(scannerModules, listIncludedFiles); grammar::main::Scanner scannerMain(code); parseMainGrammar(scannerMain, listIncludedFiles); } private: - ModulesRegistry* __registry; - void parseModulesGrammar(Scanner& scanner, std::list& listIncludedFiles){ - ModulesSolver solver(__registry); + ModulesSolver solver; Parser parser(&scanner); parser.Parse(); parser.module.__path = ""; solver.init("", parser.module); std::list modulesExternal = solver.run(parser.module); std::string programBase = solver.__program.str(); for (const std::string module: modulesExternal){ parseModulesGrammar(module, programBase, listIncludedFiles); } } void parseModulesGrammar(const std::string& path, std::string base, std::list& listIncludedFiles){ FILE* input = fopen(path.c_str(), "r"); assert(input != nullptr); Scanner scanner(input); Parser parser(&scanner); parser.Parse(); parser.module.__path = path; fclose(input); - ModulesSolver solver(__registry); + ModulesSolver solver; solver.init(base, parser.module); std::list&& modulesExternal = solver.run(parser.module); std::string programBase = solver.__program.str(); for (const std::string module: modulesExternal){ parseModulesGrammar(module, programBase, listIncludedFiles); } listIncludedFiles.push_back(path); } void parseMainGrammar(grammar::main::Scanner& scanner, std::list& listIncludedFiles){ details::inconsistent::AST* ast = new AST; grammar::main::Parser parser(&scanner); parser.root = ast; parser.Parse(); assert(!parser.errors->count && "Parser errors"); for (auto file: listIncludedFiles){ FILE* fileContent = fopen(file.c_str(), "r"); grammar::main::Scanner scanner(fileContent); grammar::main::Parser parser(&scanner); parser.root = ast; parser.Parse(); fclose(fileContent); assert(!parser.errors->count && "Parser errors"); } PassManager::prepare(ast->finalize()); } }; }} //end namespace xreate::modules #endif /* PASSMANAGERMODULAR_H */ diff --git a/cpp/src/compilation/advancedinstructions.cpp b/cpp/src/compilation/advancedinstructions.cpp index 1409e5e..787126c 100644 --- a/cpp/src/compilation/advancedinstructions.cpp +++ b/cpp/src/compilation/advancedinstructions.cpp @@ -1,470 +1,470 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * File: InstructionsAdvanced.cpp * Author: pgess * * Created on June 26, 2016, 6:00 PM */ /** * \file advanced.h * \brief Compilation of statements that require more than one LLVM instruction */ #include "analysis/typeinference.h" #include "compilation/advancedinstructions.h" #include "compilation/containers.h" #include "compilation/transformersaturation.h" #include "query/containers.h" #include "llvmlayer.h" #include "ast.h" using namespace std; using namespace llvm; using namespace xreate; using namespace xreate::containers; using namespace xreate::compilation; #define NAME(x) (hintRetVar.empty()? x : hintRetVar) #define UNUSED(x) (void)(x) #define EXPAND_CONTEXT \ LLVMLayer* llvm = context.pass->man->llvm; \ compilation::ICodeScopeUnit* scope = context.scope; \ compilation::IFunctionUnit* function = context.function; AdvancedInstructions::AdvancedInstructions(compilation::Context ctx) : context(ctx), tyNum(static_cast (ctx.pass->man->llvm->toLLVMType(ExpandedType(TypeAnnotation(TypePrimitive::Num))))) { } llvm::Value* AdvancedInstructions::compileMapSolidOutput(const Expression &expr, const std::string hintRetVar) { EXPAND_CONTEXT UNUSED(scope); //initialization Symbol symbolIn = Attachments::get(expr.getOperands()[0]); ImplementationRec implIn = containers::Query::queryImplementation(symbolIn).extract(); // impl of input list size_t size = implIn.size; CodeScope* scopeLoop = expr.blocks.front(); std::string varEl = scopeLoop->__bindings[0]; Iterator* it = Iterator::create(context, symbolIn); llvm::Value *rangeFrom = it->begin(); llvm::Value *rangeTo = it->end(); //definitions ArrayType* tyNumArray = (ArrayType*) (llvm->toLLVMType(ExpandedType(TypeAnnotation(tag_array, TypePrimitive::Num, size)))); llvm::IRBuilder<> &builder = llvm->builder; llvm::BasicBlock *blockLoop = llvm::BasicBlock::Create(llvm->llvmContext, "loop", function->raw); llvm::BasicBlock *blockBeforeLoop = builder.GetInsertBlock(); llvm::BasicBlock *blockAfterLoop = llvm::BasicBlock::Create(llvm->llvmContext, "postloop", function->raw); Value* dataOut = llvm->builder.CreateAlloca(tyNumArray, ConstantInt::get(tyNum, size), NAME("map")); // * initial check Value* condBefore = builder.CreateICmpSLE(rangeFrom, rangeTo); builder.CreateCondBr(condBefore, blockLoop, blockAfterLoop); // create PHI: builder.SetInsertPoint(blockLoop); llvm::PHINode *stateLoop = builder.CreatePHI(tyNum, 2, "mapIt"); stateLoop->addIncoming(rangeFrom, blockBeforeLoop); // loop body: Value* elIn = it->get(stateLoop, varEl); compilation::ICodeScopeUnit* scopeLoopUnit = function->getScopeUnit(scopeLoop); scopeLoopUnit->bindArg(elIn, move(varEl)); Value* elOut = scopeLoopUnit->compile(); Value *pElOut = builder.CreateGEP(dataOut, ArrayRef(std::vector{ConstantInt::get(tyNum, 0), stateLoop})); builder.CreateStore(elOut, pElOut); //next iteration preparing Value *stateLoopNext = builder.CreateAdd(stateLoop, llvm::ConstantInt::get(tyNum, 1)); stateLoop->addIncoming(stateLoopNext, builder.GetInsertBlock()); //next iteration checks: Value* condAfter = builder.CreateICmpSLE(stateLoopNext, rangeTo); builder.CreateCondBr(condAfter, blockLoop, blockAfterLoop); //finalization: builder.SetInsertPoint(blockAfterLoop); return dataOut; } Value* AdvancedInstructions::compileArrayIndex(llvm::Value* aggregate, std::vector indexes, std::string hintRetVar) { EXPAND_CONTEXT UNUSED(function); UNUSED(scope); indexes.insert(indexes.begin(), llvm::ConstantInt::get(tyNum, 0)); llvm::Value *pEl = llvm->builder.CreateGEP(aggregate, llvm::ArrayRef(indexes)); return llvm->builder.CreateLoad(pEl, NAME("el")); } Value* AdvancedInstructions::compileStructIndex(llvm::Value* aggregate, const ExpandedType& t, const std::string& idx) { EXPAND_CONTEXT UNUSED(scope); UNUSED(function); TypeUtils types(llvm); std::vector&& fields = types.getStructFields(t); for (unsigned i = 0, size = fields.size(); i < size; ++i) { if (fields.at(i) == idx) { //dereference pointer if (types.isPointer(t)) { llvm::Value* addr = llvm->builder.CreateConstGEP2_32(nullptr, aggregate, 0, i); return llvm->builder.CreateLoad(addr); } return llvm->builder.CreateExtractValue(aggregate, llvm::ArrayRef{i}); } } assert(false && "not found required struct field"); return nullptr; } llvm::Value* AdvancedInstructions::compileFold(const Expression& fold, const std::string& hintRetVar) { EXPAND_CONTEXT assert(fold.op == Operator::FOLD); //initialization: Symbol varInSymbol = Attachments::get(fold.getOperands()[0]); Implementation info = Query::queryImplementation(varInSymbol); Iterator* it = Iterator::create(context, varInSymbol); llvm::Value* rangeBegin = it->begin(); llvm::Value* rangeEnd = it->end(); llvm::Value* accumInit = scope->process(fold.getOperands()[1]); std::string varIn = fold.getOperands()[0].getValueString(); std::string varAccum = fold.bindings[1]; std::string varEl = fold.bindings[0]; llvm::BasicBlock *blockBeforeLoop = llvm->builder.GetInsertBlock(); std::unique_ptr transformerSaturation(new TransformerSaturation(blockBeforeLoop, context.pass->managerTransformations)); llvm::BasicBlock *blockLoop = llvm::BasicBlock::Create(llvm->llvmContext, "fold", function->raw); llvm::BasicBlock *blockLoopBody = llvm::BasicBlock::Create(llvm->llvmContext, "fold_body", function->raw); llvm::BasicBlock *blockAfterLoop = llvm::BasicBlock::Create(llvm->llvmContext, "fold_after", function->raw); llvm::BasicBlock *blockNext = llvm::BasicBlock::Create(llvm->llvmContext, "fold_next", function->raw); llvm->builder.CreateBr(blockLoop); // * create phi llvm->builder.SetInsertPoint(blockLoop); llvm::PHINode *accum = llvm->builder.CreatePHI(accumInit->getType(), 2, varAccum); accum->addIncoming(accumInit, blockBeforeLoop); llvm::PHINode *itLoop = llvm->builder.CreatePHI(rangeBegin->getType(), 2, "foldIt"); itLoop->addIncoming(rangeBegin, blockBeforeLoop); // * loop checks Value* condRange = llvm->builder.CreateICmpNE(itLoop, rangeEnd); llvm->builder.CreateCondBr(condRange, blockLoopBody, blockAfterLoop); // * loop body llvm->builder.SetInsertPoint(blockLoopBody); CodeScope* scopeLoop = fold.blocks.front(); compilation::ICodeScopeUnit* loopUnit = function->getScopeUnit(scopeLoop); Value* elIn = it->get(itLoop); loopUnit->bindArg(accum, move(varAccum)); loopUnit->bindArg(elIn, move(varEl)); Value* accumNext = loopUnit->compile(); // * Loop saturation checks bool flagSaturationTriggered = transformerSaturation->insertSaturationChecks(blockNext, blockAfterLoop, context); llvm::BasicBlock* blockSaturation = llvm->builder.GetInsertBlock(); if (!flagSaturationTriggered){ llvm->builder.CreateBr(blockNext); } // * computing next iteration state llvm->builder.SetInsertPoint(blockNext); Value *itLoopNext = it->advance(itLoop); accum->addIncoming(accumNext, llvm->builder.GetInsertBlock()); itLoop->addIncoming(itLoopNext, llvm->builder.GetInsertBlock()); llvm->builder.CreateBr(blockLoop); // * finalization: llvm->builder.SetInsertPoint(blockAfterLoop); if (!flagSaturationTriggered){ return accum; } llvm::PHINode* result = llvm->builder.CreatePHI(accumInit->getType(), 2); result->addIncoming(accum, blockLoop); result->addIncoming(accumNext, blockSaturation); return result; } llvm::Value* AdvancedInstructions::compileFoldInf(const Expression& fold, const std::string& hintRetVar) { EXPAND_CONTEXT - assert(fold.op == Operator::FOLD_INF); + assert(fold.op == Operator::INF); std::string accumName = fold.bindings[0]; llvm::Value* accumInit = scope->process(fold.getOperands()[0]); llvm::BasicBlock *blockBeforeLoop = llvm->builder.GetInsertBlock(); llvm::BasicBlock *blockLoop = llvm::BasicBlock::Create(llvm->llvmContext, "foldinf", function->raw); llvm::BasicBlock *blockNext = llvm::BasicBlock::Create(llvm->llvmContext, "foldinf_next", function->raw); llvm::BasicBlock *blockAfterLoop = llvm::BasicBlock::Create(llvm->llvmContext, "foldinf_post", function->raw); std::unique_ptr transformerSaturation(new TransformerSaturation(blockBeforeLoop, context.pass->managerTransformations)); llvm->builder.CreateBr(blockLoop); // * create phi llvm->builder.SetInsertPoint(blockLoop); llvm::PHINode *accum = llvm->builder.CreatePHI(accumInit->getType(), 2, accumName); accum->addIncoming(accumInit, blockBeforeLoop); // * loop body CodeScope* scopeLoop = fold.blocks.front(); compilation::ICodeScopeUnit* unitLoop = function->getScopeUnit(scopeLoop); unitLoop->bindArg(accum, move(accumName)); Value* accumNext = unitLoop->compile(); // * Loop saturation checks bool flagSaturationTriggered = transformerSaturation->insertSaturationChecks(blockNext, blockAfterLoop, context); assert(flagSaturationTriggered); // * computing next iteration state llvm->builder.SetInsertPoint(blockNext); accum->addIncoming(accumNext, llvm->builder.GetInsertBlock()); llvm->builder.CreateBr(blockLoop); // finalization: llvm->builder.SetInsertPoint(blockAfterLoop); return accumNext; } llvm::Value* AdvancedInstructions::compileIf(const Expression& exprIf, const std::string& hintRetVar) { EXPAND_CONTEXT const Expression& condExpr = exprIf.getOperands()[0]; llvm::IRBuilder<>& builder = llvm->builder; assert(builder.GetInsertBlock() == scope->currentBlockRaw); //initialization: llvm::BasicBlock *blockEpilog = llvm::BasicBlock::Create(llvm->llvmContext, "ifAfter", function->raw); llvm::BasicBlock *blockTrue = llvm::BasicBlock::Create(llvm->llvmContext, "ifTrue", function->raw); llvm::BasicBlock *blockFalse = llvm::BasicBlock::Create(llvm->llvmContext, "ifFalse", function->raw); llvm::Value* cond = scope->process(condExpr); builder.SetInsertPoint(blockTrue); CodeScope* scopeTrue = exprIf.blocks.front(); llvm::Value* resultTrue = function->getScopeUnit(scopeTrue)->compile(); llvm::BasicBlock * blockTrueEnd = builder.GetInsertBlock(); builder.CreateBr(blockEpilog); builder.SetInsertPoint(blockFalse); CodeScope* scopeFalse = exprIf.blocks.back(); llvm::Value* resultFalse = function->getScopeUnit(scopeFalse)->compile(); llvm::BasicBlock * blockFalseEnd = builder.GetInsertBlock(); builder.CreateBr(blockEpilog); builder.SetInsertPoint(scope->currentBlockRaw); llvm->builder.CreateCondBr(cond, blockTrue, blockFalse); builder.SetInsertPoint(blockEpilog); llvm::PHINode *ret = builder.CreatePHI(resultTrue->getType(), 2, NAME("if")); ret->addIncoming(resultTrue, blockTrueEnd); ret->addIncoming(resultFalse, blockFalseEnd); return ret; } //TODO Switch: default variant no needed when all possible conditions are considered llvm::Value* AdvancedInstructions::compileSwitch(const Expression& exprSwitch, const std::string& hintRetVar) { EXPAND_CONTEXT UNUSED(function); AST* root = context.pass->man->root; llvm::IRBuilder<>& builder = llvm->builder; assert(exprSwitch.operands.size() >= 2); assert(exprSwitch.operands[1].op == Operator::CASE_DEFAULT && "No default case in Switch Statement"); int countCases = exprSwitch.operands.size() - 1; llvm::BasicBlock* blockProlog = builder.GetInsertBlock(); llvm::BasicBlock *blockEpilog = llvm::BasicBlock::Create(llvm->llvmContext, "switchAfter", function->raw); builder.SetInsertPoint(blockEpilog); llvm::Type* exprSwitchType = llvm->toLLVMType(root->getType(exprSwitch)); llvm::PHINode *ret = builder.CreatePHI(exprSwitchType, countCases, NAME("switch")); llvm::Type* typI8 = llvm::Type::getInt8Ty(llvm->llvmContext); builder.SetInsertPoint(blockProlog); llvm::Value * conditionSwitch = scope->process(exprSwitch.operands[0]); llvm::BasicBlock *blockDefault = llvm::BasicBlock::Create(llvm->llvmContext, "caseDefault", function->raw); llvm::SwitchInst * instructionSwitch = builder.CreateSwitch( typeinference::doAutomaticTypeConversion(conditionSwitch, typI8, builder), blockDefault, countCases); for (int size = exprSwitch.operands.size(), i = 2; i < size; ++i) { llvm::BasicBlock *blockCase = llvm::BasicBlock::Create(llvm->llvmContext, "case" + std::to_string(i), function->raw); llvm::Value* condCase = function->getScopeUnit(exprSwitch.operands[i].blocks.front())->compile(); builder.SetInsertPoint(blockCase); llvm::Value* resultCase = function->getScopeUnit(exprSwitch.operands[i].blocks.back())->compile(); builder.CreateBr(blockEpilog); ret->addIncoming(resultCase, builder.GetInsertBlock()); builder.SetInsertPoint(blockProlog); instructionSwitch->addCase( dyn_cast( typeinference::doAutomaticTypeConversion(condCase, typI8, builder)), blockCase); } //compile default block: builder.SetInsertPoint(blockDefault); CodeScope* scopeDefault = exprSwitch.operands[1].blocks.front(); llvm::Value* resultDefault = function->getScopeUnit(scopeDefault)->compile(); builder.CreateBr(blockEpilog); ret->addIncoming(resultDefault, builder.GetInsertBlock()); builder.SetInsertPoint(blockEpilog); return ret; } llvm::Value* AdvancedInstructions::compileSwitchVariant(const Expression& exprSwitch, const std::string& hintRetVar) { EXPAND_CONTEXT UNUSED(function); AST* root = context.pass->man->root; llvm::IRBuilder<>& builder = llvm->builder; llvm::Type* typI8= llvm::Type::getInt8Ty(llvm->llvmContext); const ExpandedType& typVariant = root->getType(exprSwitch.operands.at(0)); llvm::Type* typVariantRaw = llvm->toLLVMType(typVariant); assert(typVariant->__operands.size() == exprSwitch.operands.size() - 1 && "Ill-formed Switch Variant"); int casesCount = exprSwitch.operands.size(); llvm::BasicBlock* blockProlog = builder.GetInsertBlock(); llvm::BasicBlock *blockEpilog = llvm::BasicBlock::Create(llvm->llvmContext, "switchAfter", function->raw); builder.SetInsertPoint(blockEpilog); llvm::Type* resultType = llvm->toLLVMType(root->getType(exprSwitch)); llvm::PHINode *ret = builder.CreatePHI(resultType, casesCount, NAME("switch")); builder.SetInsertPoint(blockProlog); llvm::Value * conditionSwitchRaw = scope->process(exprSwitch.operands.at(0)); llvm::Value* idRaw = builder.CreateExtractValue(conditionSwitchRaw, llvm::ArrayRef({0})); //Dereference preparation const bool flagPrepareDerefence = std::any_of(typVariant->__operands.begin(), typVariant->__operands.end(), [](const TypeAnnotation& op){ return op.isValid(); }); llvm::Value* addrAsStorage = nullptr; if (flagPrepareDerefence){ assert(exprSwitch.bindings.size() && "Switch condition alias not found"); llvm::Type* typStorageRaw = llvm::cast(typVariantRaw)->getElementType(1); llvm::Value* storageRaw = builder.CreateExtractValue(conditionSwitchRaw, llvm::ArrayRef({1})); addrAsStorage = llvm->builder.CreateAlloca(typStorageRaw); llvm->builder.CreateStore(storageRaw, addrAsStorage); } llvm::SwitchInst * instructionSwitch = builder.CreateSwitch(idRaw, nullptr, casesCount); llvm::BasicBlock* blockDefaultUndefined; std::list::const_iterator scopeCaseIt = exprSwitch.blocks.begin(); for (int instancesSize = exprSwitch.operands.size()-1, instId = 0; instId < instancesSize; ++instId) { llvm::BasicBlock *blockCase = llvm::BasicBlock::Create(llvm->llvmContext, "case" + std::to_string(instId), function->raw); builder.SetInsertPoint(blockCase); ICodeScopeUnit* unitCase = function->getScopeUnit(*scopeCaseIt); const ExpandedType& instType = ExpandedType(typVariant->__operands.at(instId)); //Actual variant derefence if (instType->isValid()) { string identCondition = exprSwitch.bindings.front(); llvm::Type* instTypeRaw = llvm->toLLVMType(instType); llvm::Value* addrAsInst = llvm->builder.CreateBitOrPointerCast(addrAsStorage, instTypeRaw->getPointerTo()); llvm::Value* instRaw = llvm->builder.CreateLoad(instTypeRaw, addrAsInst); const Symbol& identSymb = unitCase->bindArg(instRaw, move(identCondition)); Attachments::put(identSymb, instType); } llvm::Value* resultCase = function->getScopeUnit(*scopeCaseIt)->compile(); builder.CreateBr(blockEpilog); ret->addIncoming(resultCase, blockDefaultUndefined = builder.GetInsertBlock()); builder.SetInsertPoint(blockProlog); instructionSwitch->addCase(dyn_cast(llvm::ConstantInt::get(typI8, exprSwitch.operands.at(instId+1).getValueDouble())), blockCase); ++scopeCaseIt; } instructionSwitch->setDefaultDest(blockDefaultUndefined); builder.SetInsertPoint(blockEpilog); return ret; } //TODO recognize cases to make const arrays/stored in global mem/stack alloced. llvm::Value* AdvancedInstructions::compileListAsSolidArray(const Expression &expr, const std::string& hintRetVar) { EXPAND_CONTEXT UNUSED(scope); UNUSED(function); AST* root = context.pass->man->root; const size_t& length = expr.getOperands().size(); const Expression& expression = expr; llvm::Value* zero = ConstantInt::get(tyNum, 0); llvm::Value* one = ConstantInt::get(tyNum, 1); ExpandedType typAggrExpanded = root->getType(expression); - assert(typAggrExpanded->__operator == TypeOperator::LIST); + assert(typAggrExpanded->__operator == TypeOperator::LIST_ARRAY); llvm::Type* typEl = llvm->toLLVMType(ExpandedType(typAggrExpanded->__operands[0])); ArrayType* typAggr = (ArrayType*) llvm::ArrayType::get(typEl, length); llvm::Value* list = llvm->builder.CreateAlloca(typAggr, ConstantInt::get(Type::getInt32Ty(llvm->llvmContext), length, false), hintRetVar); const std::vector& operands = expression.getOperands(); llvm::Value* addrOperand = llvm->builder.CreateGEP(typAggr, list, ArrayRef(std::vector{zero, zero})); llvm->builder.CreateStore(scope->process(operands.front()), addrOperand) ; for (auto i=++operands.begin(); i!=operands.end(); ++i){ addrOperand = llvm->builder.CreateGEP(typEl, addrOperand, ArrayRef(std::vector{one})); llvm->builder.CreateStore(scope->process(*i), addrOperand) ; } return list; // Value* listDest = l.builder.CreateAlloca(typList, ConstantInt::get(typI32, __size), *hintRetVar); // l.buil1der.CreateMemCpy(listDest, listSource, __size, 16); } llvm::Value* AdvancedInstructions::compileConstantStringAsPChar(const string& data, const std::string& hintRetVar) { EXPAND_CONTEXT UNUSED(function); UNUSED(scope); Type* typPchar = PointerType::getUnqual(Type::getInt8Ty(llvm->llvmContext)); //ArrayType* typStr = (ArrayType*) (llvm->toLLVMType(ExpandedType(TypeAnnotation(tag_array, TypePrimitive::I8, size+1)))); /* std::vector chars; chars.reserve(size+1); for (size_t i=0; i< size; ++i){ chars[i] = ConstantInt::get(typI8, (unsigned char) data[i]); } chars[size] = ConstantInt::get(typI8, 0); */ Value* rawData = ConstantDataArray::getString(llvm->llvmContext, data); Value* rawPtrData = llvm->builder.CreateAlloca(rawData->getType(), ConstantInt::get(Type::getInt32Ty(llvm->llvmContext), 1, false)); llvm->builder.CreateStore(rawData, rawPtrData); return llvm->builder.CreateCast(llvm::Instruction::BitCast, rawPtrData, typPchar, hintRetVar); } llvm::Value* AdvancedInstructions::compileSequence(const Expression &expr){ EXPAND_CONTEXT UNUSED(scope); UNUSED(llvm); llvm::Value* result; for(CodeScope* scope: expr.blocks){ result = function->getScopeUnit(scope)->compile(); } return result; } diff --git a/cpp/src/compilation/containers.cpp b/cpp/src/compilation/containers.cpp index f8d36fc..ae85604 100644 --- a/cpp/src/compilation/containers.cpp +++ b/cpp/src/compilation/containers.cpp @@ -1,206 +1,206 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * File: containers.cpp * Author: pgess * * \file compilation/containers.h * \brief Containers compilation support. See more [details on Containers](/w/concepts/containers) */ #include "compilation/containers.h" using namespace std; using namespace llvm; using namespace xreate; using namespace xreate::containers; Iterator* Iterator::create(xreate::compilation::Context context, const xreate::Symbol& var){ const Implementation& data = Query::queryImplementation(var); switch(data.impl){ case ON_THE_FLY: return new IteratorForward(context, var, data.extract()); case SOLID: return new IteratorForward(context, var, data.extract()); default: assert(true); } assert(false && "Unknown declaration"); return nullptr; } llvm::Value* IteratorForward::begin() { switch(sourceDecl.op) { case xreate::Operator::LIST: { sourceRawType = llvm::Type::getInt32Ty(llvm->llvmContext); return llvm::ConstantInt::get(Type::getInt32Ty(llvm->llvmContext), 0); }; case xreate::Operator::LIST_RANGE:{ assert(sourceDecl.operands.size()==2); llvm::Value* result = sourceUnit->process(sourceDecl.operands.at(0)); sourceRawType = result->getType(); return result; }; default: break; } if (linkedlist){ llvm::Value* result = sourceUnit->process(sourceDecl); sourceRawType = result->getType(); return result; } assert(false); } llvm::Value* IteratorForward::end(){ switch(sourceDecl.op) { case xreate::Operator::LIST: { size_t idLast = sourceDecl.operands.size() - 1; return ConstantInt::get(sourceRawType, idLast); } case xreate::Operator::LIST_RANGE: { assert(sourceDecl.operands.size() == 2); llvm::Value* valueEndOfRange = sourceUnit->process(sourceDecl.operands.at(1)); llvm::Value* valueConstOne = llvm::ConstantInt::get(llvm::Type::getInt32Ty(llvm->llvmContext), 1); return llvm->builder.CreateAdd(valueEndOfRange, valueConstOne); }; default: break; } //return null pointer if (linkedlist){ return ConstantPointerNull::getNullValue(sourceRawType); } assert(false && "Unknown declaration"); return nullptr; } llvm::Value* IteratorForward::get(Value* index,const std::string& hintRetVar){ const Expression& currentDecl = CodeScope::getDefinition(current); switch (currentDecl.op) { case xreate::Operator::LIST: { //TODO re check is it right scope(source) to compile currentDecl. Provide unittests. llvm::Value* currentValue = sourceUnit->processSymbol(current); return xreate::compilation::AdvancedInstructions(context).compileArrayIndex(currentValue, std::vector{index}); }; case xreate::Operator::LIST_RANGE: { return index; }; case xreate::Operator::MAP: { assert(currentDecl.getOperands().size()==1); assert(currentDecl.bindings.size()); assert(currentDecl.blocks.size()); CodeScope* scopeLoop = currentDecl.blocks.front(); std::string varEl = currentDecl.bindings[0]; const Symbol& symbIn = Attachments::get(currentDecl.getOperands()[0]); auto it = std::unique_ptr(Iterator::create(context, symbIn)); Value* elIn = it->get(index, varEl); compilation::ICodeScopeUnit* unitLoop = function->getScopeUnit(scopeLoop); unitLoop->bindArg(elIn, std::move(varEl)); return unitLoop->compile(); } case xreate::Operator::INVALID: { //TODO review iterator determination strategy for case of Expression::BINDING assert(currentDecl.__state==Expression::IDENT); const Symbol& symbIn = Attachments::get(currentDecl); auto it = std::unique_ptr(Iterator::create(context, symbIn)); return it->get(index); }; default: break; } if (linkedlist){ return index; } assert(false && "Unknown declaration"); return nullptr; } llvm::Value* IteratorForward::advance(Value* index, const std::string& hintRetVar){ switch(sourceDecl.op) { case xreate::Operator::LIST: case xreate::Operator::LIST_RANGE: return llvm->builder.CreateAdd(index, llvm::ConstantInt::get(llvm::Type::getInt32Ty(llvm->llvmContext), 1), hintRetVar); default: break; } if (linkedlist){ ExpandedType tySource = llvm->ast->getType(CodeScope::getDefinition(source)); - assert(tySource->__operator == TypeOperator::LIST && "Linked list implementation has to have ARRAY type"); + assert(tySource->__operator == TypeOperator::LIST_ARRAY && "Linked list implementation has to have ARRAY type"); assert(tySource->__operands.size()); return xreate::compilation::AdvancedInstructions(context).compileStructIndex(index, ExpandedType(TypeAnnotation(tySource->__operands.at(0))), linkedlist.fieldPointer); } assert(false && "Unknown declaration"); return nullptr; } //const ImplementationRec& implementation IteratorForward::IteratorForward(const compilation::Context& ctx, const xreate::Symbol& symbolContainer, const ImplementationRec& implementation) : Iterator(), __length(implementation.size), llvm(ctx.pass->man->llvm) { __container = ctx.function->getScopeUnit(symbolContainer.scope)->processSymbol(symbolContainer); } llvm::Value* IteratorForward::begin(){ //0 return llvm::ConstantInt::get(llvm::Type::getInt32Ty(llvm->llvmContext), 0); } llvm::Value* IteratorForward::end(){ //length return llvm::ConstantInt::get(llvm::Type::getInt32Ty(llvm->llvmContext), __length); } llvm::Value* IteratorForward::get(llvm::Value* index,const std::string& hintRetVar){ //GEP[index]] llvm::Type* tyNum = llvm::Type::getInt32Ty(llvm->llvmContext); llvm::Value* pResult = llvm->builder.CreateGEP(__container, ArrayRef(std::vector{ConstantInt::get(tyNum, 0), index})); return llvm->builder.CreateLoad(pResult, hintRetVar); } llvm::Value* IteratorForward::advance(llvm::Value* index, const std::string& hintRetVar){ //index + 1 llvm::Type* tyNum = llvm::Type::getInt32Ty(llvm->llvmContext); return llvm->builder.CreateAdd(index, llvm::ConstantInt::get(tyNum, 1), hintRetVar); } diff --git a/cpp/src/compilation/interpretation-instructions.cpp b/cpp/src/compilation/interpretation-instructions.cpp index 7c4845f..5ad4ffb 100644 --- a/cpp/src/compilation/interpretation-instructions.cpp +++ b/cpp/src/compilation/interpretation-instructions.cpp @@ -1,116 +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 (__fnI12n->man)->ast; TranscendLayer* transcend = static_cast (__fnI12n->man)->pass->man->transcend; ExpandedType targetT = ast->getType(expression); assert(expression.operands.size() == 1); assert(expression.operands.front().__state == Expression::STRING); - assert(targetT->__operator == TypeOperator::LIST); + assert(targetT->__operator == TypeOperator::LIST_ARRAY); std::string namePredicate = expression.operands.front().getValueString(); StaticModel model = (static_cast (__fnI12n->man))->pass->man->transcend->query(namePredicate); Expression result(Operator::LIST,{}); result.operands.reserve(model.size()); ExpandedType elementT = targetT->__operands.at(0).__operator == TypeOperator::SLAVE ? dereferenceSlaveType(ExpandedType(targetT->__operands.at(0)), transcend) : ExpandedType(targetT->__operands.at(0)); if(model.size()) { - if (elementT->__operator == TypeOperator::LIST_NAMED) { + if (elementT->__operator == TypeOperator::LIST_RECORD) { //edge case, content's type is LIST_NAMED: for(const auto& row : model) { result.operands.push_back(representTransExpression(row.second, elementT, transcend)); } } else { for (const auto& row : model) { assert(row.second.args().size); result.operands.push_back(representTransExpression(row.second.args()[0], elementT, transcend)); } } } 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) { + if (argT->__operator == TypeOperator::LIST_RECORD) { 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 +} //end of xreate::interpretation diff --git a/cpp/src/compilation/operators.cpp b/cpp/src/compilation/operators.cpp index 2c93079..5ad1983 100644 --- a/cpp/src/compilation/operators.cpp +++ b/cpp/src/compilation/operators.cpp @@ -1,75 +1,75 @@ /* 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/. * * operators.cpp * * Author: pgess * Created on April 8, 2017, 1:35 PM */ /** * \file operators.h * \brief Helpers to compile various operators */ #include "operators.h" #include "llvmlayer.h" #include "ExternLayer.h" #include using namespace llvm; using namespace std; namespace xreate { namespace pointerarithmetic { llvm::Value* PointerArithmetic::add(llvm::Value *left, llvm::Value *right, compilation::Context context, const std::string& hintVarDecl){ LLVMLayer* llvm = context.pass->man->llvm; if (left->getType()->isPointerTy() && right->getType()->isIntegerTy()){ std::vector indexes{right}; //{llvm::ConstantInt::get(llvm::Type::getInt32Ty(llvm::getGlobalContext()), 0)}; //indexes.push_back(right); return llvm->builder.CreateGEP(left, llvm::ArrayRef(indexes), hintVarDecl); } return nullptr; } }//end of pointgerarithmetic namespace llvm::Value* StructUpdate::add(const Expression& left, llvm::Value *leftRaw, const Expression& right, compilation::Context context, const std::string& hintVarDecl){\ - if (!(right.__state == Expression::COMPOUND && right.op == Operator::LIST_NAMED)){ + if (!(right.__state == Expression::COMPOUND && right.op == Operator::LIST)){ return nullptr; } PassManager* man = context.pass->man; ExpandedType tyOperandLeft = man->root->getType(left); const std::vector fieldsFormal = (tyOperandLeft.get().__operator == TypeOperator::CUSTOM)? man->llvm->layerExtern->getStructFields(man->llvm->layerExtern->lookupType(tyOperandLeft.get().__valueCustom)) : tyOperandLeft.get().fields; std::map indexFields; for(size_t i=0, size = fieldsFormal.size(); iprocess(value, right.bindings.at(i)); unsigned int fieldId = indexFields.at(right.bindings.at(i)); result = man->llvm->builder.CreateInsertValue(result, valueRaw, llvm::ArrayRef({fieldId})); } return result; } } //end of xreate namespace diff --git a/cpp/src/compilation/targetinterpretation.cpp b/cpp/src/compilation/targetinterpretation.cpp index 17457db..4f4555a 100644 --- a/cpp/src/compilation/targetinterpretation.cpp +++ b/cpp/src/compilation/targetinterpretation.cpp @@ -1,628 +1,627 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * File: targetinterpretation.cpp * Author: pgess * * Created on June 29, 2016, 6:45 PM */ /** * \file targetinterpretation.h * \brief Interpretation support. See more [details on Interpretation](/w/concepts/dsl/) */ #include "compilation/targetinterpretation.h" #include "pass/interpretationpass.h" #include "analysis/typeinference.h" #include "llvmlayer.h" #include "compilation/scopedecorators.h" #include "compilation/interpretation-instructions.h" #include #include #include using namespace std; using namespace xreate::compilation; namespace xreate{ namespace interpretation{ const Expression EXPRESSION_FALSE = Expression(Atom(0)); const Expression EXPRESSION_TRUE = Expression(Atom(1)); CodeScope* InterpretationScope::processOperatorIf(const Expression& expression) { const Expression& exprCondition = process(expression.getOperands()[0]); if (exprCondition == EXPRESSION_TRUE) { return expression.blocks.front(); } return expression.blocks.back(); } CodeScope* InterpretationScope::processOperatorSwitch(const Expression& expression) { const Expression& exprCondition = process(expression.operands[0]); bool flagHasDefault = expression.operands[1].op == Operator::CASE_DEFAULT; //TODO check that one and only one case variant is appropriate for (size_t size = expression.operands.size(), i = flagHasDefault ? 2 : 1; i < size; ++i) { const Expression& exprCase = process(expression.operands[i]); if (function->getScope((const CodeScope*) exprCase.blocks.front())->processScope() == exprCondition) { return exprCase.blocks.back(); } } if (flagHasDefault) { const Expression& exprCaseDefault = expression.operands[1]; return exprCaseDefault.blocks.front(); } assert(false && "Switch has no appropriate variant"); return nullptr; } CodeScope* InterpretationScope::processOperatorSwitchVariant(const Expression& expression) { const Expression& condition = process(expression.operands.at(0)); assert(condition.op == Operator::VARIANT); const string& identCondition = expression.bindings.front(); Expression opExpected(Atom(condition.getValueDouble())); auto itFoundValue = std::find(++expression.operands.begin(), expression.operands.end(), opExpected); assert(itFoundValue != expression.operands.end()); int indexBlock = itFoundValue - expression.operands.begin() - 1; auto blockFound = expression.blocks.begin(); std::advance(blockFound, indexBlock); InterpretationScope* scopeI12n = function->getScope(*blockFound); if(condition.operands.size()) { const Expression& value = condition.operands.at(0); scopeI12n->overrideBindings({ {value, identCondition} }); } return *blockFound; } llvm::Value* InterpretationScope::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; } case SWITCH_INTERPRET_CONDITION: { CodeScope* scopeResult = processOperatorSwitch(expression); llvm::Value* result = context.function->getScopeUnit(scopeResult)->compile(); return result; } case SWITCH_VARIANT: { CodeScope* scopeResult = processOperatorSwitchVariant(expression); const Expression& condition = expression.operands.at(0); const Expression& valueCondition = process(condition); const string identCondition = expression.bindings.front(); auto scopeCompilation = Decorators::getInterface(context.function->getScopeUnit(scopeResult)); if(valueCondition.operands.size()) { //override value Symbol symbCondition{ScopedSymbol{scopeResult->__identifiers.at(identCondition), versions::VERSION_NONE}, scopeResult}; scopeCompilation->overrideDeclarations({ {symbCondition, Expression(valueCondition.operands.at(0))}} ); //set correct type for binding: TypeAnnotation typeVariant = typeinference::getType(condition, *function->man->ast); int conditionIndex = valueCondition.getValueDouble(); ScopedSymbol symbolInternal = scopeResult->getSymbol(identCondition); scopeResult->__declarations[symbolInternal].bindType(typeVariant.__operands.at(conditionIndex)); } llvm::Value* result = context.function->getScopeUnit(scopeResult)->compile(); return result; } case SWITCH_LATE: { latereasoning::LateReasoningCompiler compiler(dynamic_cast(this->function), context); return compiler.processSwitchLateStatement(expression, ""); } case FOLD_INTERPRET_INPUT: { //initialization const Expression& exprInput = process(expression.getOperands()[0]); assert(exprInput.op == Operator::LIST); CodeScope* scopeBody = expression.blocks.front(); const string& nameEl = expression.bindings[0]; Symbol symbEl{ScopedSymbol{scopeBody->__identifiers.at(nameEl), versions::VERSION_NONE}, scopeBody}; const std::string& idAccum = expression.bindings[1]; llvm::Value* rawAccum = context.scope->process(expression.getOperands()[1]); InterpretationScope* intrBody = function->getScope(scopeBody); auto unitBody = Decorators::getInterface(context.function->getScopeUnit(scopeBody)); const std::vector elementsInput = exprInput.getOperands(); for(size_t i = 0; i < elementsInput.size(); ++i) { const Expression& exprElement = elementsInput[i]; intrBody->overrideBindings({ {exprElement, nameEl} }); unitBody->overrideDeclarations({ {symbEl, exprElement} }); //resets unitBody unitBody->bindArg(rawAccum, string(idAccum)); rawAccum = unitBody->compile(); } return rawAccum; } // case FOLD_INF_INTERPRET_INOUT: // { // } //TODO refactor as InterpretationCallStatement class case CALL_INTERPRET_PARTIAL: { const std::string &calleeName = expression.getValueString(); ICodeScopeUnit* scopeUnitSelf = context.scope; ManagedFnPtr callee = this->function->man->ast->findFunction(calleeName); const FunctionInterpretationData& calleeData = FunctionInterpretationHelper::getSignature(callee); std::vector argsActual; PIFSignature sig; sig.declaration = callee; for(size_t no = 0, size = expression.operands.size(); no < size; ++no) { const Expression& op = expression.operands[no]; if (calleeData.signature.at(no) == INTR_ONLY) { sig.bindings.push_back(process(op)); continue; } argsActual.push_back(scopeUnitSelf->process(op)); } TargetInterpretation* man = dynamic_cast (this->function->man); PIFunction* pifunction = man->getFunction(move(sig)); llvm::Function* raw = pifunction->compile(); boost::scoped_ptr statement(new BruteFnInvocation(raw, man->pass->man->llvm)); return (*statement)(move(argsActual)); } case QUERY_LATE: { return IntrinsicQueryInstruction( dynamic_cast(this->function)) .processLate(expression, context); } default: break; } assert(false && "Unknown late interpretation operator"); return nullptr; } llvm::Value* InterpretationScope::compile(const Expression& expression, const Context& context) { const InterpretationData& data = Attachments::get(expression); if (data.op != InterpretationOperator::NONE) { return 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")) { std::raise(SIGINT); } #endif PassManager* man = (static_cast (function->man))->pass->man; switch (expression.__state) { case Expression::INVALID: assert(false); case Expression::NUMBER: case Expression::STRING: return expression; case Expression::IDENT: { Symbol s = Attachments::get(expression); return Parent::processSymbol(s); } case Expression::COMPOUND: break; default: assert(false); } switch (expression.op) { case Operator::EQU: { const Expression& left = process(expression.operands[0]); const Expression& right = process(expression.operands[1]); if (left == right) return EXPRESSION_TRUE; return EXPRESSION_FALSE; } case Operator::NE: { const Expression& left = process(expression.operands[0]); const Expression& right = process(expression.operands[1]); if (left == right) return EXPRESSION_FALSE; return EXPRESSION_TRUE; } case Operator::LOGIC_AND: { assert(expression.operands.size() == 1); return process (expression.operands[0]); } // case Operator::LOGIC_OR: case Operator::CALL: { const std::string &fnName = expression.getValueString(); ManagedFnPtr fnAst = this->function->man->ast->findFunction(fnName); InterpretationFunction* fnUnit = this->function->man->getFunction(fnAst); vector args; args.reserve(expression.getOperands().size()); for(size_t i = 0, size = expression.getOperands().size(); i < size; ++i) { args.push_back(process(expression.getOperands()[i])); } return fnUnit->process(args); } case Operator::CALL_INTRINSIC: { assert(false && "Unknown intrinsic"); } 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::IF: { CodeScope* scopeResult = processOperatorIf(expression); return function->getScope(scopeResult)->processScope(); } case Operator::SWITCH: { CodeScope* scopeResult = processOperatorSwitch(expression); return function->getScope(scopeResult)->processScope(); } case Operator::SWITCH_VARIANT: { CodeScope* scopeResult = processOperatorSwitchVariant(expression); return function->getScope(scopeResult)->processScope(); } case Operator::VARIANT: { if(!expression.operands.size()) return expression; Expression variantData = process(expression.operands[0]); Expression result{Operator::VARIANT, {variantData}}; result.setValueDouble(expression.getValueDouble()); return result; } case Operator::INDEX: { Expression exprData = process(expression.operands[0]); for (size_t keyId = 1; keyId < expression.operands.size(); ++keyId) { const Expression& exprKey = process(expression.operands[keyId]); if (exprKey.__state == Expression::STRING) { const string& key = exprKey.getValueString(); assert(exprData.__indexBindings.count(key)); size_t idxKey = exprData.__indexBindings.at(key); exprData = Expression(exprData.operands.at(idxKey)); continue; } if (exprKey.__state == Expression::NUMBER) { int key = exprKey.getValueDouble(); exprData = Expression(exprData.operands[key]); continue; } assert(false && "Inappropriate key"); } return exprData; } case Operator::FOLD: { const Expression& exprInput = process(expression.getOperands()[0]); const Expression& exprInit = process(expression.getOperands()[1]); const std::string& argEl = expression.bindings[0]; const std::string& argAccum = expression.bindings[1]; InterpretationScope* body = function->getScope(expression.blocks.front()); Expression accum = exprInit; for(size_t size = exprInput.getOperands().size(), i = 0; i < size; ++i) { body->overrideBindings({ {exprInput.getOperands()[i], argEl}, {accum, argAccum} }); accum = body->processScope(); } return accum; } case Operator::LIST: - case Operator::LIST_NAMED: case Operator::LIST_RANGE: { Expression result(expression.op,{}); result.operands.resize(expression.operands.size()); result.bindings = expression.bindings; result.__indexBindings = expression.__indexBindings; int keyId = 0; for(const Expression& opCurrent : expression.operands) { result.operands[keyId++] = process(opCurrent); } return result; } // case Operator::MAP: { // break; // } default: break; } return expression; } InterpretationFunction* TargetInterpretation::getFunction(IFunctionUnit* unit) { if (__dictFunctionsByUnit.count(unit)) { return __dictFunctionsByUnit.at(unit); } InterpretationFunction* f = new InterpretationFunction(unit->function, this); __dictFunctionsByUnit.emplace(unit, f); assert(__functions.emplace(unit->function.id(), f).second); return f; } PIFunction* TargetInterpretation::getFunction(PIFSignature&& sig) { auto f = __pifunctions.find(sig); if (f != __pifunctions.end()) { return f->second; } PIFunction* result = new PIFunction(PIFSignature(sig), __pifunctions.size(), this); __pifunctions.emplace(move(sig), result); assert(__dictFunctionsByUnit.emplace(result->functionUnit, result).second); return result; } InterpretationScope* TargetInterpretation::transformContext(const Context& c) { return this->getFunction(c.function)->getScope(c.scope->scope); } llvm::Value* TargetInterpretation::compile(const Expression& expression, const Context& ctx) { return transformContext(ctx)->compile(expression, ctx); } InterpretationFunction::InterpretationFunction(const ManagedFnPtr& function, Target* target) : Function(function, target) { } Expression InterpretationFunction::process(const std::vector& args) { InterpretationScope* body = getScope(__function->__entry); list> bindings; for(size_t i = 0, size = args.size(); i < size; ++i) { bindings.push_back(make_pair(args.at(i), body->scope->__bindings.at(i))); } body->overrideBindings(bindings); return body->processScope(); } // Partial function interpretation typedef BasicFunctionUnit PIFunctionUnitParent; class PIFunctionUnit : public PIFunctionUnitParent{ public: PIFunctionUnit(ManagedFnPtr f, std::set&& arguments, size_t id, CompilePass* p) : PIFunctionUnitParent(f, p), argumentsActual(move(arguments)), __id(id) { } protected: std::vector prepareSignature() override { LLVMLayer* llvm = PIFunctionUnitParent::pass->man->llvm; AST* ast = PIFunctionUnitParent::pass->man->root; CodeScope* entry = PIFunctionUnitParent::function->__entry; std::vector signature; for(size_t no : argumentsActual) { VNameId argId = entry->__identifiers.at(entry->__bindings.at(no)); ScopedSymbol arg{argId, versions::VERSION_NONE}; signature.push_back(llvm->toLLVMType(ast->expandType(entry->__declarations.at(arg).type))); } return signature; } llvm::Function::arg_iterator prepareBindings() override{ CodeScope* entry = PIFunctionUnitParent::function->__entry; ICodeScopeUnit* entryCompilation = PIFunctionUnitParent::getScopeUnit(entry); llvm::Function::arg_iterator fargsI = PIFunctionUnitParent::raw->arg_begin(); for(size_t no : argumentsActual) { ScopedSymbol arg{entry->__identifiers.at(entry->__bindings.at(no)), versions::VERSION_NONE}; entryCompilation->bindArg(&*fargsI, arg); fargsI->setName(entry->__bindings.at(no)); ++fargsI; } return fargsI; } virtual std::string prepareName() override { return PIFunctionUnitParent::prepareName() + "_" + std::to_string(__id); } private: std::set argumentsActual; size_t __id; } ; PIFunction::PIFunction(PIFSignature&& sig, size_t id, TargetInterpretation* target) : InterpretationFunction(sig.declaration, target), signatureInstance(move(sig)) { const FunctionInterpretationData& functionData = FunctionInterpretationHelper::getSignature(signatureInstance.declaration); std::set argumentsActual; for (size_t no = 0, size = functionData.signature.size(); no < size; ++no) { if (functionData.signature.at(no) != INTR_ONLY) { argumentsActual.insert(no); } } functionUnit = new PIFunctionUnit(signatureInstance.declaration, move(argumentsActual), id, target->pass); CodeScope* entry = signatureInstance.declaration->__entry; auto entryUnit = Decorators::getInterface<>(functionUnit->getEntry()); InterpretationScope* entryIntrp = InterpretationFunction::getScope(entry); list> bindingsPartial; list> declsPartial; for(size_t no = 0, sigNo = 0, size = entry->__bindings.size(); no < 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]); Symbol argSymbol{ScopedSymbol {argId, versions::VERSION_NONE}, entry}; declsPartial.push_back({argSymbol, signatureInstance.bindings[sigNo]}); ++sigNo; } } entryIntrp->overrideBindings(bindingsPartial); entryUnit->overrideDeclarations(declsPartial); } llvm::Function* PIFunction::compile() { llvm::Function* raw = functionUnit->compile(); return raw; } bool operator<(const PIFSignature& lhs, const PIFSignature& rhs) { if (lhs.declaration.id() != rhs.declaration.id()) { return lhs.declaration.id() < rhs.declaration.id(); } return lhs.bindings < rhs.bindings; } bool operator<(const PIFSignature& lhs, PIFunction * const rhs) { return lhs < rhs->signatureInstance; } bool operator<(PIFunction * const lhs, const PIFSignature& rhs) { return lhs->signatureInstance < rhs; } } } /** \class xreate::interpretation::InterpretationFunction * * Holds list of xreate::interpretation::InterpretationScope 's focused on interpretation of individual code scopes * * There is particulat subclass PIFunction intended to represent partially interpreted functions *\sa TargetInterpretation, [Interpretation Concept](/w/concepts/dfa) */ /** \class xreate::interpretation::TargetInterpretation * * Executed during compilation and intented to preprocess eligible parts of code. * Established on [Targets Infrastructure](\ref compilation::Target) * * Holds list of InterpretationFunction / PIFunction to represent interpretation process for individual functions * * In order to be activated during compilation process there is * InterpretationScopeDecorator implementation of ICodeScopeUnit * \sa InterpretationPass, compilation::Target, [Interpretation Concept](/w/concepts/dfa) * */ diff --git a/cpp/src/compilation/transformersaturation.cpp b/cpp/src/compilation/transformersaturation.cpp index 1411cca..4bf599c 100644 --- a/cpp/src/compilation/transformersaturation.cpp +++ b/cpp/src/compilation/transformersaturation.cpp @@ -1,84 +1,84 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * transformersaturation.cpp * * Author: pgess * Created on March 25, 2017, 10:06 PM */ /** * \file transformersaturation.h * \brief Loop saturation support */ #include "transformersaturation.h" #include "llvmlayer.h" using namespace llvm; namespace xreate { namespace compilation { TransformerSaturation::TransformerSaturation(llvm::BasicBlock* allocationBlock, TransformationsManager* manager) : man(manager), blockAllocation(allocationBlock){ if (man->exists()){ oldInstance = man->update(this); } else { - man->registerTransformer("break", this); + man->registerTransformer("final", this); } } TransformerSaturation::~TransformerSaturation(){ if (oldInstance) { man->update(oldInstance); } else { - man->unregisterTransformer("break", this); + man->unregisterTransformer("final", this); } } llvm::Value* TransformerSaturation::transform(const Expression& expression, llvm::Value* raw, const Context& ctx){ processBreak(ctx); return raw; } void TransformerSaturation::processBreak(const Context& ctx){ allocateFlag(ctx); //show the saturation flag llvm::IRBuilder<>& builder = ctx.pass->man->llvm->builder; llvm::Type* tyInt1 = llvm::Type::getInt1Ty(ctx.pass->man->llvm->llvmContext); llvm::Constant* constTrue = llvm::ConstantInt::get(tyInt1, 1); builder.CreateStore(constTrue, flagSaturation, true); } void TransformerSaturation::allocateFlag(const Context& ctx){ //allocation of saturation flag IRBuilder<> builder(blockAllocation, blockAllocation->getFirstInsertionPt()); llvm::Type* tyInt1 = llvm::Type::getInt1Ty(ctx.pass->man->llvm->llvmContext); llvm::Constant* constTrue = llvm::ConstantInt::get(tyInt1, 1); flagSaturation = builder.CreateAlloca(tyInt1, constTrue, "flagSaturation"); llvm::Constant* constFalse = llvm::ConstantInt::get(tyInt1, 0); builder.CreateStore(constFalse, flagSaturation, true); } bool TransformerSaturation::insertSaturationChecks(llvm::BasicBlock* blockContinue, llvm::BasicBlock* blockExit, const Context& ctx){ if (!flagSaturation) return false; llvm::IRBuilder<>& builder = ctx.pass->man->llvm->builder; builder.CreateCondBr(builder.CreateLoad(flagSaturation), blockExit, blockContinue); return true; } } } diff --git a/cpp/src/llvmlayer.cpp b/cpp/src/llvmlayer.cpp index eb4228b..6cca735 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: + case TypeOperator::LIST_ARRAY: { assert(t.__operands.size() == 1); TypeAnnotation elTy = t.__operands.at(0); return llvm::ArrayType::get(toLLVMType(ExpandedType(move(elTy)), conjuctions), t.__size); } - case TypeOperator::LIST_NAMED: + case TypeOperator::LIST_RECORD: { std::vector pack_; pack_.reserve(t.__operands.size()); std::transform(t.__operands.begin(), t.__operands.end(), std::inserter(pack_, pack_.end()), [this, &conjuctions](const TypeAnnotation & t) { return toLLVMType(ExpandedType(TypeAnnotation(t)), conjuctions); }); llvm::ArrayRef pack(pack_); //process recursive types: if (conjuctions.count(t.conjuctionId)) { auto result = conjuctions[t.conjuctionId]; result->setBody(pack, false); return result; } return llvm::StructType::get(llvmContext, pack, false); }; case TypeOperator::LINK: { llvm::StructType* conjuction = llvm::StructType::create(llvmContext); int id = t.conjuctionId; conjuctions.emplace(id, conjuction); return conjuction; }; case TypeOperator::CALL: { assert(false); }; case TypeOperator::CUSTOM: { //Look in extern types clang::QualType qt = layerExtern->lookupType(t.__valueCustom); return layerExtern->toLLVMType(qt); }; //DEBT omit ID field in case of single variant. case TypeOperator::VARIANT: { /* Variant Type Layout: * { * id :: i8, Holds stored variant id * storage:: type of biggest variant * } */ uint64_t sizeStorage = 0; llvm::Type* typStorageRaw = llvm::Type::getVoidTy(llvmContext); for(const TypeAnnotation& subtype : t.__operands) { llvm::Type* subtypeRaw = toLLVMType(ExpandedType(subtype), conjuctions); if (subtypeRaw->isVoidTy()) continue; uint64_t sizeSubtype = module->getDataLayout().getTypeStoreSize(subtypeRaw); if (sizeSubtype > sizeStorage) { sizeStorage = sizeSubtype; typStorageRaw = subtypeRaw; } } std::vector layout; layout.push_back(llvm::Type::getInt8Ty(llvmContext)); //id const bool flagHoldsData = sizeStorage > 0; if (flagHoldsData) { layout.push_back(typStorageRaw); //storage } return llvm::StructType::get(llvmContext, llvm::ArrayRef(layout)); } case TypeOperator::NONE: { switch (t.__value) { case TypePrimitive::I32: case TypePrimitive::Int: case TypePrimitive::Num: return llvm::Type::getInt32Ty(llvmContext); case TypePrimitive::Bool: return llvm::Type::getInt1Ty(llvmContext); case TypePrimitive::I8: return llvm::Type::getInt8Ty(llvmContext); case TypePrimitive::I64: return llvm::Type::getInt64Ty(llvmContext); case TypePrimitive::Float: return llvm::Type::getDoubleTy(llvmContext); case TypePrimitive::String: return llvm::Type::getInt8PtrTy(llvmContext); case TypePrimitive::Invalid: return llvm::Type::getVoidTy(llvmContext); default: assert(false); } } default: assert(false); } assert(false); return nullptr; } bool TypeUtils::isStruct(const ExpandedType& ty) { const TypeAnnotation& t = ty.get(); - if (t.__operator == TypeOperator::LIST_NAMED) { + if (t.__operator == TypeOperator::LIST_RECORD) { return true; } if (t.__operator != TypeOperator::CUSTOM) { return false; } clang::QualType tqual = llvm->layerExtern->lookupType(t.__valueCustom); const clang::Type * raw = tqual.getTypePtr(); // TODO skip ALL the pointers until non-pointer type found if (raw->isStructureType()) return true; if (!raw->isAnyPointerType()) return false; clang::QualType pointee = raw->getPointeeType(); return pointee->isStructureType(); } bool TypeUtils::isPointer(const ExpandedType &ty) { if (ty.get().__operator != TypeOperator::CUSTOM) return false; clang::QualType qt = llvm->layerExtern->lookupType(ty.get().__valueCustom); return llvm->layerExtern->isPointer(qt); } std::vector TypeUtils::getStructFields(const ExpandedType &t) { - return (t.get().__operator == TypeOperator::LIST_NAMED) + return (t.get().__operator == TypeOperator::LIST_RECORD) ? t.get().fields : llvm->layerExtern->getStructFields( llvm->layerExtern->lookupType(t.get().__valueCustom)); } diff --git a/cpp/src/modules.cpp b/cpp/src/modules.cpp index c8ff3f6..ca196eb 100644 --- a/cpp/src/modules.cpp +++ b/cpp/src/modules.cpp @@ -1,183 +1,168 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * modules.cpp * * Author: pgess * Created on July 22, 2017, 5:13 PM */ /** * \file modules.h * \brief Modules support */ #include "modules.h" #include "modules/Parser.h" #include "analysis/utils.h" #include #include #include #include #include +using namespace std; namespace fs = boost::filesystem; namespace xreate { namespace modules{ void -ModuleRecord::addModuleQuery(const Expression& query){ - __queries.push_back(query); +ModuleRecord::addRequest(const Expression& request){ + __requests.push_back(request); } void ModuleRecord::addControllerPath(const std::string& path){ __controllers.push_back(path); } void ModuleRecord::addDiscoveryPath(const std::string& path){ - __discoveries.push_back(path); + __discoveryPaths.push_back(path); } void ModuleRecord::addProperty(const Expression& prop){ __properties.push_back(prop); } void ModulesSolver::loadControllers(const ModuleRecord& module){ for (const std::string& pathController: module.__controllers){ std::fstream fileContent(pathController); __program << fileContent.rdbuf(); } } void ModulesSolver::extractProperties(const ModuleRecord& module){ - unsigned int moduleId = __registry->getModuleHash(module.__path); const std::string atomProperty = "bind_module"; - boost::format formatProperty(atomProperty + "(%1%, %2%)."); + boost::format formatProperty(atomProperty + "(\"%1%\", %2%)."); for (const Expression& property: module.__properties){ std::list reprProp = xreate::analysis::compile(property); assert(reprProp.size()== 1); - __program << (formatProperty % moduleId % reprProp.front()) + __program << (formatProperty % module.__path % reprProp.front()) << std::endl; } } void ModulesSolver::discoverModules(const ModuleRecord& moduleClient){ std::regex extXreate("\\.xreate$", std::regex::basic); - for(const std::string& path: moduleClient.__discoveries){ + for(const std::string& path: moduleClient.__discoveryPaths){ for(fs::directory_entry e: fs::recursive_directory_iterator(path)) { if (fs::is_regular_file(e.status())){ if (!std::regex_search(e.path().string(), extXreate)) continue; FILE* script = fopen(e.path().c_str(), "r"); Scanner scanner(script); Parser parser(&scanner); parser.Parse(); assert(!parser.errors->count && "Discovery errors"); parser.module.__path = e.path().c_str(); extractProperties(parser.module); fclose(script); } } } } void ModulesSolver::extractRequirements(const ModuleRecord& module){ - const std::string atomQuery = "module_require"; - boost::format formatProperty(atomQuery + "(%1%, %2%)."); - unsigned int moduleId = __registry->getModuleHash(module.__path); + const std::string atomQuery = "modules_require"; + boost::format formatProperty(atomQuery + "(\"%1%\", %2%)."); - for (const Expression& query: module.__queries){ + for (const Expression& query: module.__requests){ std::list reprQuery = xreate::analysis::compile(query); assert(reprQuery.size()== 1); - __program << (formatProperty % moduleId % reprQuery.front()) + __program << (formatProperty % module.__path % reprQuery.front()) << std::endl; } } void ModulesSolver::add(const std::string& base){ __program << base; } void ModulesSolver::init(const std::string& programBase, const ModuleRecord& module){ add(programBase); extractRequirements(module); extractProperties(module); loadControllers(module); discoverModules(module); std::cout << __program.str() << std::endl; } std::list ModulesSolver::run(const ModuleRecord& module){ - const std::string atomDecision = "module_include"; - unsigned int moduleId = __registry->getModuleHash(module.__path); + const std::string predicateResolution = "modules_resolution"; - std::list result; + std::map dictResolution; std::vector args{"clingo", nullptr}; DefaultGringoModule moduleDefault; Gringo::Scripts scriptsDefault(moduleDefault); ClingoLib ctl(scriptsDefault, 0, args.data(), {}, 0); ctl.add("base", {}, __program.str()); ctl.ground({{"base", {}}}, nullptr); - ctl.solve([&atomDecision, this, &result, moduleId](Gringo::Model const &model) { + ctl.solve([&predicateResolution, this, &dictResolution, &module](Gringo::Model const &model) { for (Gringo::Symbol atom : model.atoms(clingo_show_type_atoms)) { std::cout << atom << std::endl; + if (std::strcmp(atom.name().c_str(), predicateResolution.c_str())!=0) continue; - if (std::strcmp(atom.name().c_str(), atomDecision.c_str())==0){ - auto rowDecision = TranscendLayer::parse(atom); - - unsigned int moduleIdActual = std::get<0>(rowDecision); - if (moduleIdActual == moduleId){ - Gringo::Symbol moduleDecided = std::get<1>(rowDecision); - switch (moduleDecided.type()) { - case Gringo::SymbolType::Str: - result.push_back(moduleDecided.string().c_str()); - break; + if (atom.arity() == 2){ + auto resolution = TranscendLayer::parse(atom); + dictResolution.emplace(get<0>(resolution), get<1>(resolution)); + continue; + } - case Gringo::SymbolType::Num: - result.push_back(__registry->getModuleNameByHash(moduleDecided.num())); - break; + if (atom.arity() == 3){ + auto resolution = TranscendLayer::parse(atom); + if(get<2>(resolution) != module.__path) continue; - default: assert(false && "Inappropriate symbol type"); - } - } + dictResolution.emplace(get<0>(resolution), get<1>(resolution)); + continue; } + assert(false && "Wrong resolution format"); } return true; }, {}); - return result; -} - -const std::string& -ModulesRegistry::getModuleNameByHash(unsigned int hash){ - auto result = __registry.right.find(hash); - assert(result != __registry.right.end()); - - return result->second; -} - -unsigned int -ModulesRegistry::getModuleHash(const std::string& moduleName){ - auto result = __registry.left.insert(Hash::left_value_type(moduleName, __registry.size())); + std::list result; + for(const Expression& request: module.__requests){ + assert(dictResolution.count(request) && "Can't find requested module"); + result.push_back(dictResolution.at(request)); + } - return result.first->second; + return result; } }} //namespace xreate::modules diff --git a/cpp/src/modules.h b/cpp/src/modules.h index 6800cd2..3be3aaa 100644 --- a/cpp/src/modules.h +++ b/cpp/src/modules.h @@ -1,90 +1,76 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * File: modules.h * Author: pgess * * Created on July 22, 2017, 5:11 PM */ #ifndef MODULES_H #define MODULES_H #include "ast.h" #include #ifndef FRIENDS_MODULES_TESTS #define FRIENDS_MODULES_TESTS #endif namespace xreate { namespace modules{ -/**\brief Cache of already processed modules */ -class ModulesRegistry{ -public: - const std::string& getModuleNameByHash(unsigned int hash); - unsigned int getModuleHash(const std::string& moduleName); - -private: - typedef boost::bimap Hash; - Hash __registry; -}; - class ModulesSolver; /**\brief Holds information related to an individual module * \sa XreateManagerDecoratorModules, ModulesSolver, ModulesRegistry */ class ModuleRecord { FRIENDS_MODULES_TESTS friend class ModulesSolver; public: - void addModuleQuery(const Expression& query); + void addRequest(const Expression& request); void addControllerPath(const std::string& path); void addDiscoveryPath(const std::string& path); void addProperty(const Expression& prop); private: - std::list __queries; + std::list __requests; std::list __controllers; - std::list __discoveries; + std::list __discoveryPaths; std::list __properties; public: std::string __path; }; /** \brief Resolves module's requrements * \sa XreateManagerDecoratorModules, ModuleRecord */ class ModulesSolver{ FRIENDS_MODULES_TESTS public: - ModulesSolver(ModulesRegistry *registry): __registry(registry) {} + ModulesSolver(){} /** \brief Loads content of *controllers* into logic program for resolution */ void loadControllers(const ModuleRecord& module); /** \brief Discovers specified path for existing modules and stores found modules' properties */ void discoverModules(const ModuleRecord& moduleClient); void extractProperties(const ModuleRecord& module); void extractRequirements(const ModuleRecord& module); void add(const std::string& base); void init(const std::string& programBase, const ModuleRecord& module); std::list run(const ModuleRecord& module); -private: - ModulesRegistry* __registry; - public: std::ostringstream __program; }; }} //end namespace xreate::modules #endif /* MODULES_H */ diff --git a/cpp/src/pass/compilepass.cpp b/cpp/src/pass/compilepass.cpp index d747d1b..a101e3b 100644 --- a/cpp/src/pass/compilepass.cpp +++ b/cpp/src/pass/compilepass.cpp @@ -1,750 +1,771 @@ /* 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{ std::string BasicFunctionUnit::prepareName() { AST* ast = IFunctionUnit::pass->man->root; string name = ast->getFunctionSpecializations(IFunctionUnit::function->__name).size() > 1 ? IFunctionUnit::function->__name + std::to_string(IFunctionUnit::function.id()) : IFunctionUnit::function->__name; return name; } std::vector BasicFunctionUnit::prepareSignature() { LLVMLayer* llvm = IFunctionUnit::pass->man->llvm; AST* ast = IFunctionUnit::pass->man->root; CodeScope* entry = IFunctionUnit::function->__entry; std::vector signature; std::transform(entry->__bindings.begin(), entry->__bindings.end(), std::inserter(signature, signature.end()), [llvm, ast, entry](const std::string & arg)->llvm::Type* { assert(entry->__identifiers.count(arg)); ScopedSymbol argid{entry->__identifiers.at(arg), versions::VERSION_NONE}; return llvm->toLLVMType(ast->expandType(entry->__declarations.at(argid).type)); }); return signature; } llvm::Type* BasicFunctionUnit::prepareResult() { LLVMLayer* llvm = IFunctionUnit::pass->man->llvm; AST* ast = IFunctionUnit::pass->man->root; CodeScope* entry = IFunctionUnit::function->__entry; return llvm->toLLVMType(ast->expandType(entry->__declarations.at(ScopedSymbol::RetSymbol).type)); } llvm::Function::arg_iterator BasicFunctionUnit::prepareBindings() { CodeScope* entry = IFunctionUnit::function->__entry; ICodeScopeUnit* entryCompilation = IFunctionUnit::getScopeUnit(entry); llvm::Function::arg_iterator fargsI = IFunctionUnit::raw->arg_begin(); for (std::string &arg : entry->__bindings) { ScopedSymbol argid{entry->__identifiers[arg], versions::VERSION_NONE}; entryCompilation->bindArg(&*fargsI, argid); fargsI->setName(arg); ++fargsI; } return fargsI; } //DEBT compiler rigidly depends on exact definition of DefaultFunctionUnit typedef latex::LatexBruteFunctionDecorator< compilation::BasicFunctionUnit> BruteFunctionDefault; ICodeScopeUnit::ICodeScopeUnit(const CodeScope * const codeScope, IFunctionUnit* f, CompilePass* compilePass) : pass(compilePass), function(f), scope(codeScope), currentBlockRaw(nullptr) { } llvm::Value* BruteFnInvocation::operator()(std::vector&& args, const std::string& hintDecl) { llvm::Function* calleeInfo = dyn_cast(__callee); if (calleeInfo) { auto argsFormal = calleeInfo->args(); size_t sizeArgsF = std::distance(argsFormal.begin(), argsFormal.end()); assert(args.size() >= sizeArgsF); assert(calleeInfo->isVarArg() || args.size() == sizeArgsF); auto argFormal = argsFormal.begin(); for(size_t argId = 0; argId < args.size(); ++argId){ if(argFormal != argsFormal.end()){ args[argId] = typeinference::doAutomaticTypeConversion( args.at(argId), argFormal->getType(), llvm->builder); ++argFormal; } } } //Do not name function call that returns Void. std::string nameStatement = hintDecl; if (calleeInfo->getReturnType()->isVoidTy()) { nameStatement.clear(); } return llvm->builder.CreateCall(__calleeTy, __callee, args, nameStatement); } //DESABLEDFEATURE implement inlining class CallStatementInline : public IFnInvocation{ public: CallStatementInline(IFunctionUnit* caller, IFunctionUnit* callee, LLVMLayer* l) : __caller(caller), __callee(callee), llvm(l) { } llvm::Value* operator()(std::vector&& args, const std::string& hintDecl) { //TOTEST inlining // CodeScopeUnit* entryCompilation = outer->getScopeUnit(function->__entry); // for(int i=0, size = args.size(); ibindArg(args.at(i), string(entryCompilation->scope->__bindings.at(i))); // } // // // return entryCompilation->compile(); return nullptr; } private: IFunctionUnit* __caller; IFunctionUnit* __callee; LLVMLayer* llvm; bool isInline() { // Symbol ret = Symbol{0, function->__entry}; // bool flagOnTheFly = SymbolAttachments::get(ret, false); //TODO consider inlining return false; } } ; BasicCodeScopeUnit::BasicCodeScopeUnit(const CodeScope * const codeScope, IFunctionUnit* f, CompilePass* compilePass) : ICodeScopeUnit(codeScope, f, compilePass) { } llvm::Value* BasicCodeScopeUnit::processSymbol(const Symbol& s, std::string hintRetVar) { Expression declaration = CodeScope::getDefinition(s); const CodeScope* scopeExternal = s.scope; ICodeScopeUnit* scopeBruteExternal = ICodeScopeUnit::function->getScopeUnit(scopeExternal); assert(scopeBruteExternal->currentBlockRaw); llvm::Value* resultRaw; llvm::BasicBlock* blockOwn = pass->man->llvm->builder.GetInsertBlock(); if (scopeBruteExternal->currentBlockRaw == blockOwn) { resultRaw = scopeBruteExternal->process(declaration, hintRetVar); scopeBruteExternal->currentBlockRaw = currentBlockRaw = pass->man->llvm->builder.GetInsertBlock(); } else { pass->man->llvm->builder.SetInsertPoint(scopeBruteExternal->currentBlockRaw); resultRaw = scopeBruteExternal->processSymbol(s, hintRetVar); pass->man->llvm->builder.SetInsertPoint(blockOwn); } return resultRaw; } IFnInvocation* BasicCodeScopeUnit::findFunction(const Expression& opCall) { const std::string& calleeName = opCall.getValueString(); LLVMLayer* llvm = pass->man->llvm; const std::list& specializations = pass->man->root->getFunctionSpecializations(calleeName); //if no specializations registered - check external function if (specializations.size() == 0) { llvm::Function* external = llvm->layerExtern->lookupFunction(calleeName); llvm::outs() << "Debug/External function: " << calleeName; external->getType()->print(llvm::outs(), true); llvm::outs() << "\n"; return new BruteFnInvocation(external, llvm); } //There should be only one specialization without any valid guards at this point return new BruteFnInvocation(pass->getFunctionUnit( pass->man->root->findFunction(calleeName))->compile(), llvm); } //DISABLEDFEATURE transformations // if (pass->transformations->isAcceptable(expr)){ // return pass->transformations->transform(expr, result, ctx); // } llvm::Value* BasicCodeScopeUnit::process(const Expression& expr, const std::string& hintVarDecl) { #define DEFAULT(x) (hintVarDecl.empty()? x: hintVarDecl) llvm::Value *left; llvm::Value *right; LLVMLayer& l = *pass->man->llvm; xreate::compilation::AdvancedInstructions instructions = xreate::compilation::AdvancedInstructions({this, function, pass}); switch (expr.op) { case Operator::SUB: case Operator::MUL: case Operator::DIV: case Operator::EQU: case Operator::LSS: case Operator::GTR: case Operator::NE: case Operator::LSE: case Operator::GTE: assert(expr.__state == Expression::COMPOUND); assert(expr.operands.size() == 2); left = process(expr.operands[0]); right = process(expr.operands[1]); break; default:; } switch (expr.op) { case Operator::ADD: { left = process(expr.operands[0]); Context context{this, function, pass}; llvm::Value* resultSU = StructUpdate::add(expr.operands[0], left, expr.operands[1], context, DEFAULT("tmp_add")); if (resultSU) return resultSU; right = process(expr.operands[1]); llvm::Value* resultAddPA = pointerarithmetic::PointerArithmetic::add(left, right, context, DEFAULT("tmp_add")); if (resultAddPA) { return resultAddPA; } return l.builder.CreateAdd(left, right, DEFAULT("tmp_add")); break; } case Operator::SUB: return l.builder.CreateSub(left, right, DEFAULT("tmp_sub")); break; case Operator::MUL: return l.builder.CreateMul(left, right, DEFAULT("tmp_mul")); break; case Operator::DIV: 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")); const ExpandedType& leftT = pass->man->root->getType(expr.operands[0]); const ExpandedType& rightT = pass->man->root->getType(expr.operands[0]); if(leftT->__operator == TypeOperator::VARIANT && rightT->__operator == TypeOperator::VARIANT){ llvm::Type* selectorT = llvm::cast(left->getType())->getElementType(0); llvm::Value* leftUnwapped = typeinference::doAutomaticTypeConversion(left, selectorT, l.builder); llvm::Value* rightUnwapped = typeinference::doAutomaticTypeConversion(right, selectorT, l.builder); return l.builder.CreateICmpEQ(leftUnwapped, rightUnwapped, DEFAULT("tmp_equ")); } break; } case Operator::NE: return l.builder.CreateICmpNE(left, right, DEFAULT("tmp_ne")); break; case Operator::LSS: return l.builder.CreateICmpSLT(left, right, DEFAULT("tmp_lss")); break; case Operator::LSE: return l.builder.CreateICmpSLE(left, right, DEFAULT("tmp_lse")); break; case Operator::GTR: return l.builder.CreateICmpSGT(left, right, DEFAULT("tmp_gtr")); break; case Operator::GTE: return l.builder.CreateICmpSGE(left, right, DEFAULT("tmp_gte")); break; case Operator::NEG: left = process(expr.operands[0]); return l.builder.CreateNeg(left, DEFAULT("tmp_neg")); break; case Operator::CALL: { assert(expr.__state == Expression::COMPOUND); shared_ptr callee(findFunction(expr)); const std::string& nameCallee = expr.getValueString(); //prepare arguments std::vector args; args.reserve(expr.operands.size()); std::transform(expr.operands.begin(), expr.operands.end(), std::inserter(args, args.end()), [this](const Expression & operand) { return process(operand); } ); return (*callee)(move(args), DEFAULT("res_" + nameCallee)); } case Operator::IF: { return instructions.compileIf(expr, DEFAULT("tmp_if")); } case Operator::SWITCH: { return instructions.compileSwitch(expr, DEFAULT("tmp_switch")); } case Operator::LOGIC_AND: { assert(expr.operands.size() == 1); return process(expr.operands[0]); } case Operator::LIST: { - return instructions.compileListAsSolidArray(expr, DEFAULT("tmp_list")); - }; + ExpandedType exprT = l.ast->getType(expr); + bool flagIsArray; + + do { + if (exprT->__operator == TypeOperator::CUSTOM){ + if (l.layerExtern->isArrayType(exprT->__valueCustom)){ + flagIsArray = true; + break; + } - case Operator::LIST_RANGE: - { - assert(false); //no compilation phase for a range list - // return InstructionList(this).compileConstantArray(expr, l, hintRetVar); - }; + if (l.layerExtern->isRecordType(exprT->__valueCustom)){ + flagIsArray = false; + break; + } - case Operator::LIST_NAMED: - { - typedef Expanded ExpandedType; + assert(false && "Inapproriate external type"); + } - ExpandedType tyStructLiteral = l.ast->getType(expr); + if (exprT->__operator != TypeOperator::LIST_ARRAY && exprT->__operator != TypeOperator::LIST_RECORD){ + assert(false && "Inapproriate type"); + } - const std::vector fieldsFormal = (tyStructLiteral.get().__operator == TypeOperator::CUSTOM) ? - l.layerExtern->getStructFields(l.layerExtern->lookupType(tyStructLiteral.get().__valueCustom)) - : tyStructLiteral.get().fields; + flagIsArray = exprT->__operator == TypeOperator::LIST_ARRAY; + + } while(false); + + if(flagIsArray){ + return instructions.compileListAsSolidArray(expr, DEFAULT("tmp_list")); + } + + const std::vector fieldsFormal = (exprT.get().__operator == TypeOperator::CUSTOM) ? + l.layerExtern->getStructFields(l.layerExtern->lookupType(exprT.get().__valueCustom)) + : exprT.get().fields; std::map indexFields; for (size_t i = 0, size = fieldsFormal.size(); i < size; ++i) { indexFields.emplace(fieldsFormal[i], i); } - llvm::StructType* tyLiteralRaw = llvm::cast(l.toLLVMType(tyStructLiteral)); + llvm::StructType* tyLiteralRaw = llvm::cast(l.toLLVMType(exprT)); llvm::Value* record = llvm::UndefValue::get(tyLiteralRaw); for (size_t i = 0; i < expr.operands.size(); ++i) { const Expression& operand = expr.operands.at(i); unsigned int fieldId = indexFields.at(expr.bindings.at(i)); llvm::Value* result = process(operand); assert(result); record = l.builder.CreateInsertValue(record, result, llvm::ArrayRef({fieldId})); } return record; }; + case Operator::LIST_RANGE: + { + assert(false); //no compilation phase for a range list + // return InstructionList(this).compileConstantArray(expr, l, hintRetVar); + }; + case Operator::MAP: { assert(expr.blocks.size()); return instructions.compileMapSolidOutput(expr, DEFAULT("map")); }; case Operator::FOLD: { return instructions.compileFold(expr, DEFAULT("fold")); }; - case Operator::FOLD_INF: + case Operator::INF: { return instructions.compileFoldInf(expr, DEFAULT("fold")); }; case Operator::INDEX: { //TASK allow multiindex compilation assert(expr.operands.size() == 2); assert(expr.operands[0].__state == Expression::IDENT); const std::string& hintIdent = expr.operands[0].getValueString(); Symbol s = Attachments::get(expr.operands[0]); const ExpandedType& t2 = pass->man->root->getType(expr.operands[0]); llvm::Value* aggr = processSymbol(s, hintIdent); switch (t2.get().__operator) { - case TypeOperator::LIST_NAMED: case TypeOperator::CUSTOM: + case TypeOperator::LIST_RECORD: case TypeOperator::CUSTOM: { std::string idxField; const Expression& idx = expr.operands.at(1); switch (idx.__state) { //named struct field case Expression::STRING: idxField = idx.getValueString(); break; //anonymous struct field case Expression::NUMBER: idxField = to_string((int) idx.getValueDouble()); break; default: assert(false && "Wrong index for a struct"); } return instructions.compileStructIndex(aggr, t2, idxField); }; - case TypeOperator::LIST: + case TypeOperator::LIST_ARRAY: { std::vector indexes; std::transform(++expr.operands.begin(), expr.operands.end(), std::inserter(indexes, indexes.end()), [this] (const Expression & op) { return process(op); } ); return instructions.compileArrayIndex(aggr, indexes, DEFAULT(string("el_") + hintIdent)); }; default: assert(false); } }; case Operator::CALL_INTRINSIC: { const std::string op = expr.getValueString(); if (op == "copy") { llvm::Value* result = process(expr.getOperands().at(0)); auto decoratorVersions = Decorators::getInterface(this); llvm::Value* storage = decoratorVersions->processIntrinsicInit(result->getType()); decoratorVersions->processIntrinsicCopy(result, storage); return l.builder.CreateLoad(storage, hintVarDecl); } assert(false && "undefined intrinsic"); } case Operator::QUERY: case Operator::QUERY_LATE: { assert(false && "Should be processed by interpretation"); } case Operator::VARIANT: { const ExpandedType& typVariant = pass->man->root->getType(expr); llvm::Type* typVariantRaw = l.toLLVMType(typVariant); llvm::Type* typIdRaw = llvm::cast(typVariantRaw)->getElementType(0); uint64_t id = expr.getValueDouble(); llvm::Value* variantRaw = llvm::UndefValue::get(typVariantRaw); variantRaw = l.builder.CreateInsertValue(variantRaw, llvm::ConstantInt::get(typIdRaw, id), llvm::ArrayRef({0})); const bool flagDoReference = expr.operands.size(); if (flagDoReference) { const ExpandedType& subtyp = ExpandedType(typVariant->__operands.at(id)); llvm::Type* subtypRaw = l.toLLVMType(subtyp); Attachments::put(expr.operands.at(0), subtyp); llvm::Value* subtypValue = process(expr.operands.at(0)); llvm::Type* typStorageRaw = llvm::cast(typVariantRaw)->getElementType(1); llvm::Value* addrAsStorage = l.builder.CreateAlloca(typStorageRaw); llvm::Value* addrAsSubtyp = l.builder.CreateBitOrPointerCast(addrAsStorage, subtypRaw->getPointerTo()); l.builder.CreateStore(subtypValue, addrAsSubtyp); llvm::Value* storageRaw = l.builder.CreateLoad(typStorageRaw, addrAsStorage); variantRaw = l.builder.CreateInsertValue(variantRaw, storageRaw, llvm::ArrayRef({1})); } return variantRaw; } case Operator::SWITCH_VARIANT: { return instructions.compileSwitchVariant(expr, DEFAULT("tmpswitch")); } case Operator::SWITCH_LATE: { assert(false && "Instruction's compilation should've been redirected to interpretation"); return nullptr; } case Operator::SEQUENCE: { return instructions.compileSequence(expr); } case Operator::UNDEF: { llvm::Type* typExprUndef = l.toLLVMType(typeinference::getType(expr, *pass->man->root)); return llvm::UndefValue::get(typExprUndef); } case Operator::INVALID: assert(expr.__state != Expression::COMPOUND); switch (expr.__state) { case Expression::IDENT: { Symbol s = Attachments::get(expr); return processSymbol(s, expr.getValueString()); } case Expression::NUMBER: { llvm::Type* typConst = l.toLLVMType(typeinference::getType(expr, *pass->man->root)); int literal = expr.getValueDouble(); return llvm::ConstantInt::get(typConst, literal); } case Expression::STRING: { return instructions.compileConstantStringAsPChar(expr.getValueString(), DEFAULT("tmp_str")); }; default: { break; } }; break; default: break; } assert(false && "Can't compile expression"); return 0; } llvm::Value* BasicCodeScopeUnit::compile(const std::string& hintBlockDecl) { LLVMLayer* llvm = pass->man->llvm; if (!hintBlockDecl.empty()) { llvm::BasicBlock *block = llvm::BasicBlock::Create(llvm->llvmContext, hintBlockDecl, function->raw); pass->man->llvm->builder.SetInsertPoint(block); } currentBlockRaw = pass->man->llvm->builder.GetInsertBlock(); Symbol symbScope = Symbol{ScopedSymbol::RetSymbol, scope}; return processSymbol(symbScope); } ICodeScopeUnit::~ICodeScopeUnit() { } IFunctionUnit::~IFunctionUnit() { } llvm::Function* IFunctionUnit::compile() { if (raw != nullptr) return raw; LLVMLayer* llvm = pass->man->llvm; llvm::IRBuilder<>& builder = llvm->builder; string&& functionName = prepareName(); std::vector&& types = prepareSignature(); llvm::Type* expectedResultType = prepareResult(); llvm::FunctionType *ft = llvm::FunctionType::get(expectedResultType, types, false); raw = llvm::cast(llvm->module->getOrInsertFunction(functionName, ft)); prepareBindings(); const std::string&blockName = "entry"; llvm::BasicBlock* blockCurrent = builder.GetInsertBlock(); llvm::Value* result = getScopeUnit(function->__entry)->compile(blockName); assert(result); //SECTIONTAG types/convert function ret value builder.CreateRet(typeinference::doAutomaticTypeConversion(result, expectedResultType, llvm->builder)); if (blockCurrent) { builder.SetInsertPoint(blockCurrent); } llvm->moveToGarbage(ft); return raw; } ICodeScopeUnit* IFunctionUnit::getScopeUnit(const CodeScope * const scope) { if (__scopes.count(scope)) { auto result = __scopes.at(scope).lock(); if (result) { return result.get(); } } std::shared_ptr unit(pass->buildCodeScopeUnit(scope, this)); if (scope->__parent != nullptr) { auto parentUnit = Decorators::getInterface(getScopeUnit(scope->__parent)); parentUnit->registerChildScope(unit); } else { __orphanedScopes.push_back(unit); } if (!__scopes.emplace(scope, unit).second) { __scopes[scope] = unit; } return unit.get(); } ICodeScopeUnit* IFunctionUnit::getScopeUnit(ManagedScpPtr scope) { return getScopeUnit(&*scope); } ICodeScopeUnit* IFunctionUnit::getEntry() { return getScopeUnit(function->getEntryScope()); } template<> compilation::IFunctionUnit* CompilePassCustomDecorators ::buildFunctionUnit(const ManagedFnPtr& function) { return new BruteFunctionDefault(function, this); } template<> compilation::ICodeScopeUnit* CompilePassCustomDecorators ::buildCodeScopeUnit(const CodeScope * const scope, IFunctionUnit* function) { return new DefaultCodeScopeUnit(scope, function, this); } } // end of compilation compilation::IFunctionUnit* CompilePass::getFunctionUnit(const ManagedFnPtr& function) { unsigned int id = function.id(); if (!functions.count(id)) { compilation::IFunctionUnit* unit = buildFunctionUnit(function); functions.emplace(id, unit); return unit; } return functions.at(id); } void CompilePass::run() { //Initialization: managerTransformations = new xreate::compilation::TransformationsManager(); targetInterpretation = new interpretation::TargetInterpretation(this->man->root, this); //Determine entry function: StaticModel model = man->transcend->query(Config::get("function-entry")); assert(model.size() && "Error: No entry function found"); assert(model.size() == 1 && "Error: Ambiguous entry function"); string nameMain = std::get<0>(TranscendLayer::parse(model.begin()->second)); compilation::IFunctionUnit* unitMain = getFunctionUnit(man->root->findFunction(nameMain)); //Compilation itself: entry = unitMain->compile(); } llvm::Function* CompilePass::getEntryFunction() { assert(entry); return entry; } void CompilePass::prepareQueries(TranscendLayer* transcend) { transcend->registerQuery(new containers::Query(), QueryId::ContainersQuery); transcend->registerQuery(new polymorph::PolymorphQuery(), QueryId::PolymorphQuery); transcend->registerQuery(new latex::LatexQuery(), QueryId::LatexQuery); } } //end of namespace xreate /** * \class xreate::CompilePass * \brief 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 2b440f8..9143ecb 100644 --- a/cpp/src/pass/interpretationpass.cpp +++ b/cpp/src/pass/interpretationpass.cpp @@ -1,555 +1,554 @@ /* 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"); + auto i=tags.find("i12n"); 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"){ + if(cmd=="on"){ return INTR_ONLY; - } else if(cmd=="suppress"){ + } else if(cmd=="off"){ 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 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 opNo=0; opNo__identifiers.at(argName), versions::VERSION_NONE}, exprBody }; getSymbolCache().setCachedValue(argS, INTR_ONLY); Parent::process(expression.blocks.front(), context); resolution = CMPL_ONLY; 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})){ 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})){ opNo=FOLD_INTERPRET_INPUT; flagInput=ANY; } resolution=unify(flagInput, flagAccumInit, flagBody); break; } case Operator::INDEX: { 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})){ opNo=SWITCH_INTERPRET_CONDITION; flagHeaders=ANY; } //determine body resolutions resolution=flagHeaders; for(size_t size=expression.operands.size(), i=1; i({resolution})){ 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 &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 &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 || 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 *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/tests/ast.cpp b/cpp/tests/ast.cpp index 17bee50..65f5c69 100644 --- a/cpp/tests/ast.cpp +++ b/cpp/tests/ast.cpp @@ -1,90 +1,170 @@ /* Any copyright is dedicated to the Public Domain. * http://creativecommons.org/publicdomain/zero/1.0/ * * ast.cpp * * Created on: Jun 11, 2015 * Author: pgess */ #include "gtest/gtest.h" #include "xreatemanager.h" #include "main/Parser.h" using namespace std; using namespace xreate; using namespace xreate::grammar::main; TEST(AST, Containers1){ FILE* input = fopen("scripts/containers/Containers_Implementation_LinkedList1.xreate","r"); Scanner scanner(input); Parser parser(&scanner); parser.Parse(); assert(!parser.errors->count && "Parser errors"); fclose(input); } TEST(AST, InterfacesDataCFA) { XreateManager* man = XreateManager::prepare ("interface(cfa){\n" " operator map :: annotation1.\n" "}"); auto answer = man->root->__interfacesData.equal_range(CFA); EXPECT_EQ(1, std::distance(answer.first, answer.second)); Expression&& scheme = move(answer.first->second); EXPECT_EQ(Operator::MAP, scheme.op); EXPECT_EQ("annotation1", scheme.getOperands().at(0).getValueString()); } TEST(AST, syntax_recognizeIdentifiers){ XreateManager* man = XreateManager::prepare(R"Code( test= function(a:: num):: num; entry { a = b:: int. b = 8:: int. a } )Code"); } TEST(AST, syntax_operatorIndex){ XreateManager* man = XreateManager::prepare(R"Code( test= function(a:: num):: num; entry { b = a[1]. b } )Code"); } TEST(AST, Variants_switch){ XreateManager* man = XreateManager::prepare(R"Code( Color = type variant{Blue, White, Green}. main = function:: int { x = White()::Color. switch variant(x)::int case (Green) {0} case (White) {1} case (Blue){2} } )Code"); Expression e= man->root->findFunction("main")->getEntryScope()->getBody(); ASSERT_EQ(4, e.getOperands().size()); ASSERT_EQ(3, e.blocks.size()); } TEST(AST, DISABLED_InterfacesDataDFA){ } TEST(AST, DISABLED_InterfacesDataExtern){ } -//TODO xreate.atg: replace all Type<> as ExprAnnotations<> +TEST(AST, Doc_LiteralsAndExpressions){ + XreateManager* man = XreateManager::prepare( + R"Code( + + Record1 = type {year:: int, month:: string}. + isOdd = function(x :: int) :: bool {true} + + test = function:: bool; entry { + x1 = 5 :: int. + x2 = "Nimefurahi kukujua":: string. + x3 = {year = 1934, month = "april"}:: Record1. + x4 = {16, 8, 3} :: [int]. + x5 = 8>=3:: bool. + x6 = "Blue" <> "Green" :: bool. + colors = {"Green", "Blue"} :: [string]. + color = colors[0] :: string. + date = {year = 1934, month = "april"}:: Record1. year = date["year"] :: int. + a = 0::int. b = 0 :: int. + x7 = a - b:: int. + result = isOdd(6) :: bool. + + true + } + + )Code"); + + ASSERT_TRUE(true); +} + +TEST(AST, Doc_CodeBlocks){ + XreateManager* man = XreateManager::prepare( + R"Code( + test = function:: int; entry { + a = 10:: int. + b = 2:: int. + + a + b:: int + } + + )Code"); + + ASSERT_TRUE(true); +} + +TEST(AST, Doc_Functions){ + XreateManager* man = XreateManager::prepare( + R"Code( + + sum = function(x:: int, y:: int):: int; entry; status(needs_review) + { + x+y + } + + )Code"); + + ASSERT_TRUE(true); +} + +TEST(AST, Doc_BranchStatements){ + XreateManager* man = XreateManager::prepare( + R"Code( + + test = function:: int; entry + { + question = "Favorite color?":: string. + answer = if (question == "Favorite color?"):: string + {"Yellow"} else {"Don't know"}. + + monthNum = 2 :: int. + monthName = switch(monthNum) :: string + case (1) {"Jan"} + case (2) {"Feb"} + case default {"Strange.. Don't know this month"}. + + {answer, monthName} + } + + )Code"); + + ASSERT_TRUE(true); +} diff --git a/cpp/tests/compilation.cpp b/cpp/tests/compilation.cpp index 11cef99..21c1d12 100644 --- a/cpp/tests/compilation.cpp +++ b/cpp/tests/compilation.cpp @@ -1,228 +1,228 @@ /* Any copyright is dedicated to the Public Domain. * http://creativecommons.org/publicdomain/zero/1.0/ * * compilation.cpp * * Created on: - * Author: pgess */ #include "xreatemanager.h" #include "gtest/gtest.h" using namespace xreate; //DEBT implement no pkgconfig ways to link libs //TOTEST FunctionUnit::compileInline TEST(Compilation, functionEntry1){ std::unique_ptr program(XreateManager::prepare( "func1 = function(a:: int):: int {a+8} \ func2 = function::int; entry {12 + func1(4)} \ ")); void* entryPtr = program->run(); int (*entry)() = (int (*)())(intptr_t)entryPtr; int answer = entry(); ASSERT_EQ(24, answer); } TEST(Compilation, full_IFStatementWithVariantType){ XreateManager* man = XreateManager::prepare( "Color = type variant {RED, BLUE, GREEN}.\n" "\n" " main = function(x::int):: bool; entry {\n" " color = if (x == 0 )::Color {RED()} else {BLUE()}.\n" " if (color == BLUE())::bool {true} else {false}\n" " }" ); bool (*main)(int) = (bool (*)(int)) man->run(); ASSERT_FALSE(main(0)); ASSERT_TRUE(main(1)); } TEST(Compilation, full_Variant1){ XreateManager* man = XreateManager::prepare(R"Code( OneArgument = type{x::int}. TwoArguments = type{x::int, y::int}. Command= type variant{ Add::TwoArguments, Dec::OneArgument }. main = function::Command; entry { Dec({x=2})::Command } )Code"); void (*main)() = (void (*)()) man->run(); } TEST(Compilation, full_SwitchVariant1){ XreateManager* man = XreateManager::prepare(R"Code( OneArgument = type{x::int}. TwoArguments = type{x::int, y::int}. Command= type variant{ Add::TwoArguments, Dec::OneArgument }. main = function::int; entry { //command = Dec({x = 8}):: Command. command = Add({x= 3, y= 5}):: Command. switch variant(command)::int case(Add){command["x"] + command["y"]} case(Dec){command["x"]} } )Code"); int (*mainFn)() = (int (*)()) man->run(); int result = mainFn(); ASSERT_EQ(8, result); } TEST(Compilation, full_SwitchVariantNoArguments2){ XreateManager* man = XreateManager::prepare(R"Code( Command= type variant{Add, Dec}. main = function::int; entry { command = Dec():: Command. switch variant(command)::int case(Add){0} case(Dec){1} } )Code"); int (*mainFn)() = (int (*)()) man->run(); int result = mainFn(); ASSERT_EQ(1, result); } TEST(Compilation, full_SwitchVariantMixedArguments3){ XreateManager* man = XreateManager::prepare(R"Code( TwoArguments = type{x::int, y::int}. Command= type variant{ Add::TwoArguments, Dec }. main = function(arg::int):: int; entry { command = if (arg > 0)::Command {Dec()} else {Add({x=1,y=2})}. switch variant(command)::int case(Add){0} case(Dec){1} } )Code"); int (*mainFn)(int) = (int (*)(int)) man->run(); int result = mainFn(5); ASSERT_EQ(1, result); } TEST(Compilation, full_StructUpdate){ XreateManager* man = XreateManager::prepare( R"Code( Rec = type { a :: int, b:: int }. test= function:: int; entry { a = {a = 18, b = 20}:: Rec. b = a + {a = 11}:: Rec. b["a"] } )Code"); int (*main)() = (int (*)()) man->run(); int result = main(); ASSERT_EQ(11, result); } TEST(Compilation, AnonymousStruct_init_index){ std::string code = R"Code( main = function:: int; entry { x = {10, 15} :: {int, int}. x[1] } )Code"; std::unique_ptr man(XreateManager::prepare(move(code))); int (*main)() = (int (*)()) man->run(); EXPECT_EQ(15, main()); } TEST(Compilation, AnonymousStruct_init_update){ std::string code = R"Code( main = function:: int; entry { x = {10, 15} :: {int, int}. y = x + {6}:: {int, int}. y[0] } )Code"; std::unique_ptr man(XreateManager::prepare(move(code))); int (*main)() = (int (*)()) man->run(); EXPECT_EQ(6, main()); } TEST(Compilation, BugIncorrectScopes1){ std::string code = R"Code( init = function:: int {10} main = function(cmd:: int):: int; entry { x = init():: int. if(cmd > 0):: int { x + 1 } else { x } } )Code"; std::unique_ptr man(XreateManager::prepare(move(code))); int (*mainFn)(int) = (int (*)(int)) man->run(); EXPECT_EQ(11, mainFn(1)); } TEST(Compilation, Sequence1){ std::string code = R"Code( interface(extern-c){ libbsd = library:: pkgconfig("libbsd"). include { - libbsd = ["bsd/stdlib.h", "string.h"] + libbsd = {"bsd/stdlib.h", "string.h"} }. } start = function:: i32; entry { seq { nameNew = "TestingSequence":: string. setprogname(nameNew) } {strlen(getprogname())}::i32 } )Code"; std::unique_ptr man(XreateManager::prepare(move(code))); int (*startFn)() = (int (*)()) man->run(); int nameNewLen = startFn(); ASSERT_EQ(15, nameNewLen); } diff --git a/cpp/tests/containers.cpp b/cpp/tests/containers.cpp index a68b8cd..8d0ba20 100644 --- a/cpp/tests/containers.cpp +++ b/cpp/tests/containers.cpp @@ -1,103 +1,103 @@ /* Any copyright is dedicated to the Public Domain. * http://creativecommons.org/publicdomain/zero/1.0/ * * containers.cpp * * Created on: Jun 9, 2015 * Author: pgess */ #include "xreatemanager.h" #include "query/containers.h" #include "main/Parser.h" #include "gtest/gtest.h" using namespace std; using namespace xreate::grammar::main; using namespace xreate::containers; using namespace xreate; TEST(Containers, ListAsArray){ XreateManager* man = XreateManager::prepare( R"Code( main = function(x:: int):: int;entry { - a = [1, 2, 3]:: [int]. + a = {1, 2, 3}:: [int]. a[x] } )Code" ); void* mainPtr = man->run(); int (*main)(int) = (int (*)(int))mainPtr; ASSERT_EQ(2, main(1)); delete man; } TEST(Containers, ListAsArray2){ XreateManager* man = XreateManager::prepare( R"Code( // CONTAINERS import raw("scripts/dfa/ast-attachments.lp"). import raw("scripts/containers/containers.lp"). main = function:: int;entry { - a= [1, 2, 3]:: [int]. + a= {1, 2, 3}:: [int]. b= loop map(a->el:: int):: [int]{ 2 * el }. sum = loop fold(b->el:: int, 0->acc):: int { acc + el }. sum } )Code"); void* mainPtr = man->run(); int (*main)() = (int (*)())mainPtr; ASSERT_EQ(12, main()); delete man; } TEST(Containers, ContanierLinkedList1){ 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 Symbol symb_chilrenRaw{body->getSymbol("childrenRaw"), body}; containers::ImplementationLinkedList iLL(symb_chilrenRaw); ASSERT_EQ(true, static_cast(iLL)); ASSERT_EQ("next", iLL.fieldPointer); Implementation impl = Implementation::create(symb_chilrenRaw); ASSERT_NO_FATAL_FAILURE(impl.extract()); ImplementationRec recOnthefly = impl.extract(); ASSERT_EQ(symb_chilrenRaw, recOnthefly.source); } TEST(Containers, Implementation_LinkedListFull){ FILE* input = fopen("scripts/containers/Containers_Implementation_LinkedList1.xreate","r"); assert(input != nullptr); std::unique_ptr program(XreateManager::prepare(input)); void* mainPtr = program->run(); int (*main)() = (int (*)())(intptr_t)mainPtr; int answer = main(); ASSERT_EQ(17, answer); fclose(input); } diff --git a/cpp/tests/effects-versions.cpp b/cpp/tests/effects-versions.cpp index 2f18544..8391384 100644 --- a/cpp/tests/effects-versions.cpp +++ b/cpp/tests/effects-versions.cpp @@ -1,279 +1,279 @@ /* Any copyright is dedicated to the Public Domain. * http://creativecommons.org/publicdomain/zero/1.0/ * * Created on: Dec 16, 2016 * Author: pgess */ #include "pass/versionspass.h" #include "xreatemanager.h" #include "gtest/gtest.h" using namespace xreate; using namespace xreate::versions; TEST(Effects, syntax_versions_1){ XreateManager* man = XreateManager::prepare(R"Code( test= function(a:: num):: num; entry { x= b[8]. b = 5:: num. x{1} = a:: num. x{1} + a } )Code"); } TEST(Effects, analysis_versions_1){ XreateManager* man = XreateManager::prepare( R"Code( test= function:: num; entry { x{0}= 3:: int. x{1} = x{0} + 1. x{1} } )Code"); VersionsPass* pass = new VersionsPass(man); pass->run(); VersionsGraph graph = pass->getResultGraph(); ASSERT_TRUE(graph.validate()); } TEST(Effects, analysis_versions_2){ XreateManager* man = XreateManager::prepare( R"Code( test= function(a:: num):: num; entry { x{0}= 3:: int. - b = [1, 2, x{0}]. + b = {1, 2, x{0}}. x{1} = b[2]. x{1} + a } )Code"); VersionsPass* pass = new VersionsPass(man); pass->run(); VersionsGraph graph = pass->getResultGraph(); ASSERT_TRUE(graph.validate()); } TEST(Effects, analysis_versions_2_1_fail){ XreateManager* man = XreateManager::prepare( R"Code( test= function(a:: num):: num; entry { x{0}= 5:: int. b = x{0}. x{1} = 2. b + x{1} } )Code"); VersionsPass* pass = new VersionsPass(man); pass->run(); VersionsGraph graph = pass->getResultGraph(); graph.__debug_print(std::cout); ASSERT_FALSE(graph.validate()); } TEST(Effects, analysis_versions_2_2){ XreateManager* man = XreateManager::prepare( R"Code( test= function(a:: num):: num; entry { x{0}= 5:: int. b = intrinsic copy(x{0}). x{1} = 2. b + x{1} } )Code"); VersionsPass* pass = new VersionsPass(man); pass->run(); VersionsGraph graph = pass->getResultGraph(); graph.__debug_print(std::cout); ASSERT_TRUE(graph.validate()); } TEST(Effects, analysis_versions_3){ XreateManager* man = XreateManager::prepare( R"Code( test= function:: num; entry { x{0}= 3:: int. a = x{0}:: int. b = a :: int. x{1} = b. x{1} } )Code"); VersionsPass* pass = new VersionsPass(man); pass->run(); VersionsGraph graph = pass->getResultGraph(); graph.__debug_print(std::cout); ASSERT_TRUE(graph.validate()); std::cout << "========================\n"; graph.__debug_print(std::cout); AttachmentsContainerDefault>* attachmentsDependency = graph.representAsAttachments(); CodeScope* scope = man->root->findFunction("test")->getEntryScope(); const std::list& dependenciesX1 = attachmentsDependency->get(Symbol{ScopedSymbol{1, 1}, scope}); ASSERT_EQ(3, dependenciesX1.size()); } TEST(Effects, compilation_versions_1){ details::tier1::XreateManager* man = details::tier1::XreateManager::prepare( R"Code( test= function:: num; entry { x{1} = b. b = a :: int. a = x{0}:: int. x{0}= 3:: int. x{1} } )Code"); man->analyse(); if (!man->isPassRegistered(PassId::VersionsPass)){ VersionsPass* pass = new VersionsPass(man); pass->run(); pass->finish(); } int (*body)() = (int (*)())man->run(); int answer = body(); ASSERT_EQ(3, answer); } TEST(Effects, compilation_versions_versionInit1){ details::tier1::XreateManager* man = details::tier1::XreateManager::prepare( R"Code( test= function:: num; entry { x{0} = 3. x{0} } )Code"); man->analyse(); if (!man->isPassRegistered(PassId::VersionsPass)){ VersionsPass* pass = new VersionsPass(man); pass->run(); pass->finish(); } int (*body)() = (int (*)())man->run(); int answer = body(); ASSERT_EQ(3, answer); } TEST(Effects, compilation_versions_versionNext1){ details::tier1::XreateManager* man = details::tier1::XreateManager::prepare( R"Code( test= function:: num; entry { x{0} = 5. x{1} = x{0} - 2. x{1} } )Code"); man->analyse(); if (!man->isPassRegistered(PassId::VersionsPass)){ VersionsPass* pass = new VersionsPass(man); pass->run(); pass->finish(); } int (*body)() = (int (*)())man->run(); int answer = body(); ASSERT_EQ(3, answer); } TEST(Effects, compilation_versions_IntrinsicCopy1){ details::tier1::XreateManager* man = details::tier1::XreateManager::prepare( R"Code( test= function:: num; entry { x{0} = 5. b = intrinsic copy (x{0}). x{1} = 2. b - x{1} } )Code"); man->analyse(); if (!man->isPassRegistered(PassId::VersionsPass)){ VersionsPass* pass = new VersionsPass(man); pass->run(); pass->finish(); } int (*body)() = (int (*)())man->run(); int answer = body(); ASSERT_EQ(3, answer); } TEST(Effects, compilation_versions_varexchange){ details::tier1::XreateManager* man = details::tier1::XreateManager::prepare( R"Code( test= function:: num; entry { a{0} = 3. b{0} = 5. tmp = intrinsic copy (a{0}). a{1} = b{0}. b{1} = tmp. b{1} } )Code"); man->analyse(); if (!man->isPassRegistered(PassId::VersionsPass)){ VersionsPass* pass = new VersionsPass(man); pass->run(); pass->finish(); } int (*body)() = (int (*)())man->run(); int answer = body(); ASSERT_EQ(3, answer); } /* TEST(Effects, analysis_versions_copy){ } TEST(Effects, syntax_references1){ } TEST(Effects, syntax_scope_versions1){ } TEST(Effects, DynamicVersions_analysis){ } */ diff --git a/cpp/tests/externc.cpp b/cpp/tests/externc.cpp index 3686be8..5e355a5 100644 --- a/cpp/tests/externc.cpp +++ b/cpp/tests/externc.cpp @@ -1,115 +1,115 @@ /* Any copyright is dedicated to the Public Domain. * http://creativecommons.org/publicdomain/zero/1.0/ * * externc.cpp * * Created on: - * Author: pgess */ #include "gtest/gtest.h" #include "xreatemanager.h" #include "main/Scanner.h" #include "main/Parser.h" #include #include using namespace std; using namespace xreate; TEST(InterfaceExternC, testAST) { std::string code = " \ interface(extern-c){ \ - xml2 = library:: pkgconfig(\"libxml-2.0\"). \ + xml2 = library:: pkgconfig(\"libxml-2.0\"). \ \ include { \ - xml2 = [\"libxml/tree.h\"] \ + xml2 = {\"libxml/tree.h\"} \ }. \ } \ "; xreate::grammar::main::Scanner scanner(reinterpret_cast (code.c_str()), code.size()); xreate::grammar::main::Parser parser(&scanner); parser.Parse(); ASSERT_EQ(1, parser.root->__externdata.size()); for (const ExternEntry& lib : parser.root->__externdata) { ASSERT_EQ("libxml-2.0", lib.package); ASSERT_EQ(1, lib.headers.size()); ASSERT_EQ("libxml/tree.h", lib.headers.at(0)); } } TEST(InterfaceExternC, testfetchPackageHeaders) { ExternEntry entry{"libxml-2.0", {}}; vector args = ExternLayer::fetchPackageFlags(entry); ASSERT_EQ(1, args.size()); ASSERT_EQ("-I/usr/include/libxml2", args.at(0)); } TEST(InterfaceExternC, testfetchPackageLibs) { ExternEntry entry{"libxml-2.0", {}}; vector args = ExternLayer::fetchPackageLibs(entry); ASSERT_EQ(1, args.size()); ASSERT_EQ("xml2", args.at(0)); } TEST(InterfaceExternC, testLoadLib) { std::string msgErr; if (!llvm::sys::DynamicLibrary::LoadLibraryPermanently("-lpcre -lxml2", &msgErr)) { cout << msgErr; ASSERT_EQ("", msgErr); } ASSERT_TRUE(true); } TEST(InterfaceExternC, testBSD1) { std::string code = " \n\ interface(extern-c){ \n\ libbsd = library:: pkgconfig(\"libbsd\"). \n\ \n\ include { \n\ - libbsd = [\"bsd/stdlib.h\"] \n\ + libbsd = {\"bsd/stdlib.h\"} \n\ }. \n\ } \n" "main= function:: int; entry{arc4random_uniform(24) }"; std::unique_ptr program(XreateManager::prepare(move(code))); void* entryPtr = program->run(); int (*entry)() = (int (*)())(intptr_t) entryPtr; int answer = 24; answer = entry(); cout << answer; ASSERT_LT(answer, 24); } TEST(InterfaceExternC, testStructFields1) { FILE* input = fopen("scripts/containers/Containers_Implementation_LinkedList1.xreate", "r"); assert(input != nullptr); xreate::grammar::main::Scanner scanner(input); xreate::grammar::main::Parser parser(&scanner); parser.Parse(); AST* ast = parser.root->finalize(); CodeScope* body = ast->findFunction("test")->getEntryScope(); const ExpandedType& t2Tree = ast->getType(body->getDefinition(body->getSymbol("tree"))); LLVMLayer llvm(ast); TypeUtils utils(&llvm); std::vectorfields = utils.getStructFields(t2Tree); auto field = std::find(fields.begin(), fields.end(), "children"); ASSERT_TRUE(field != fields.end()); } diff --git a/cpp/tests/interpretation.cpp b/cpp/tests/interpretation.cpp index 516fc7f..a032b19 100644 --- a/cpp/tests/interpretation.cpp +++ b/cpp/tests/interpretation.cpp @@ -1,532 +1,568 @@ /* Any copyright is dedicated to the Public Domain. * http://creativecommons.org/publicdomain/zero/1.0/ * * interpretation.cpp * * Created on: - * Author: pgess */ #include "attachments.h" using namespace xreate; #include "xreatemanager.h" #include "compilation/targetinterpretation.h" #include "analysis/interpretation.h" #include "gtest/gtest.h" #include "boost/scoped_ptr.hpp" //#define FRIENDS_INTERPRETATION_TESTS \ // friend class ::Modules_AST2_Test; \ // friend class ::Modules_Discovery1_Test; \ // friend class ::Modules_Solve1_Test; #include "pass/interpretationpass.h" using namespace xreate::grammar::main; using namespace xreate::interpretation; TEST(Interpretation, Analysis_StatementIF_1){ XreateManager* man = XreateManager::prepare( R"Code( main = function::bool { x = "a":: string. - y = if (x=="b"):: bool; interpretation(force) { + y = if (x=="b"):: bool; i12n(on) { true } else { false }. y } )Code" ); InterpretationPass* pass = new InterpretationPass(man); pass->run(); CodeScope* scopeEntry = man->root->findFunction("main")->getEntryScope(); Symbol symbolY{scopeEntry->getSymbol("y"), scopeEntry}; InterpretationData& dataSymbolY = Attachments::get(symbolY); ASSERT_EQ(INTR_ONLY, dataSymbolY.resolution); } -TEST(Interpretation, Compilation_StatementIF_1){ +TEST(Interpretation, Doc_Compilation_StatementIF_1){ xreate::details::tier1::XreateManager* man = xreate::details::tier1::XreateManager::prepare( R"Code( - main = function::int; entry { - x = "a":: string. - - y = if (x=="b"):: string; interpretation(force) { - 1 - - } else { - 0 - }. + main= function:: int; entry + { + x= "a"::string. + y= if (x=="b")::string; i12n(on) + {1} else {0}. y } )Code" ); man->analyse(); InterpretationPass* pass; if (man->isPassRegistered(PassId::InterpretationPass)){ pass = (InterpretationPass*) man->getPassById(PassId::InterpretationPass); } else { pass = new InterpretationPass(man); pass->run(); } int (*main)() = (int (*)())man->run(); int result = main(); ASSERT_EQ(0, result); } TEST(Interpretation, Analysis_StatementIF_InterpretCondition_1){ XreateManager* man = XreateManager::prepare( R"Code( main = function(x:: int):: int { - comm= "inc":: string; interpretation(force). + comm= "inc":: string; i12n(on). y = if (comm == "inc")::int {x+1} else {x}. y } )Code" ); InterpretationPass* pass = new InterpretationPass(man); pass->run(); CodeScope* scopeEntry = man->root->findFunction("main")->getEntryScope(); Symbol symbolY{scopeEntry->getSymbol("y"), scopeEntry}; InterpretationData& dataSymbolY = Attachments::get(symbolY); ASSERT_EQ(CMPL_ONLY, dataSymbolY.resolution); ASSERT_EQ(IF_INTERPRET_CONDITION, dataSymbolY.op); } -TEST(Interpretation, Compilation_StatementIF_InterpretCondition_1){ +TEST(Interpretation, Doc_Compilation_StatementIF_InterpretCondition_1){ xreate::details::tier1::XreateManager* man = xreate::details::tier1::XreateManager::prepare( R"Code( - main = function(x:: int):: int; entry { - comm= "inc":: string; interpretation(force). + test = function(x:: int):: int; entry { + comm= "inc":: string; i12n(on). - y = if (comm == "inc")::int {x+1} else {x}. + y= if (comm == "inc"):: int + {x + 1} else {x}. y } )Code" ); man->analyse(); InterpretationPass* pass; if (man->isPassRegistered(PassId::InterpretationPass)){ pass = (InterpretationPass*) man->getPassById(PassId::InterpretationPass); } else { pass = new InterpretationPass(man); pass->run(); } int (*main)(int) = (int (*)(int))man->run(); int result = main(1); ASSERT_EQ(2, result); } -TEST(Interpretation, Compilation_StatementFOLD_INTERPRET_INPUT_1){ +TEST(Interpretation, Doc_Compilation_StatementFOLD_INTERPRET_INPUT_1){ xreate::details::tier1::XreateManager* man = xreate::details::tier1::XreateManager::prepare( R"Code( - main = function(x:: int):: int; entry { - commands = ["inc", "double", "dec"]:: [string]; interpretation(force). - - loop fold(commands->comm::string, x->operand):: int{ - switch(comm)::int - - case ("inc"){ - operand + 1 - } - - case ("dec"){ - operand - 1 - } - - case ("double"){ - operand * 2 - } + main = function(x:: int):: int; entry { + commands = {"inc", "double", "dec"}:: [string]; i12n(on). + + loop fold(commands->comm::string, x->operand):: int + { + switch(comm):: int + case ("inc") {operand + 1} + case ("dec") {operand - 1} + case ("double") {operand * 2} } } )Code" ); man->analyse(); InterpretationPass* pass; if (man->isPassRegistered(PassId::InterpretationPass)){ pass = (InterpretationPass*) man->getPassById(PassId::InterpretationPass); } else { pass = new InterpretationPass(man); pass->run(); } const ManagedFnPtr& funcMain = man->root->findFunction("main"); InterpretationData& dataBody = Attachments::get(funcMain); ASSERT_EQ(FOLD_INTERPRET_INPUT, dataBody.op); int (*main)(int) = (int (*)(int))man->run(); int result = main(10); ASSERT_EQ(21, result); } -TEST(Interpretation, StatementCall_RecursionNo_1){ +TEST(Interpretation, Doc_StatementCall_RecursionNo_1){ xreate::details::tier1::XreateManager* man = xreate::details::tier1::XreateManager::prepare( R"Code( - unwrap = function(data::unknType, keys::unknType):: unknType; interpretation(force){ - loop fold(keys->key::string, data->a):: unknType { - a[key] + unwrap = function(data::unknType, keys::unknType):: unknType; i12n(on) + { + loop fold(keys->key::string, data->record):: unknType + { + record[key] } } - start = function::num; entry{ - result = unwrap( - { - a = { - b = - { - c = "core" - } - } - }, ["a", "b", "c"])::unknType. - - result == "core" + test = function:: bool; entry + { + book = unwrap({ + Library = { + Shelf = { + Book = "Aristotle's Politics" + }}}, {"Library", "Shelf", "Book"}):: unknType. + + book == "Aristotle's Politics" } )Code" ); man->analyse(); InterpretationPass* pass; if (man->isPassRegistered(PassId::InterpretationPass)){ pass = (InterpretationPass*) man->getPassById(PassId::InterpretationPass); } else { pass = new InterpretationPass(man); pass->run(); } - int (*main)() = (int (*)())man->run(); - int result = main(); + unsigned char (*main)() = (unsigned char (*)())man->run(); + unsigned char result = main(); + + ASSERT_EQ(1, result); +} + +TEST(Interpretation, Doc_StatementCall_RecursionNo_2){ + xreate::details::tier1::XreateManager* man = xreate::details::tier1::XreateManager::prepare( +R"Code( + unwrap = function(data::unknType, keys::unknType):: unknType + { + loop fold(keys->key::string, data->record):: unknType + { + record[key] + } + } + + test = function:: bool; entry + { + book = unwrap({ + Library = { + Shelf = { + Book = "Aristotle's Politics" + }}}, {"Library", "Shelf", "Book"}):: unknType; i12n(on). + + book == "Aristotle's Politics" + } +)Code" ); + + man->analyse(); + + InterpretationPass* pass; + if (man->isPassRegistered(PassId::InterpretationPass)){ + pass = (InterpretationPass*) man->getPassById(PassId::InterpretationPass); + } else { + pass = new InterpretationPass(man); + pass->run(); + } + + unsigned char (*main)() = (unsigned char (*)())man->run(); + unsigned char result = main(); ASSERT_EQ(1, result); } -TEST(Interpretation, StatementCall_RecursionDirect_1){ +TEST(Interpretation, Doc_StatementCall_RecursionDirect_1){ xreate::details::tier1::XreateManager* man = xreate::details::tier1::XreateManager::prepare( R"Code( - unwrap = function(data:: X):: Y { - if (data[0] == "a")::Y {0} else {unwrap(data[0])} + unwrap = function(data:: X):: bool + { + if (data[0] == "the-end"):: bool + {true} else {unwrap(data[0])} } - entry = function:: i8; entry { - unwrap([[[["a"]]]]):: i8; interpretation(force) + entry = function:: bool; entry { + unwrap({{{{"the-end"}}}}):: bool; i12n(on) } )Code" ); man->analyse(); InterpretationPass* pass; if (man->isPassRegistered(PassId::InterpretationPass)){ pass = (InterpretationPass*) man->getPassById(PassId::InterpretationPass); } else { pass = new InterpretationPass(man); pass->run(); } InterpretationResolution resolutionActual = pass->process(man->root->findFunction("unwrap")); ASSERT_EQ(ANY, resolutionActual); - int (*main)() = (int (*)())man->run(); - int result = main(); + unsigned char (*main)() = (unsigned char (*)())man->run(); + unsigned char result = main(); - ASSERT_EQ(0, result); + ASSERT_NE(0, result); } TEST(Interpretation, StatementCall_RecursionIndirect_1){ XreateManager* man = XreateManager::prepare( R"Code( - funcA = function(data:: X):: Y { - if (data == "a")::Y {0} else {funcB(data)} + searchNemo = function(data:: Data):: bool + { + if (data == "nemo"):: bool + {false} else {searchDory(data)} } - funcB = function(data:: X):: Y { - if (data == "b")::Y {1} else {funcA(data)} + searchDory = function(data:: Data):: bool + { + if (data == "dory"):: bool + {true} else {searchNemo(data)} } - entry = function:: i8; entry { - funcA(""):: i8; interpretation(force) + entry = function:: bool; entry { + searchNemo(""):: bool; i12n(on) } )Code" ); InterpretationPass* pass = new InterpretationPass(man); ASSERT_DEATH(pass->run(), "Indirect recursion detected"); } TEST(Interpretation, PartialIntr_1){ XreateManager* man = XreateManager::prepare( R"Code( - evaluate= function(argument:: num, code:: string; interpretation(force)):: num { - switch(code)::int - case ("inc") {argument + 1} - case ("dec") {argument - 1} - case ("double") {argument * 2} + evaluate= function(argument:: num, code:: string; i12n(on)):: num { + switch(code):: num + case ("inc") {argument + 1} + case ("dec") {argument - 1} + case ("double") {argument * 2} + case default {argument} } - main = function::int; entry { - commands= ["inc", "double", "dec"]:: [string]; interpretation(force). + main = function:: int; entry { + commands= {"inc", "double", "dec"}:: [string]; i12n(on). - loop fold(commands->comm::string, 10->operand):: int{ + loop fold(commands->comm::string, 10->operand):: int + { evaluate(operand, comm) } } )Code" ); InterpretationPass* pass = new InterpretationPass(man); pass->run(); ManagedFnPtr fnEvaluate = man->root->findFunction("evaluate"); InterpretationResolution resFnEvaluate= pass->process(fnEvaluate); ASSERT_EQ(CMPL_ONLY, resFnEvaluate); ASSERT_TRUE(FunctionInterpretationHelper::needPartialInterpretation(fnEvaluate)); const Expression& exprLoop = man->root->findFunction("main")->__entry->getBody(); Symbol symbCallEv{{0, versions::VERSION_NONE}, exprLoop.blocks.front()}; InterpretationData dataCallEv = Attachments::get(symbCallEv); ASSERT_EQ(CMPL_ONLY, dataCallEv.resolution); ASSERT_EQ(CALL_INTERPRET_PARTIAL, dataCallEv.op); } -TEST(Interpretation, Compilation_PartialIntr_2){ +TEST(Interpretation, Doc_Compilation_PartialIntr_2){ xreate::details::tier1::XreateManager* man = xreate::details::tier1::XreateManager::prepare( R"Code( - evaluate= function(argument:: num, code:: string; interpretation(force)):: num { - switch(code)::int - case ("inc") {argument + 1} - case ("dec") {argument - 1} - case ("double") {argument * 2} - case default {argument} - } +evaluate= function(argument:: num, code:: string; i12n(on)):: num { + switch(code):: num + case ("inc") {argument + 1} + case ("dec") {argument - 1} + case ("double") {argument * 2} + case default {argument} +} - main = function::int; entry { - commands= ["inc", "double", "dec"]:: [string]; interpretation(force). +main = function(init::int):: int; entry { + commands= {"inc", "double", "dec"}:: [string]; i12n(on). - loop fold(commands->comm::string, 10->operand):: int{ - evaluate(operand, comm) - } + loop fold(commands->comm::string, init->operand):: int + { + evaluate(operand, comm) } +} )Code" ); man->analyse(); if (!man->isPassRegistered(PassId::InterpretationPass)){ InterpretationPass* pass = new InterpretationPass(man); pass->run(); } - int (*main)() = (int (*)())man->run(); - int result = main(); + int (*main)(int) = (int (*)(int))man->run(); + int result = main(10); ASSERT_EQ(21, result); } TEST(Interpretation, PartialIntr_3){ xreate::details::tier1::XreateManager* man = xreate::details::tier1::XreateManager::prepare( R"Code( Command= type variant {INC, DEC, DOUBLE}. - evaluate= function(argument:: num, code:: Command; interpretation(force)):: num { + evaluate= function(argument:: num, code:: Command; i12n(on)):: num { switch variant(code)::int case (INC) {argument + 1} case (DEC) {argument - 1} case (DOUBLE) {argument * 2} } main = function::int; entry { - commands= [INC(), DOUBLE(), DEC()]:: [Command]; interpretation(force). + commands= {INC(), DOUBLE(), DEC()}:: [Command]; i12n(on). loop fold(commands->comm::Command, 10->operand):: int{ evaluate(operand, comm) } } )Code" ); man->analyse(); if (!man->isPassRegistered(PassId::InterpretationPass)){ InterpretationPass* pass = new InterpretationPass(man); pass->run(); } int (*main)() = (int (*)())man->run(); int result = main(); ASSERT_EQ(21, result); } TEST(Interpretation, PartialIntr_4){ xreate::details::tier1::XreateManager* man = xreate::details::tier1::XreateManager::prepare( R"Code( Command= type variant {INC, DEC, DOUBLE}. - evaluate= function(argument:: num, code:: Command; interpretation(force)):: num { + evaluate= function(argument:: num, code:: Command; i12n(on)):: num { switch variant(code)::num case (INC) {argument + 1} case (DEC) {argument - 1} case (DOUBLE) {argument * 2} } main = function::int; entry { evaluate(4, DEC()) } )Code" ); man->analyse(); if (!man->isPassRegistered(PassId::InterpretationPass)){ InterpretationPass* pass = new InterpretationPass(man); pass->run(); } int (*main)() = (int (*)())man->run(); int result = main(); ASSERT_EQ(3, result); } TEST(Interpretation, SwitchVariant){ xreate::XreateManager* man = xreate::XreateManager::prepare( R"Code( OneArgument = type{x::int}. TWoArgument = type {x::int, y::int}. Command= type variant { ADD::TwoArguments, DEC:: OneArgument, DOUBLE::OneArgument }. main = function::int; entry{ - program = ADD({x=2, y=3})::Command; interpretation(force). + program = ADD({x=2, y=3})::Command; i12n(on). switch variant(program)::int case (ADD) {program["x"]+program["y"]} case (DEC) {1} case (DOUBLE) {2} } )Code" ); int (*main)() = (int (*)())man->run(); int result = main(); ASSERT_EQ(5, result); } TEST(Interpretation, SwitchVariantAlias){ xreate::XreateManager* man = xreate::XreateManager::prepare( R"Code( -OneArgument = type{x::int}. +OneArgument = type {x::int}. TWoArgument = type {x::int, y::int}. Command= type variant { ADD::TwoArguments, DEC:: OneArgument, DOUBLE::OneArgument }. main = function::int; entry{ - program = [ADD({x=2, y=3}), DEC({x=8})]::[Command]; interpretation(force). + program = {ADD({x=2, y=3}), DEC({x=8})}::[Command]; i12n(on). switch variant(program[0]->program::Command)::int case (ADD) {program["x"]+program["y"]} case (DEC) {1} case (DOUBLE) {2} } )Code" ); int (*main)() = (int (*)())man->run(); int result = main(); ASSERT_EQ(5, result); } TEST(Interpretation, Multiindex1){ std::string script2= R"Code( - extract = function(program::unknType)::int; interpretation(force){ + extract = function(program::unknType)::int; i12n(on){ program["arguments"][1] } main = function::int; entry { - x = {arguments = [10, 9, 8, 7]}:: unknType; interpretation(force). + x = {arguments = {10, 9, 8, 7}}:: unknType; i12n(on). extract(x) } )Code"; std::unique_ptr man(XreateManager::prepare(std::move(script2))); int (*main)() = (int (*)())man->run(); int result = main(); ASSERT_EQ(9, result); } TEST(InterpretationExamples, Regexp1){ FILE* input = fopen("scripts/dsl/regexp.xreate","r"); assert(input != nullptr); std::unique_ptr man(XreateManager::prepare(input)); int (*main)() = (int (*)())man->run(); int result = main(); ASSERT_EQ(4, result); } TEST(Interpretation, Variant1){ std::string script= R"Code( Data = type {Num:: [int], String::string}. DataPacked = type variant { Var1:: Data, Var2:: Data }. extractInt = function(data::DataPacked):: int { resultWrong = 0 :: int. switch variant(data)::int case (Var1) {data["Num", 0]} case (Var2) {resultWrong} } main = function :: int; entry { dataActual = 10. - dataPacked = Var1({Num = [dataActual], String = "whatever"}):: DataPacked. + dataPacked = Var1({Num = {dataActual}, String = "whatever"}):: DataPacked. - extractInt(dataPacked):: int; interpretation(force) + extractInt(dataPacked):: int; i12n(on) } )Code"; std::unique_ptr man(XreateManager::prepare(std::move(script))); int (*main)() = (int (*)())man->run(); int result = main(); ASSERT_EQ(10, result); } //TOTEST call indirect recursion(w/o tags) //TASk implement and test Loop Inf (fix acc types in coco grammar) diff --git a/cpp/tests/loops.cpp b/cpp/tests/loops.cpp index 1de81f0..7e080f5 100644 --- a/cpp/tests/loops.cpp +++ b/cpp/tests/loops.cpp @@ -1,187 +1,274 @@ /* Any copyright is dedicated to the Public Domain. * http://creativecommons.org/publicdomain/zero/1.0/ * * loops.cpp * * Created on: - * Author: pgess */ #include "xreatemanager.h" #include "gtest/gtest.h" using namespace std; -TEST(Loop, SimpleLoop1){ +TEST(Loop, LoopFold1){ string code = R"CODE( main = function:: int; entry { input = [1..5]:: [int]. loop fold(input->el::int, 0->sum)::int { sum + el } } )CODE"; xreate::XreateManager* man = xreate::XreateManager::prepare(move(code)); int (*funcMain)() = (int (*)()) man->run(); int answerActual = funcMain(); ASSERT_EQ(15, answerActual); } -TEST(Loop, Break1){ +TEST(Loop, LoopFoldFinal){ string code = R"CODE( main = function:: int; entry { input = [1..10]:: [int]. loop fold(input->el::int, 0->sum)::int { if (sum>5)::int { - sum:: int; break + sum:: int; final } else {sum+el} } } )CODE"; xreate::XreateManager* man = xreate::XreateManager::prepare(move(code)); int (*funcMain)() = (int (*)()) man->run(); int answerActual = funcMain(); ASSERT_EQ(6, answerActual); } -TEST(Loop, NestedLoopsSimple1){ +TEST(Loop, NestedLoops1){ string code = R"CODE( main = function:: int; entry { listX = [1..5]:: [int]. loop fold(listX->x::int, 0->acc)::int { listY = [1..5]:: [int]. row = loop fold(listY->y::int, 1->acc):: int { acc * ( y + x) }. acc + row } } )CODE"; xreate::XreateManager* man = xreate::XreateManager::prepare(move(code)); int (*funcMain)() = (int (*)()) man->run(); int answerActual = funcMain(); ASSERT_EQ(55320, answerActual); } -TEST(Loop, NestedLoopsBreak1){ +TEST(Loop, NestedLoopsFinal1){ string code = R"CODE( main = function:: int; entry { listX = [1..5]:: [int]. loop fold(listX->x::int, 0->acc)::int { listY = [1..5]:: [int]. row = loop fold(listY->y::int, 1->acc):: int { res = acc * ( y + x) :: int. if (res > 20):: int { - 20:: int; break + 20:: int; final } else { res } }. acc + row } } )CODE"; xreate::XreateManager* man = xreate::XreateManager::prepare(move(code)); int (*funcMain)() = (int (*)()) man->run(); int answerActual = funcMain(); ASSERT_EQ(100, answerActual); } -TEST(Loop, NestedLoopsBreak2){ +TEST(Loop, NestedLoopsFinal2){ string code = R"CODE( main = function:: int; entry { listX = [1..3]:: [int]. loop fold(listX->x::int, 0->acc)::int { listY = [1..5]:: [int]. row = loop fold(listY->y::int, 1->acc):: int { res = acc * y :: int. if (res > 24):: int { - 24:: int; break + 24:: int; final } else { res } }. if (x==3)::int{ - acc:: int; break + acc:: int; final } else { acc + row } } } )CODE"; xreate::XreateManager* man = xreate::XreateManager::prepare(move(code)); int (*funcMain)() = (int (*)()) man->run(); int answerActual = funcMain(); ASSERT_EQ(48, answerActual); } -//TEST nested loop breaks. -//TEST 2 breaks^ outer loop break, inner loop break - TEST(Loop, InfiniteLoop1){ string code = R"Code( fac = function(x:: int):: int{ range = [2..x] :: [int]. - loop fold(range->i::int, 1->acc)::int { - acc * i - } + loop fold(range->i::int, 1->acc)::int + {acc * i} } main = function:: int; entry { - loop fold inf(2->state) :: int { + loop (2->state) :: int { if (fac(state)==120)::int { - state::int; break + state::int; final } else {state + 1} } } )Code" ; xreate::XreateManager* man = xreate::XreateManager::prepare(move(code)); int (*funcMain)() = (int (*)()) man->run(); int answerActual = funcMain(); ASSERT_EQ(5, answerActual); } + +TEST(Loop, Doc_LoopInfinite){ + string code = +R"Code( + //infinite loop + answer = loop (2->x) :: int + { + if(IsPerfect(x)):: int {x} else {x+1} + }. +)Code" ; + + string code2 = +R"Code( + //loop exits after first perfect number is found + answer2 = loop (2->x) :: int + { + if(IsPerfect(x))::int {x:: int; final} else {x+1} + }. +)Code" ; + + string codeWrapper = +R"Code( + IsPerfect = function(x::int):: bool {x==6} + test = function::int; entry + { + %TEST% + %TEST2% + + answer + answer2 + } +)Code" ; + + codeWrapper.replace(codeWrapper.find("%TEST%"), 6, code); + codeWrapper.replace(codeWrapper.find("%TEST2%"), 7, code2); + xreate::XreateManager* man = xreate::XreateManager::prepare(string(codeWrapper)); + ASSERT_TRUE(man); +} + +TEST(Loop, Doc_LoopLoopFold){ + string code = +R"CODE( + numbers = {4, 8, 7, 1, 5}:: [int]. + min = loop fold(numbers->x:: int, 10->acc):: int + { + if (acc > x):: int {x} else {acc} + }. +)CODE"; + + string codeWrapper = +R"CODE( + main = function:: int; entry + { + %TEST% + min + } +)CODE"; + + codeWrapper.replace(codeWrapper.find("%TEST%"), 6, code); + xreate::XreateManager* man = xreate::XreateManager::prepare(move(codeWrapper)); + int (*funcMain)() = (int (*)()) man->run(); + + int answerActual = funcMain(); + ASSERT_EQ(1, answerActual); +} + +TEST(Loop, Doc_LoopLoopMap){ + string code = +R"CODE( + numbers = {4, 8, 7, 1, 5}:: [int]. + min = loop fold(numbers->x:: int, 10->acc):: int + { + if (acc > x):: int {x} else {acc} + }. +)CODE"; + + string codeWrapper = +R"CODE( + main = function:: int; entry + { + odd_numbers = {1, 3, 5}:: [int]. + even_numbers = loop map(odd_numbers->number::int) :: [int] + { 2 * number }. + + even_numbers[0] + } +)CODE"; + + //codeWrapper.replace(codeWrapper.find("%TEST%"), 6, code); + xreate::XreateManager* man = xreate::XreateManager::prepare(move(codeWrapper)); + ASSERT_TRUE(man); +} diff --git a/cpp/tests/modules.cpp b/cpp/tests/modules.cpp index a857c5d..602e096 100644 --- a/cpp/tests/modules.cpp +++ b/cpp/tests/modules.cpp @@ -1,323 +1,407 @@ /* Any copyright is dedicated to the Public Domain. * http://creativecommons.org/publicdomain/zero/1.0/ * * modules.cpp * * Author: pgess * Created on June 18, 2017, 8:25 PM */ class Modules_AST2_Test; class Modules_Discovery1_Test; class Modules_Solve1_Test; #define FRIENDS_MODULES_TESTS \ friend class ::Modules_AST2_Test; \ friend class ::Modules_Discovery1_Test; \ friend class ::Modules_Solve1_Test; #include "modules.h" #include "aux/xreatemanager-decorators.h" #include "aux/xreatemanager-modules.h" #include "xreatemanager.h" #include "modules/Parser.h" #include "gtest/gtest.h" #include #include #include namespace fs = boost::filesystem; using namespace std; using namespace xreate; using namespace xreate::modules; TEST(Modules, AST1) { FILE* input = fopen("scripts/dsl/regexp.xreate","r"); assert(input != nullptr); Scanner scanner(input); Parser parser(&scanner); parser.Parse(); ASSERT_EQ(parser.errors->count, 0); } TEST(Modules, AST2){ string code = R"Code( - module { - name(test1). - status(untested). - - require provides(logging). - include controller("/tmp/test-controller.ls"). + module:: name(test1); status(untested) + { + require(provides(logging)). + controller("/tmp/test-controller.ls"). discover("/tmp/root/"). } )Code"; Scanner scanner(reinterpret_cast(code.c_str()), code.size()); Parser parser(&scanner); parser.Parse(); ModuleRecord module = parser.module; ASSERT_EQ(2, module.__properties.size()); ASSERT_EQ("name", module.__properties.front().getValueString()); ASSERT_EQ("status", module.__properties.back().getValueString()); - ASSERT_EQ(1, module.__queries.size()); - ASSERT_EQ("provides", module.__queries.front().getValueString()); + ASSERT_EQ(1, module.__requests.size()); + ASSERT_EQ("provides", module.__requests.front().getValueString()); ASSERT_EQ(1, module.__controllers.size()); ASSERT_EQ("/tmp/test-controller.ls", module.__controllers.front()); - ASSERT_EQ(1, module.__discoveries.size()); - ASSERT_EQ("/tmp/root/", module.__discoveries.front()); + ASSERT_EQ(1, module.__discoveryPaths.size()); + ASSERT_EQ("/tmp/root/", module.__discoveryPaths.front()); } TEST(Modules, Discovery1){ const std::string dirModulesRoot = "/tmp/testModulesDiscovery1_t54723/"; string codeA = -R"Code(module { - name(testA). - status(needToTestMore). -})Code"; +R"Code( + module::name(testA); status(needToTestMore). +)Code"; string codeB = -R"Code(module { - name(testB). - status(needToTestEvenMore). -})Code"; +R"Code( + module:: name(testB); status(needToTestEvenMore). +)Code"; - string codeMain = string("module{discover \"") + dirModulesRoot + "\".}"; + string codeMain = string("module{discover (\"") + dirModulesRoot + "\").}"; fs::create_directories(dirModulesRoot); fs::ofstream fileA(dirModulesRoot + "a.xreate"); fileA << codeA; fileA.close(); fs::ofstream fileB(dirModulesRoot + "b.xreate"); fileB << codeB; fileB.close(); Scanner scanner(reinterpret_cast(codeMain.c_str()), codeMain.size()); Parser parser(&scanner); parser.Parse(); - ModulesRegistry registry; - ModulesSolver solver(®istry); + ModulesSolver solver; solver.discoverModules(parser.module); fs::remove_all(dirModulesRoot); std::string output = solver.__program.str(); cout << output << endl; - ASSERT_NE(string::npos, output.find("bind_module(0, name(testA)).")); - ASSERT_NE(string::npos, output.find("bind_module(1, status(needToTestEvenMore)).")); + ASSERT_NE(string::npos, output.find("bind_module(\"/tmp/testModulesDiscovery1_t54723/a.xreate\", name(testA)).")); + ASSERT_NE(string::npos, output.find("bind_module(\"/tmp/testModulesDiscovery1_t54723/b.xreate\", status(needToTestEvenMore)).")); } TEST(Modules, Requests1){ } -TEST(Modules, Solve1){ - const std::string dirModulesRoot = "/tmp/testModulesDiscovery1_t54724/"; - +TEST(Modules, Doc_AdvModRes_1){ string codeA = -R"Code(module { - name(testA). - provide(superService). - status(needToTestMore). -})Code"; + R"Code( + //First Module + module:: + name(testA); + provide(superService); + status(needToTestEvenMore). + )Code"; string codeB = -R"Code(module { - name(testB). - provide(superService). - status(needToTestEvenMore). -})Code"; + R"Code( + //Second Module + module:: + name(testB); + provide(superService); + status(needToTest). + )Code"; string codeMain = -R"Code(module { - discover("/tmp/testModulesDiscovery1_t54724/") - include controller ("/tmp/testModulesDiscovery1_t54724/controller") +R"Code( + //Third Module + module { + require (superService). + + discover("/tmp/testModulesDiscovery1_t54724/"). + controller("/tmp/testModulesDiscovery1_t54724/controller"). + } +)Code"; - require (superService) -})Code"; + const std::string dirModulesRoot = "/tmp/testModulesDiscovery1_t54724/"; string codeController = R"Code( status_score(0, needToTestEvenMore). -status_score(1, needToTestMore). +status_score(1, needToTest). -module_include_candidate(X, Y, Request):- - module_require(X, Request); bind_module(Y, provide(Request)). +module_include_candidate(Request, Y):- + bind_module(Y, provide(Request)). -module_include_winner(X, Request, MaxScore) :- - MaxScore = #max{Score: module_include_candidate(X, Y, Request), bind_module(Y, status(Status)), status_score(Score, Status)}; - module_require(X, Request). +module_include_winner(Request, MaxScore) :- + MaxScore = #max{Score: module_include_candidate(Request, Y), bind_module(Y, status(Status)), status_score(Score, Status)}; + modules_require(_, Request). -module_include(X, Y) :- - module_include_winner(X, Request, MaxScore); +modules_resolution(Request, Y) :- + module_include_winner(Request, MaxScore); bind_module(Y, provide(Request)); bind_module(Y, status(Status)); status_score(MaxScore, Status). )Code"; fs::create_directories(dirModulesRoot); fs::ofstream fileA(dirModulesRoot + "a.xreate"); fileA << codeA; fileA.close(); fs::ofstream fileB(dirModulesRoot + "b.xreate"); fileB << codeB; fileB.close(); fs::ofstream fileController(dirModulesRoot + "controller"); fileController << codeController; fileController.close(); Scanner scanner(reinterpret_cast(codeMain.c_str()), codeMain.size()); Parser parser(&scanner); parser.Parse(); - ModulesRegistry registry; - ModulesSolver solver(®istry); + ModulesSolver solver; solver.init("", parser.module); fs::remove_all(dirModulesRoot); cout << solver.__program.str() << endl; std::list modulesRequired = solver.run(parser.module); ASSERT_EQ(1, modulesRequired.size()); string moduleActualRequired = modulesRequired.front(); - string moduleExpected = dirModulesRoot + "a.xreate"; + string moduleExpected = dirModulesRoot + "b.xreate"; ASSERT_EQ(moduleExpected, moduleActualRequired); } TEST(Modules, Compilation1){ const std::string dirModulesRoot = "/tmp/testModulesDiscovery1_t54726/"; string codeMain = R"Code( module { - discover("/tmp/testModulesDiscovery1_t54726/") - include controller("/tmp/testModulesDiscovery1_t54726/controller") - - require (superService) + discover("/tmp/testModulesDiscovery1_t54726/"). + controller("/tmp/testModulesDiscovery1_t54726/controller"). + require (superService). } test = function:: int; entry { getYourNumber() } )Code"; string codeA = -R"Code(module { - name(testA). - provide(superService). - status(needToTestEvenMore). -} +R"Code( + module:: name(testA); provide(superService); status(needToTestEvenMore). -getYourNumber= function:: int {0} + getYourNumber= function:: int {0} )Code"; string codeB = -R"Code(module { - name(testB). - provide(superService). - status(needToTestMore). -} +R"Code( + module :: name(testB); provide(superService); status(needToTestMore). -getYourNumber= function:: int {1} + getYourNumber= function:: int {1} )Code"; string codeController = R"Code( status_score(0, needToTestEvenMore). status_score(1, needToTestMore). -module_include_candidate(X, Y, Request):- - module_require(X, Request); bind_module(Y, provide(Request)). +module_include_candidate(Request, Y):- + bind_module(Y, provide(Request)). -module_include_winner(X, Request, MaxScore) :- - MaxScore = #max{Score: module_include_candidate(X, Y, Request), bind_module(Y, status(Status)), status_score(Score, Status)}; - module_require(X, Request). +module_include_winner(Request, MaxScore) :- + MaxScore = #max{Score: module_include_candidate(Request, Y), bind_module(Y, status(Status)), status_score(Score, Status)}; + modules_require(_, Request). -module_include(X, Y) :- - module_include_winner(X, Request, MaxScore); +modules_resolution(Request, Y) :- + module_include_winner(Request, MaxScore); bind_module(Y, provide(Request)); bind_module(Y, status(Status)); status_score(MaxScore, Status). )Code"; fs::create_directories(dirModulesRoot); fs::ofstream fileA(dirModulesRoot + "a.xreate"); fileA << codeA; fileA.close(); fs::ofstream fileB(dirModulesRoot + "b.xreate"); fileB << codeB; fileB.close(); fs::ofstream fileController(dirModulesRoot + "controller"); fileController << codeController; fileController.close(); auto man = new XreateManagerImpl>(); man->prepareCode(std::move(codeMain)); fs::remove_all(dirModulesRoot); int (*funcMain)() = (int (*)()) man->run(); int result = funcMain(); ASSERT_EQ(1, result); } TEST(Modules, Compilation_AssignModulePath1){ const std::string dirModulesRoot = "/tmp/testModulesDiscovery1_t54725/"; string codeMain = R"Code( module { - discover("/tmp/testModulesDiscovery1_t54725/") - include controller("/tmp/testModulesDiscovery1_t54725/controller") + discover("/tmp/testModulesDiscovery1_t54725/"). + controller("/tmp/testModulesDiscovery1_t54725/controller"). - require (superService) + require (superService). } test = function:: int; entry { getYourNumber() } )Code"; string codeA = -R"Code(module { - name(testA). - provide(superService). - status(needToTestEvenMore). -} +R"Code( + module:: name(testA); provide(superService); status(needToTestEvenMore). -getYourNumber= function:: int {0} + getYourNumber= function:: int {0} )Code"; string codeController = R"Code( -module_include(X, "/tmp/testModulesDiscovery1_t54725/a.xreate") :- module_require(X, superService). + modules_resolution(superService, "/tmp/testModulesDiscovery1_t54725/a.xreate"). )Code"; fs::create_directories(dirModulesRoot); fs::ofstream fileA(dirModulesRoot + "a.xreate"); fileA << codeA; fileA.close(); fs::ofstream fileController(dirModulesRoot + "controller"); fileController << codeController; fileController.close(); auto man = new XreateManagerImpl>(); man->prepareCode(std::move(codeMain)); fs::remove_all(dirModulesRoot); int (*funcMain)() = (int (*)()) man->run(); int result = funcMain(); ASSERT_EQ(0, result); } + +TEST(Modules, Doc_Requesting_Modules_1){ + string codeExcerpt = R"Code( + module { + require(logger). + } + )Code"; + + string codeController = R"Code( + modules_resolution(logger, "/tmp/logger"). + )Code"; + + Scanner scanner(reinterpret_cast(codeExcerpt.c_str()), codeExcerpt.size()); + Parser parser(&scanner); + parser.Parse(); + + ModulesSolver solver; + solver.init(move(codeController), parser.module); + std::list result = solver.run(parser.module); + ASSERT_EQ(1, result.size()); + ASSERT_STREQ("/tmp/logger", result.front().c_str()); +} + +TEST(Modules, Doc_Requesting_Modules_2){ + string codeExcerpt = R"Code( + module{require(stringslib).} + processString = function(a:: string):: string + { + someStrFunc(a) + } + + module{require(mathlib).} + processNumber = function(a:: num):: num + { + someMathFunc(a) + } + )Code"; + + string codeController = R"Code( + modules_resolution(stringslib, "/tmp/stringslib"). + modules_resolution(mathlib, "/tmp/mathlib"). + )Code"; + + Scanner scanner(reinterpret_cast(codeExcerpt.c_str()), codeExcerpt.size()); + Parser parser(&scanner); + parser.Parse(); + + ModulesSolver solver; + solver.init(move(codeController), parser.module); + std::list result = solver.run(parser.module); + ASSERT_EQ(2, result.size()); + ASSERT_STREQ("/tmp/stringslib", result.front().c_str()); + ASSERT_STREQ("/tmp/mathlib", result.back().c_str()); +} + +TEST(Modules, Doc_ModuleAnnotations_1){ + string codeExcerpt = R"Code( + module:: status(obsolete). + )Code"; + + Scanner scanner(reinterpret_cast(codeExcerpt.c_str()), codeExcerpt.size()); + Parser parser(&scanner); + parser.Parse(); + + ModulesSolver solver; + solver.init("", parser.module); + + string program = solver.__program.str(); + ASSERT_NE(string::npos, program.find("bind_module(\"\", status(obsolete)).")); +} + +TEST(Modules, Doc_ModulesResolution_1){ + string codeExcerpt = R"Code( + modules_resolution(numlib, "/path/to/numlib"). + modules_resolution(strings, "/path/to/ansi-lib", ""). + modules_resolution(strings, "/path/to/utf8-lib", "moduleB"). + )Code"; + + string codeModule = R"Code( + module {require(numlib). require(strings)} + )Code"; + + Scanner scanner(reinterpret_cast(codeModule.c_str()), codeModule.size()); + Parser parser(&scanner); + parser.Parse(); + + ModulesSolver solver; + solver.init(codeExcerpt, parser.module); + std::list result = solver.run(parser.module); + ASSERT_EQ(2, result.size()); + ASSERT_STREQ("/path/to/numlib", result.front().c_str()); + ASSERT_STREQ("/path/to/ansi-lib", result.back().c_str()); +} diff --git a/cpp/tests/types.cpp b/cpp/tests/types.cpp index a25c7d4..110d315 100644 --- a/cpp/tests/types.cpp +++ b/cpp/tests/types.cpp @@ -1,248 +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(TypeOperator::LIST_RECORD, 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(TypeOperator::LIST_ARRAY, 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(TypeOperator::LIST_RECORD, typeConcrete->__operator); ASSERT_EQ(2, typeConcrete->__operands.size()); - ASSERT_EQ(TypeOperator::LIST_NAMED, typeConcrete->__operands.at(0).__operator); + ASSERT_EQ(TypeOperator::LIST_RECORD, typeConcrete->__operands.at(0).__operator); - ASSERT_EQ(TypeOperator::LIST, typeConcrete->__operands.at(1).__operator); + ASSERT_EQ(TypeOperator::LIST_ARRAY, 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(TypeOperator::LIST_RECORD, typeConcrete->__operator); ASSERT_EQ(2, typeConcrete->__operands.size()); - ASSERT_EQ(TypeOperator::LIST_NAMED, typeConcrete->__operands.at(0).__operator); + ASSERT_EQ(TypeOperator::LIST_RECORD, typeConcrete->__operands.at(0).__operator); - ASSERT_EQ(TypeOperator::LIST, typeConcrete->__operands.at(1).__operator); + ASSERT_EQ(TypeOperator::LIST_ARRAY, 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); + EXPECT_EQ(t2->__operator, TypeOperator::LIST_ARRAY); } 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(TypeOperator::LIST_RECORD, 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"); } diff --git a/cpp/tests/virtualization.cpp b/cpp/tests/virtualization.cpp index fe6bc53..033a706 100644 --- a/cpp/tests/virtualization.cpp +++ b/cpp/tests/virtualization.cpp @@ -1,60 +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, UniqueSizoPrefix_1) { FILE* input = fopen("scripts/virtualization/test1.xreate", "r"); assert(input != nullptr); 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); + ASSERT_EQ(TypeOperator::LIST_RECORD, 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(); testing::internal::CaptureStdout(); main(); std::string outputActual = testing::internal::GetCapturedStdout(); cout << outputActual << endl; ASSERT_STREQ("file opened: test1 file opened: test1 ", outputActual.c_str()); } 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/modules.graphml b/documentation-api/modules.graphml new file mode 100644 index 0000000..542a391 --- /dev/null +++ b/documentation-api/modules.graphml @@ -0,0 +1,121 @@ + + + + + + + + + + + + + + + + + + + + + + + + ModuleRecord + + + addModuleQuery +addControllerPath +addDiscoveryPath +addProperty + + + + + + + + + + + ModulesSolver + + + loadControllers +discoverModules +extractProperties +extractRequirements +init +add + + + + + + + + + + + XreateManagerDecoratorModules + + + + + + + + + + + + + + + PassManager + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/documentation/Analysis/cfa.remarkup b/documentation/Analysis/cfa.remarkup deleted file mode 100644 index 30e1acc..0000000 --- a/documentation/Analysis/cfa.remarkup +++ /dev/null @@ -1,4 +0,0 @@ -==CFA: Control Flow Analisys== - -CFA expresses program control flow graph. Number of language aspects depends on knowledge of caller/callee relation between various parts of program. -[[Concepts/context]] is probably the most prominent Xreate feature depended of CFA. \ No newline at end of file diff --git a/documentation/Analysis/dfa.remarkup b/documentation/Analysis/dfa.remarkup deleted file mode 100644 index e69de29..0000000 diff --git a/documentation/Analysis/dominators_analysis.remarkup b/documentation/Analysis/dominators_analysis.remarkup deleted file mode 100644 index e69de29..0000000 diff --git a/documentation/Analysis/index.remarkup b/documentation/Analysis/index.remarkup deleted file mode 100644 index e69de29..0000000 diff --git a/documentation/Articles/declarative_patterns.remarkup b/documentation/Articles/declarative_patterns.remarkup deleted file mode 100644 index 96ef02a..0000000 --- a/documentation/Articles/declarative_patterns.remarkup +++ /dev/null @@ -1,37 +0,0 @@ -In addition to a classic object-oriented common patterns and practices there are -several areas and problems not very easy and conveniently expressed by object oriented approach. - -Few of so called declarative patterns are presented below : - -* **Dependency resolution** - Starting at some level of complexity every software project usually faces need of managing dependencies - of some kind like package dependencies, components and versions dependency. - Dependencies are easily represented by declarative means and moreover usually do not change - drastically at runtime. Thus dependency management is good candidate for static/compile-time resolution. - See [[articles/declarative_patterns#dependency-resolution|details]]. - -* **Supply and demand** - A big amount of a problems could be expressed in terms of supply and demand of interacting components. - See [[articles/declarative_patterns#demand-and-supply|details]]. - -* **Share or joint use**(as planning in terms of space): - Examples: first/last use determination, share use planning and allocation(memory, etc).See for example [[concepts/usage| resources usage]]. - - * Planning in time. - Examples: Time Machine - - -* **Verification and Adaptation** -TODO expand on verification and adaptation. Upstream/downstream - -* **Preferences** -Abitility to express preferences(like/dislike) allows recognize situation ... - -* **Distibuted information in no particular order ** -Information gathered from different sources. - - - -===Demand and supply=== - -===Share or joint use=== diff --git a/documentation/Articles/gestalts.remarkup b/documentation/Articles/gestalts.remarkup deleted file mode 100644 index 449df72..0000000 --- a/documentation/Articles/gestalts.remarkup +++ /dev/null @@ -1,22 +0,0 @@ -==Computational gestalts== -There are number of commonly accepted concepts that are redefined or reevaluated in Xreate. - -* Interface is comprised of common subset of features supported by all concrete implementations. - See [[concepts/containers]] - -* Top-down annotations(like function, objects annotations) are exposed to and could be intospected by client code or caller. - Most usefull is exposing of caller annotations to a callee code or bottom-up annotations. - -* Lazy/eager execution atnagonism. - It's possible to determine which sites of using resource should treat it as lazy resource or eager otherwise. - See [[concepts/exploitation]] for details. - -* Static/dynamic antagonism - - -* High-level feast or famine - -===Static/dynamic antagonism=== - -===Polymorphism=== -Either instantiations or indirect calls \ No newline at end of file diff --git a/documentation/Articles/logic_inference.remarkup b/documentation/Articles/logic_inference.remarkup deleted file mode 100644 index 8d5743f..0000000 --- a/documentation/Articles/logic_inference.remarkup +++ /dev/null @@ -1,83 +0,0 @@ -==Annotations== - -**Annotation** stands for any additional piece of information provided by developer in source code or other augmented files. -Annotations express specific properties and relations of be it either a variable, -or single code statement or a code block or a function or source file or even a whole program. -This additional knowledge is precious in number of circumstances for improving compilation in a different ways. - -NOTE: Beyond that, there are implicit annotations automatically inferred from source code by various analyses phases to express useful insights regarding analised code. -Such annotations do not exposed directly to a developer but accessed and used internally at reasoning phase. - -See [[Syntax/Annotations|syntax and examples]] for annotations. - -==Logic inference== - -This is a process of an annotations extracting from source code and from any accompanied data and reasoning to make decisions affecting compilation phase. - -Annotations are gathered from number of inputs, such as: - -|Explicit source annotations | Annotations provided by code authors in order to explictily affect on compilation. See [[Syntax/Annotations]] for details | -|Annotation rules | Extracting rules from source code and from any other accompanied data to control reasoning and annotations propagation. See [[Syntax/Annotations#annotation-rules]] for details| -|Code analysis | {TODO: provide links}. Number of different code analyses provide data implicitly inferred from source code | -|Supervision annotations| Annotations to reflect current external requirements and overall environment state where compilation took place either on perating mode- or OS- or computer- or even network-level. See [[Concepts/supervision]] for details| - -{Fres/diagram-logic_inference_overview.dia} -Usual path of program compilation(depicted in the left part of the diagram) augmented by logic reasoning path(depicted in the right). -During initial phases scattered and disjoined annotations are gathered from various levels and inputs to form complete logic program. -Now reasoning runs based on gathered data and logic rules. Reasoning output directly affects compilation process in a number of ways(depicted as return arrow in the diagram). - -Ways to impact compilation phase are expanded and are matter of language evolution. -As of now implemented: - -|Context-based specialization| Exact function variant is picked up during compilation based on context. See [[Concepts/context]] for details| -|Container implementation| Exact container data implementation is picked up during compilation based on container usage. See [[Concepts/containers]] for details| - -In order to facilitate practically useful features as intended, annotations have to be: - * Domain specific, extendable, developer provided annotations - Compiler itself does not dictate exact set of annotations for developer to use, - but able to use custom annotations to expess desired program properties without prior changes to compiler. - Such ability is necessary to check program-specific policies and code metrics. See [[Syntax/Annotations#annotation-rules]], for further examples. - - * Explicitly control compiler - Annotations constitute convenient interface to interfere with compiler internal processes in cases - when it produces suboptimal results or even silly enough to not be able produce any at all. - Good examples are [[Syntax/Interfaces/extern_c| external interface]] or [[Concepts/dsl]] - - * Diffusible - Annotations in Xreate are intended for expressing information specific or useful in certain circumstances only. - Different annotations usually related to a different program aspects and it's natural way to allow different aspect's annotations - to sit in different places, to isolate responsibility and reduce manual support effors. - On the other hand, different anylis phases could produce additional(implicit) annotations along with manually provided ones to improve decisions quality. - - Taking all of this into account, compiler should be able to diffuse, or blend in annotations originated from various sources seamlessly to build solid foundation for logic inference. - Such ability is cruicial to facilitate [[Articles/declartative_patterns#preferences]], for example. - - * Augmented annotations - Very close to point above is ability to connect external and independent sources of annotations unknown on the development stage. - See [[Concepts/supervision]] for examples. - - * Bottom up annotations - Purpose of annotations' very existing as a language construct is unquestionable if it able to conduct information impossible to - express by any other traditional programming techniques or constructs. Particularly, this is true for information which is unknown during development. - //Paradoxycally speaking, annotations' very purpose and utility is to provide information which is impossbile to provide.// - - One example of such kind is information which is known only very lately is an enviroment where code is executing. - More precisely, library code(server) is unaware of exact particular characteristics of client code(frontend) it used by while library development. - Important ability of annotations to conduct information regarding caller code to a callee code for possible adjustemnts is called "bottom-up annotations" - meaning awareness "down" code(deep nodes in control tree) of "up" code (top nodes in control tree) particular characteristics. - - See [Objectives/Optimization/component_level_optimization] as example. - - * Automatic reevaluation - Any code reworking and rewriting leads to changes in annotations or relations between them, - and as a consequence leads to a different dicisions inferred by inference engine. - Such feature releases developer from burden of manually to spot and fix invalidated parts every time. - So it's good candidate to express by annotations every aspect which is broke frequentlty after code changes - - * Different applicable objects - Different techniques require reasoning about different kinds of program entities be it variables or whole source files. - As of now, Xreate supports annotations for variables, single statements, code blocks and entire functions. - -See also: - * [[Syntax/Annotations]] - * [[Articles/declarative_patterns]] diff --git a/documentation/Concepts/adhocs.remarkup b/documentation/Concepts/adhocs.remarkup deleted file mode 100644 index e69de29..0000000 diff --git a/documentation/Concepts/cache.remarkup b/documentation/Concepts/cache.remarkup deleted file mode 100644 index d7984e0..0000000 --- a/documentation/Concepts/cache.remarkup +++ /dev/null @@ -1,7 +0,0 @@ -* enclosed(parent-child) cache storage - -* sequential flow cache storage - -* cache implemented as set of cache invariant annotations, like: -//sin = function (x:: num)::num; cache(ResultDependsOnArgumentsOnly)// - diff --git a/documentation/Concepts/computation_monads.remarkup b/documentation/Concepts/computation_monads.remarkup deleted file mode 100644 index e69de29..0000000 diff --git a/documentation/Concepts/containers.remarkup b/documentation/Concepts/containers.remarkup deleted file mode 100644 index 3e1602d..0000000 --- a/documentation/Concepts/containers.remarkup +++ /dev/null @@ -1,29 +0,0 @@ -==Introduction== - -A //Containers// is a general name for data structures intended to hold group of elements of certain type. -Considering that almost every program needs containers to store, retrieve, search or otherwise process aggregate data, -obviously efficiency of containers implementation is one of the top priorities for Xreate design. - -Main idea behind containers in Xreate is to gather information on //how containers are used//, inferred from program sources. -On this ground it's possible to choose semi-automatically most appropriate data structure for container implementation to efficiently fullfil particular needs. - - a= [1, 2, 3, 4, 5]:: [num]; impl(solid). //container definition - - b= a[0]:: num; op(randaccess). //operation on container - -In this example, definition of container(variable `a`) offers one or several implementations it supports, that is `impl(solid)` which -is explicilty provided for clarity. On the other side, //retrieving by index// operation(variable `b`) demands certain implementations -to operate. Annotation `op(randaccess)` explicitly describes operation nature, i.e. it requires any data structure that supports //random access// . -Based on gathered information, most appropriate tradeoff //in supply and demand// is applied as given container implementation, i.e. `impl(solid)` in this simple case. - -In order to exppress possible and required implementations, describe operations, constraints and preferences an annotations are used, either manually provided or automatically inferred from program sources. - -==Container definitions== - - - -==Container operations== - -| `map` loop | `op(seqaccess)` | `impl(on_the_fly)`, `impl(solid)` -| `fold` loop | `op(seqaccess)`| `impl(on_the_fly)`, `impl(solid)` -| index retrieving | `op(randaccess` | `impl(solid)` \ No newline at end of file diff --git a/documentation/Concepts/context.remarkup b/documentation/Concepts/context.remarkup deleted file mode 100644 index f619cd3..0000000 --- a/documentation/Concepts/context.remarkup +++ /dev/null @@ -1,263 +0,0 @@ -Data the applications operates with usually stored in memory explicitly 'as-is'. -In pursuit of reducing memory footprint many approaches are developed, such as storing data in packed format and unpacking on-the-fly when needed. -Extreme example of packing is procedural generation when only most basic parameters are stored in memory and actual data generated by predefined algorithms. - -In Xreate **context** is any data(implicitly stored) which could be generated based on parameters reflecting place in the program code or, -to be more precise, place in the [[Analysis/cfa|Control Flow Graph]] of program code, thereby context is data atatched to a code scope. - -===Static context=== -Static context is part of context fully known at the compile-time and thus use no memory for storing context data. - - import raw ("core/control-context.lp") //needed to activate context reasoning - case context::zero { - calculate = function::int {0} //return 0 - } - - case context::one { - calculate = function::int {1} //return 1 - } - - test = function:: int; entry { - context:: one. //set up context, consisting of expression 'one' - calculate() // return 1 - } - -In this example at the moment of executing function //calculate// context (//one//) is fully defined statically(at compile time). -It represents case when information for decision of what specialization of //calculate// to choose requires no memory at all. - -In example below we have only one function specialization: - import raw ("core/control-context.lp")" - - case context:: safe { - funSensitive = function:: int {0} - } - - test = function:: int; entry { - context:: safe. - funcSensitive() - } - -There is only //safe// specialization of funSensitive and code compiles only if function called in expected context(//safe// in this example). - -NOTE:: The example shows that function specialization guards could express requirements(or //contract//)to a context it works within. - -===Context propagation=== -Simplest case is a **nested scope propagation**. The term denotes context propagation from a parent scope to a nested one, or in other words, nested scope inherits parent scope's context. - - import raw ("core/control-context.lp") - - case context::safe { //requires 'safe' context - square = function(x:: int):: int { - x * x - }} - - test = function:: int; entry { - // scopeA - context:: safe; test. - - range = [1..10]:: [int]. - loop fold(range->x::int, 0->acc):: int { - //scopeB - acc + square(x) // In the nested scope 'safe' context still accessable - } - } - -The example demonstrates availability of a `safe` annotation in the nested context of code scope `scopeB` despite being declared in other scope. - -More complicated case is **interfunction context propagation**. This stands for a context propagating through "caller/callee" relation: callee inherits caller context. The example below demonstates this: - - import raw ("core/control-context.lp") - - case context::toMillimeters { - convertConcrete = function(source:: num)::num { - 10 * source - } - } - - case context::toInches { - convertConcrete = function(source:: num)::num { - 2 * source - } - } - - convert= function(source:: num):: num { - convertConcrete(source) - } - - test = function(source:: num):: num; entry { - context:: toMillimeters. - convert(1) - } - -To sort out what's going on here the control flow presented below: -{Fres/diagram-context-propagation-interfunction-static.dia} -There is only one path to reach `convertConcrete` and consequenlty context could be determind statically(on compile-time). -Since root function `test` sets up context `toMillimeters` only one relevant specialization of `convertConcrete` is vaild. - -And now let's consider even more compilcated case with several different context pathes in CFG: -{Fres/diagram-context-propagation-interfunction-mixed, layout=right, float} - - import raw ("core/control-context.lp") - compute = function::int { - 0 - } - - computeFast = function:: int { - context:: computation(fast). - - compute() - } - - computePrecisely = function:: int { - context:: computation(precise). - - compute() - } - - test = function(cmnd:: int):: int; entry { - context:: arithmetic(iee754). - - if (cmnd > 0)::int {computePrecisely()} else {computeFast()} - } - -Here several(that is two) pathes exists to reach function `compute` and moreover each path inroduces its own context. -Statically could be determined only path invariant context annotations or -annotations that are hold for any possible path to a given code scope. - -!!In other words, statically determined context is a conjuction of all possible contexts of a given code scope.!! - -Thus, in the given example only `arithmetic(iee754)` annotattion is statically determined for function `compute` -since it defined in the `test` function which is a root in the CFG(more generally, `test` //dominates// 'compute'). - -===Context rules=== -Full utility of annotations is exposed if provided that we able to infer new annotations or decisions by employing rules of inference. -Given specific and somewhat compilcated nature of context annotations propagation there should be specific rules -that take in account these considerations. - -To put it simple, context rules are rules to extend context by deriving new context annotations from already exisiting ones. - - import raw ("core/control-context.lp") - case context:: toMilli { - convert = function(lengthInCm::int)::int{ - 10 * length - } - } - - main=function::int; entry { - context:: output(milli). - - //here we inroduce context rule(aliasing) - rule context::toMilli - case output(milli) {true} - - convert(1) - } - -See [[Syntax/Annotations#annotation_rules| syntax of annotation rules]] for details. -In this example obvious rule is inroduced having form like `AnnotationOld -> AnnotationNew` meaning //aliasing// to -inroduce `AnnotationNew` as new context annotation whenever `AnnotationNew` holds. - -Host function `main` inroduces context `output(milli)` but callee requires slightly different context for execution(`toMilli`). -Thus, in order to adapt context the rule for introducing //alias// could be applied. As a consequence, context of both functions consists of -`output(milli)` and `toMilli` as well. - -It is obvious, that rule is applicable to an annotations if it defined in the same scope(as in example above) or below, in terms of CFG. - -===Context rules propagation=== -Slightly more complex situation is for rules defined above annotations it applicable to. - import raw ("core/control-context.lp") - case context:: toMilli { - convert = function(lengthInCm::int)::int{ - 10 * length - } - } - - funcIntermediate = function(lengthInCm::int)::int{ - context:: output(milli). - - convert(1) - } - - main=function::int; entry { - //here we inroduce context rule(aliasing) - rule context::toMilli - case output(milli) {true} - - funcIntermediate(1) - } - -Here rule is defined in root function `main` but appropriate annotations for rule are defined in another function(`funcIntermediate`). -In other words, scope's context where rule is defined do not hold relevant annotations and therefore rule produces nothing new for the context. -Reasonable behaviour would be to //inherit// rules as it done for context annotations in order to apply rule whenever possible for nested scopes or for scopes located below in CFG. - -Thus, unlike other rules a context rules implicilty propagated in the same way as it done for annotations. - -===Late context=== -Static scope context reasoning and consequent decisions is too //weak// to be usefull for real world applications, because it could deduce only context annotattions that are guarantied to be always true. -However, for any cases it's cruicial to consider //possible contexts// that is, contexts valid only under certain conditions. - - import raw ("core/control-context.lp") - case context:: computation(fast) { - compute = function:: num { - 0 - } - } - - case context:: computation(precise) { - compute = function:: num { - 0 - } - } - - executeComputation= function:: num { - compute() - } - - test = function(cmnd:: num):: num; entry { - if (cmnd > 0)::num { - context:: computation(fast). - executeComputation() - - } else { - context:: computation(precise). - executeComputation() - } - } - -In this example, static(compile-time) reasoning is fruitless and infer nothing for `compute` scope -because there are two different pathes to reach `compute` from top function(`test`) and moreover each path conducts its own context: -`computation(fast)` through true block of `IF` statement and `computation(precise)` through false block respectively. - -Such uncertainty could be resolved at runtime when one path or another is choosen. -It leads to a necessity of having //late context// - context data gathered on relevant occasion at runtime to determing right decisions. - -To sum up, context consists of two complements parts: on the one hand //static(early) context// denotes compile time inferences, -and on the other hand, //late(dynamic) context// denotes annotations decided upon at runtime. - -===Remarks on late context implementation=== -To return to a last example, in order to correcly determine `compute`'s context it's necessary: - * to infer at compile-time every possible context for given scope - * to store in memory key context data and fully restore particular context whenever needed - -As of now, to convey late context data //a hidden parameter injected to a function signature//. -After such transformation signature of `executeComputation` looks like `executeComputation(__hidden_context_data__)`, -where `hidden_context_data` holds data enough to determine within `executeComputation` which one of possible contexts it encountered with. -Consequently, `executeComputation` decides which specialization of `compute` should be called based on `hidden_context_data` value. - -Only at run-time there is enough information for `executeComputation` to decide what specialization of `compute` to call. - -NOTE: Since it is possible to determine number of possible contexts with diffent outcome decisions, -it is possible to determine least size for late context data enough to identify each possible variant. -(In example above, since there are only two specializons of `compute`, 1 bit is enough to convey late context data) - -===Path dependent late context=== -TODO: fill in this section - -===Context loops=== -TODO: fill in this section - - -See also: - -* [[Articles/gestalts#static_dynamic_antagonism]] -* [[Articles/gestalts#static_dynamic_antagonism#polymorphism]] \ No newline at end of file diff --git a/documentation/Concepts/dsl.remarkup b/documentation/Concepts/dsl.remarkup deleted file mode 100644 index d13092e..0000000 --- a/documentation/Concepts/dsl.remarkup +++ /dev/null @@ -1,198 +0,0 @@ -==Domain specific languages== -DSL allows to express various concepts in very lapidary and concise form. Xreate recognizes and acknowledges very successful and beneficial DSL usage in certain areas, primarily to express //queries// and //configs//, to name a few. -Taking this into account Xreate offers DSL concept by employing //interpretation//. - - -==Interpretation== -Interpretation stands for pre evaluation of program parts that are known at compile time. - - main= function ::int;entry - { - x= "a"::string. - - y= if (x=="b")::string; interpretation(force) - {1} - else {0}. - y - } - -In this example, identifier `y` has annotation `interpretation(force)` to enable compile-time interpretation for `y`. -Consequenlty, function result is `0` with neither memory allocations for string variable `x` nor any computation at runtime. - -There are two annotations reserved to interfere with interpretation process: - -| `interpretation(force)` | Force compiler to apply interpretation for annotated expression, function, function argument| -| `interpretation(suppress)` | Disable interpretation for annotated expression | - -==Eligible Operations== - -| Atomic instructions| numbers, strings, identifiers | -| Relational and logic operators | e.g. `x=="true"`, `x!=0`, operator `and` | -| `if`, `switch` statements |[[#expansion|Statement expansion]] allowed| -| loops statements | [[#expansion|Statement expansion]] allowed | -| `call` statement | [[#function-call-interpreta|Function calls]], [[#partial-function|Partial function call interpretation]]| -| index operator | e.g. `x= [1, 2, 3]. y= x[0]`, `info= {planet="Earth"}. x= info["planet"]`| -| list operators | e.g. `x= [1..10]`, `x=["day", "night"]`| - - -==Expansion== -Expansion stands for partial simplification or elimination of interpretable parts of certain statements. - - test = function(x:: int) :: int; entry { - comm= "inc":: string; interpretation(force). - - y= if (comm == "inc") {x + 1} else {x} - y - } - -In this example, computation of `y` depends on `comm` and `x`. Annotated identifier `comm` should be interpretated but identifier `x` is unknown at compile-time. -Thus, in order to satisfy opposite requierments //expansion// is enabled, i.e. due to possibility of condition interpretation, statement `if` is expanded to a just one of the child blocks, -`x+1` in this example. - -Below more complex example of loop expansion: - - main = function(x:: int):: int; entry { - commands = ["inc", "double", "dec"]:: [string]; interpretation(force). - - loop fold(commands->comm::string, x->operand):: int{ - switch(comm):: int - - case ("inc"){ - operand + 1 - } - - case ("dec"){ - operand - 1 - } - - case ("double"){ - operand * 2 - } - } - } - -We force compiler to interpret variable `commands`. Consequenlty, compiler has no choice but to expand loop in order to get rid of `commands`. Result could be presented as: - - main = function(x:: int):: int; entry { - x(1) = x + 1. - x(2) = x(1) * 2. - x(3) = x(2) - 1. - x(3) - } - -In other words, this mimics famous loop unrolling technique by putting several copies of the loop body in a row, each one for every item of a list of `commands`. - -IMPORTANT: As of now, expansion defined for `if`, `switch`, `loop fold` statements and for functions. - -==Function call interpretation== -Whole function body could be subject of interpretation. - - unwrap= function(data:: undef, keys:: undef):: undef; interpretation(force){ - loop fold(keys->key:: string, data->a):: undef { - a[key] - } - } - - start= function::num; entry{ - result= unwrap( - { - a = { - b = - { - c = "needle" - } - } - }, ["a", "b", "c"])::undef. - - result == "needle" - } - -Here, compiler is informed by respective annotation to interpret `unwrap`. Moreover, all arguments of `unwrap` are fully defined at compile-time and compiler simply replaces function call by calculated value. - -NOTE: In example, an arbitrary undefined type `undef` is used in order to be 100% sure that no compilation occurs, while interpretation pays no attention to a types for now. - -In simple cases interpretation analysis could determine that function is subject of interpretation on its own with no annotation hints provided. - - unwrap= function(data:: undef, keys:: undef):: undef { - loop fold(keys->key:: string, data->a):: undef { - a[key] - } - } - - start= function::num; entry{ - result= unwrap( - { - a = { - b = - { - c = "needle" - } - } - }, ["a", "b", "c"])::undef; interpretation(force). - - result == "needle" - } - -Only difference from example above is lack of annotation hint for `unwrap`. Developer requires interpretation of `result` and compiler accepts such code since analysis find out -that `unwrap` is possible to interpret. - -There are, hovewer, more compilcated cases for analysis: - -|Direct recursion| Analysis is able to correctly find out whether function involving direct recursion(in which a function calls itself) is subject to interpretation | -|Indirect recursion | As of now for processing of indirect recursion( in which a function is called not by itself but by another function) analysis rely on manually provided annotation hints | - -==Partial function call interpretation== -More compilcated case is when some of the function arguments are subject to interpretation and other to a compilation - //partial function interpretation//. - - evaluate= function(argument:: num, code:: string; interpretation(force)):: num { - switch(code)::int - case ("inc") {argument + 1} - case ("dec") {argument - 1} - case ("double") {argument * 2} - case default {argument} - } - - main = function:: int; entry { - commands= ["inc", "double", "dec"]:: [string]; interpretation(force). - - loop fold(commands->comm::string, 10->operand):: int{ - evaluate(operand, comm) - } - } - -Here function `evaluate` is subject to a partial interpretation. To enable partial interpretation for function some of its arguments should be annotated with `interpretation(force)`. -Compiler finds all the distinctive interpretable arguments combinations the given function called with and produces function specializations, each for every finded distinctive arguments combination. - -For this example three different `evaluate` specializations are produced as below: - - evaluate1= function(argument:: num):: num { - argument + 1 - } - - evaluate2= function(argument:: num):: num { - argument * 2 - } - - evaluate3= function(argument:: num):: num { - argument - 1 - } - - main= function:: int; entry { - operand= 10:: int. - - operand(1)= evaluate1(operand). - operand(2)= evaluate2(operand(1)). - operand(3)= evaluate3(operand(2)). - - operand(3) - } - -TODO: find correct term in supercomilation for partial interpretation -TODO: distinctive combinations w.r.t. equivalence relation -TODO: mention oppostion between cloning/ additional arguments - -==On interpretation analysis== -Analysis follows classical type reconstruction algorithms to determine what expressions are subject to an interpretation and check correctness of reconstruction w.r.t. developer-provided annotations. Analysis consists of two general parts: - -| Inference | Infers is it possible to interpret expression based on known decisions for its arguments | -| Unification | Assigns appropriate decision w.r.t. to an previously inferred expectations and developer-provided annotations | \ No newline at end of file diff --git a/documentation/Concepts/effectful computations.remarkup b/documentation/Concepts/effectful computations.remarkup deleted file mode 100644 index 3f0cfca..0000000 --- a/documentation/Concepts/effectful computations.remarkup +++ /dev/null @@ -1,3 +0,0 @@ -Effects: changes and alterations of environment ... unexpected interactions between parts of the program. - -Computations governed by solver in order to verify rules not a concrete computations. \ No newline at end of file diff --git a/documentation/Concepts/exploitation.remarkup b/documentation/Concepts/exploitation.remarkup deleted file mode 100644 index 6589240..0000000 --- a/documentation/Concepts/exploitation.remarkup +++ /dev/null @@ -1,11 +0,0 @@ -Analyzing CFG to find common resource exploitation patterns, -like to determine sites of first and last usage of resources in order to check(provide) safe initialization or releasing. - -**Usecases:** -* resource using in loop: acquire resource right before loop, and freeing right after that. -* group of probable first/last using: every site in the group should treat resource as lazy(with safety check), - and eager otherwise - -**Examples:** -* appending to a file -* memory management \ No newline at end of file diff --git a/documentation/Concepts/interpretation.xml b/documentation/Concepts/interpretation.xml new file mode 100644 index 0000000..7ebcaa2 --- /dev/null +++ b/documentation/Concepts/interpretation.xml @@ -0,0 +1,415 @@ + + + Interpretation + + Interpretation is mode in which Xreate interprets + given program i.e. evaluates, expands and simplifies parts of program based + on information if any known at compilation time. On another hand, + Interpretation is a middle man or intermediate level between Transcend and + Brute levels, it facilitates communication between them by means of + interpreting data of respective layers. It can be further divided into Upper + and Lower Interpretations depending on interacting with which layer we are + focused at the moment. + + main= function:: int; entry +{ + x= "a"::string. + + y= if (x=="b")::string; i12n(on) + {1} else {0}. + y +} + + + In this example, identifier y has annotation + i12(on) which indicates that compiler should use compile-time + interpretation to evaluate y. After simplification, the + function's result is 0 with neither memory allocations for + string variable x nor any computation at runtime. + + There are two annotations reserved to control interpretation + process: + + + + i12n(on) Forces compiler to interpret annotated + expression, function, function argument. It yields error if expression + impossible to interpret + + + + i12n(off) Disables interpretation for annotated + expression + + + +
+ Eligible Expressions + + Currently compiler able to interpret following expressions: + + + + Atomic instructions: numbers, strings, identifiers + + + + Relational and logic operators e.g. x==true, + x!=0 + + + + if, switch statements. + [[#expansion|Statement expansion]] allowed + + + + loop statements. [[#expansion|Statement expansion]] + allowed + + + + Functions. [[#function-call-interpreta|Function calls]], + [[#partial-function|Partial function call interpretation]] + + + + index operator e.g. x= {1, 2, 3}. y= x[0], + info= {planet="Earth"}. x= info["planet"]. + + + + list operators e.g. x= [1..10]. y={"day", + "night"}. + + +
+ +
+ Function Interpretation + + Whole function body could be subject to interpretation if it only + consists of interpretable expressions. + + unwrap = function(data::unknType, keys::unknType):: unknType; i12n(on) +{ + loop fold(keys->key::string, data->record):: unknType + { + record[key] + } +} + +test = function:: bool; entry +{ + book = unwrap({ + Library = { + Shelf = { + Book = "Aristotle's Politics" + }}}, {"Library", "Shelf", "Book"}):: unknType. + + book == "Aristotle's Politics" +} + + + The example demonstrates function unwrap which is + intended to be fully interpretable as depicted by function header + annotation. Obviously, the interpretable function requires all its + arguments be also interpretable. In this case compiler able to calculate + function's result at compile time and nothing of function's body goes to + compiled code. Compiled code looks like(which also optimized out during + consequent compilation phases): + + test = function:: bool; entry +{ + book = "Aristotle's Politics":: string. + book == "Aristotle's Politics" +} + + The example also reveals number of similarities with a dynamically + typed programming languages: + + + + Relaxed types. Notice unknType + type which has not been defined. It's interpreted well because + compiler does not look at type system at all since everything can be + checked at compile time anyway. Interpretation mode is exactly level + where relaxed type system is possible without any penalties during + runtime. + + + + Introspection abilities. Notice how it's + allowed to treat list fields as string keys, so functions like + unwrap can get list field name as a parameter. If list + does not have requested field it just leads to a compilation error and + no hard to catch runtime bugs. + + + + + Additional reason for an arbitrary undefined type + unknType being used in the example is to ensure that no + compilation occurs and everything done on purely interpretation + level + + + In simple cases Interpretation Analysis could determine that + function is subject to interpretation with no annotation hints + provided. + + unwrap = function(data::unknType, keys::unknType):: unknType + { + loop fold(keys->key::string, data->record):: unknType + { + record[key] + } + } + + test = function:: bool; entry + { + book = unwrap({ + Library = { + Shelf = { + Book = "Aristotle's Politics" + }}}, {"Library", "Shelf", "Book"}):: unknType; i12n(on). + + book == "Aristotle's Politics" + } + + + The only difference from example above is lack of annotation hint + for unwrap. Developer requires interpretation of + book variable which in its turn depends on + unwrap. In this case Analysis able to recognize + unwrap is possible to interpret, so no errors occur. + + There are, however, more complicated cases for Interpretation + Analysis: + + + + Direct recursion. Interpretation Analysis is able to correctly + find out whether function involving direct recursion(in which a + function calls itself) is subject to interpretation + + + + Indirect recursion. As of now for processing of indirect + recursion(in which a function is called not by itself but by another + function) analysis usually fails and rely on manually provided + annotation hints + + + + Below is an example of a direct recursion: + + unwrap = function(data:: X):: bool +{ + if (data[0] == "the-end"):: bool + {true} else {unwrap(data[0])} +} + +entry = function:: bool; entry { + unwrap({{{{"the-end"}}}}):: bool; i12n(on) +} + + Function unwrap unwraps nested list until it finds + desired value. No function level annotation required. +
+ +
+ Expansion or Late Interpretation + + Expansion is a partial simplification or elimination of + interpretable parts of certain statements. + + test = function(x:: int):: int; entry { + comm= "inc":: string; i12n(on). + + y= if (comm == "inc"):: int + {x + 1} else {x}. + y +} + + + In this example, computation of y depends on + comm and x. On one side, comm has + an annotation that requires interpretation, on another side x + is unknown at compile-time and can't be interpreted. In this case the only + way to satisfy contradictory requirements is to + expand IF statement, since there is a + possibility to only interpret condition part of the statement, leaving + conditional blocks unchanged. In another words, IF statement + is expanded and just one of the child blocks is + compiled , x+1 in this example based on already known fact + that the other block would never be executed. + + With regard to the fact that expansion leaves some code for + compilation which has to be executed later as opposed to the "pure + interpretation" it can be also called late + interpretation as having runtime footprint. + + Below more complex example of a loop expansion: + + main = function(x:: int):: int; entry { + commands = {"inc", "double", "dec"}:: [string]; i12n(on). + + loop fold(commands->comm::string, x->operand):: int + { + switch(comm):: int + case ("inc") {operand + 1} + case ("dec") {operand - 1} + case ("double") {operand * 2} + } +} + + + commands contains list of operations that should be + interpreted as indicated by corresponding annotation. Operand + x gets assigned at runtime. This is the same situation as in + previous example and triggers expansion as expected. Result after + expansion looks as follows: + + main = function(x:: int):: int; entry { + x{1} = x + 1. + x{2} = x{1} * 2. + x{3} = x{2} - 1. + x{3} +} + + + In other words, this mimics well known loop unrolling technique by + putting several copies of the loop body in a row, each one for every item + of a list of `commands`. + + As of now follow statements support late interpretation: + + + + Branching statements: if, switch, + switch variant, switch late + + + + Loop statements: loop fold + + + + functions + + + + Other operators: query late + + +
+ +
+ Partial or Late Function Interpretation + + Xreate supports case when function has mixed arguments in regard to + interpretation, some should be interpreted, while others - + compiled. + + evaluate= function(argument:: num, code:: string; i12n(on)):: num { + switch(code):: num + case ("inc") {argument + 1} + case ("dec") {argument - 1} + case ("double") {argument * 2} + case default {argument} +} + +main = function(init::int):: int; entry { + commands= {"inc", "double", "dec"}:: [string]; i12n(on). + + loop fold(commands->comm::string, init->operand):: int + { + evaluate(operand, comm) + } +} + + + Looking at function evaluate's signature in this + example we can see only one argument code requires + interpretation. This means that function evaluate is subject + to a partial interpretation or in other words late function + interpretation. To enable late interpretation for function at + least one of its arguments should be annotated as i12n(on). + What compiler does next is to generate number of distinctive + function specializations. Each unique combination of + interpretable argument values corresponds to its own function + specialization. This should be used with cautiousness for compiler can + generate a lot of code for some cases. + + Example above generates three different evaluate + specializations as follows + + evaluate1= function(argument:: num):: num { + argument + 1 +} + +evaluate2= function(argument:: num):: num { + argument * 2 +} + +evaluate3= function(argument:: num):: num { + argument - 1 +} + +main= function(init::int):: int; entry { + operand= init:: int. + + operand{1}= evaluate1(operand). + operand{2}= evaluate2(operand(1)). + operand{3}= evaluate3(operand(2)). + + operand(3) +} + +
+ +
+ Domain Specific Languages and Interpretation + + DSL is an idea of expressing various concepts in a lapidary and + concise form. Xreate recognizes and acknowledges very successful and + beneficial DSL usage in certain areas, primarily to express + queries and configs, to name a + few. It is possible to use interpretation abilities to emulate DSL. + Developer can express desired functionality as a nested lists of numbers, + variants and strings which then processed by partially interpreted + function. Such function in its turn transforms input data into set of low + level compilation instructions so there is no runtime overhead. +
+ +
+ On Interpretation Analysis + + Analysis follows classical type reconstruction algorithms to + determine which expressions are subject to an interpretation and check + correctness of reconstruction w.r.t. developer-provided annotations. + Analysis consists of two general parts: + + + + Inference. Infers is it possible to + interpret expression based on known decisions for its arguments + + + + Unification. Assigns appropriate decision + w.r.t. to a previously inferred expectations and developer-provided + hints as well + + +
+
diff --git a/documentation/Concepts/macroses.remarkup b/documentation/Concepts/macroses.remarkup deleted file mode 100644 index 3433aa4..0000000 --- a/documentation/Concepts/macroses.remarkup +++ /dev/null @@ -1,4 +0,0 @@ -==Macroses== - -Annotation(marks) in order to execute code specific rewriting procedure. -For example for functions marked as "List" the overloaded version should be added to handle containers \ No newline at end of file diff --git a/documentation/Concepts/modules.remarkup b/documentation/Concepts/modules.remarkup deleted file mode 100644 index 8d1c8b6..0000000 --- a/documentation/Concepts/modules.remarkup +++ /dev/null @@ -1 +0,0 @@ - diff --git a/documentation/Concepts/pointers_management.remarkup b/documentation/Concepts/pointers_management.remarkup deleted file mode 100644 index cbb4c31..0000000 --- a/documentation/Concepts/pointers_management.remarkup +++ /dev/null @@ -1,7 +0,0 @@ -Pointers management implementations: - -* scope bounded poinetrs -* parent bounded pointers -* use-aware pointers -* last usage detection -* validptr \ No newline at end of file diff --git a/documentation/Concepts/strings.remarkup b/documentation/Concepts/strings.remarkup deleted file mode 100644 index df0a078..0000000 --- a/documentation/Concepts/strings.remarkup +++ /dev/null @@ -1,5 +0,0 @@ -String implementations: - -* zero-ended char* -* size-aware string -* on-the-fly \ No newline at end of file diff --git a/documentation/Concepts/supervision.remarkup b/documentation/Concepts/supervision.remarkup deleted file mode 100644 index e69de29..0000000 diff --git a/documentation/Concepts/versions.remarkup b/documentation/Concepts/versions.remarkup deleted file mode 100644 index 8d1c8b6..0000000 --- a/documentation/Concepts/versions.remarkup +++ /dev/null @@ -1 +0,0 @@ - diff --git a/documentation/Concepts/views.remarkup b/documentation/Concepts/views.remarkup deleted file mode 100644 index c0fa073..0000000 --- a/documentation/Concepts/views.remarkup +++ /dev/null @@ -1,5 +0,0 @@ -Views: holds related data in consistent way while data changes - -==Methods== -* "delta(difference)" method for supporting view in consistent way - diff --git a/documentation/Concepts/wells_time_machine.remarkup b/documentation/Concepts/wells_time_machine.remarkup deleted file mode 100644 index 3560d1e..0000000 --- a/documentation/Concepts/wells_time_machine.remarkup +++ /dev/null @@ -1,15 +0,0 @@ -* Feature: Run computation on relevant occasion in the future -* Past: Run specific computation prior the moment they needed - -Planning in time. Planning ahead as a powerfull optimisation. -Reordering. - -Example: Caching/Precomputing as reordering - -Example: Late Installation quyestions -Is an instance of Single Responsiiblity(main page) when easier to read/write incorrect program required furher reordering - -For contributors -Idea appeared while working on XML processing by XSLT queries. Many queries usually process the same nodes and idea is to recognize situations when some future queries might need data and cache it beforeheand - - diff --git a/documentation/Internal/Local/d.pdf b/documentation/Internal/Local/d.pdf deleted file mode 100644 index 2309f62..0000000 Binary files a/documentation/Internal/Local/d.pdf and /dev/null differ diff --git a/documentation/Internal/Local/reference.remarkup b/documentation/Internal/Local/reference.remarkup deleted file mode 100644 index 020bfa0..0000000 --- a/documentation/Internal/Local/reference.remarkup +++ /dev/null @@ -1,721 +0,0 @@ -@title Remarkup Reference -@group userguide - -Explains how to make bold text; this makes your words louder so you can win -arguments. - -= Overview = - -Phabricator uses a lightweight markup language called "Remarkup", similar to -other lightweight markup languages like Markdown and Wiki markup. - -This document describes how to format text using Remarkup. - -= Quick Reference = - -All the syntax is explained in more detail below, but this is a quick guide to -formatting text in Remarkup. - -These are inline styles, and can be applied to most text: - - **bold** //italic// `monospaced` ##monospaced## ~~deleted~~ __underlined__ - !!highlighted!! - D123 T123 rX123 # Link to Objects - {D123} {T123} # Link to Objects (Full Name) - {F123} # Embed Images - {M123} # Embed Pholio Mock - @username # Mention a User - #project # Mention a Project - [[wiki page]] # Link to Phriction - [[wiki page | name]] # Named link to Phriction - http://xyz/ # Link to web - [[http://xyz/ | name]] # Named link to web - [name](http://xyz/) # Alternate Link - -These are block styles, and must be separated from surrounding text by -empty lines: - - = Large Header = - - == Smaller Header == - - ## This is a Header As Well - - Also a Large Header - =================== - - Also a Smaller Header - --------------------- - - > Quoted Text - - Use `- ` or `* ` for bulleted lists, and `# ` for numbered lists. - Use ``` or indent two spaces for code. - Use %%% for a literal block. - Use | ... | ... for tables. - -= Basic Styling = - -Format **basic text styles** like this: - - **bold text** - //italic text// - `monospaced text` - ##monospaced text## - ~~deleted text~~ - __underlined text__ - !!highlighted text!! - -Those produce **bold text**, //italic text//, `monospaced text`, ##monospaced -text##, ~~deleted text~~, __underlined text__, and !!highlighted text!! -respectively. - -= Layout = - -Make **headers** like this: - - = Large Header = - - == Smaller Header == - - ===== Very Small Header ===== - - Alternate Large Header - ====================== - - Alternate Smaller Header - ------------------------ - -You can optionally omit the trailing `=` signs -- that is, these are the same: - - == Smaller Header == - - == Smaller Header - -This produces headers like the ones in this document. Make sure you have an -empty line before and after the header. - -Lists -===== - -Make **lists** by beginning each item with a `-` or a `*`: - - lang=text - - milk - - eggs - - bread - - * duck - * duck - * goose - -This produces a list like this: - - - milk - - eggs - - bread - -(Note that you need to put a space after the `-` or `*`.) - -You can make numbered lists with a `#` instead of `-` or `*`: - - # Articuno - # Zapdos - # Moltres - -Numbered lists can also be started with `1.` or `1)`. If you use a number other -than `1`, the list will start at that number instead. For example, this: - -``` - 200) OK - 201) Created - 202) Accepted -``` - -...produces this: - - 200) OK - 201) Created - 202) Accepted - -You can also nest lists: - -```- Body - - Head - - Arm - - Elbow - - Hand - # Thumb - # Index - # Middle - # Ring - # Pinkie - - Leg - - Knee - - Foot``` - -...which produces: - - - Body - - Head - - Arm - - Elbow - - Hand - # Thumb - # Index - # Middle - # Ring - # Pinkie - - Leg - - Knee - - Foot - -If you prefer, you can indent lists using multiple characters to show indent -depth, like this: - -```- Tree --- Branch ---- Twig``` - -As expected, this produces: - -- Tree --- Branch ---- Twig - -You can add checkboxes to items by prefacing them with `[ ]` or `[X]`, like -this: - -``` - - [X] Preheat oven to 450 degrees. - - [ ] Zest 35 lemons. -``` - -When rendered, this produces: - - - [X] Preheat oven to 450 degrees. - - [ ] Zest 35 lemons. - -Make **code blocks** by indenting two spaces: - - f(x, y); - -You can also use three backticks to enclose the code block: - - ```f(x, y); - g(f);``` - -You can specify a language for syntax highlighting with `lang=xxx`: - - lang=text - lang=html - ... - -This will highlight the block using a highlighter for that language, if one is -available (in most cases, this means you need to configure Pygments): - - lang=html - ... - -You can also use a `COUNTEREXAMPLE` header to show that a block of code is -bad and shouldn't be copied: - - lang=text - COUNTEREXAMPLE - function f() { - global $$variable_variable; - } - -This produces a block like this: - - COUNTEREXAMPLE - function f() { - global $$variable_variable; - } - -You can use `lines=N` to limit the vertical size of a chunk of code, and -`name=some_name.ext` to give it a name. For example, this: - - lang=text - lang=html, name=example.html, lines=12, counterexample - ... - -...produces this: - - lang=html, name=example.html, lines=12, counterexample -

Apple

-

Apricot

-

Avocado

-

Banana

-

Bilberry

-

Blackberry

-

Blackcurrant

-

Blueberry

-

Currant

-

Cherry

-

Cherimoya

-

Clementine

-

Date

-

Damson

-

Durian

-

Eggplant

-

Elderberry

-

Feijoa

-

Gooseberry

-

Grape

-

Grapefruit

-

Guava

-

Huckleberry

-

Jackfruit

-

Jambul

-

Kiwi fruit

-

Kumquat

-

Legume

-

Lemon

-

Lime

-

Lychee

-

Mandarine

-

Mango

-

Mangostine

-

Melon

- - -You can use the `NOTE:`, `WARNING:` or `IMPORTANT:` elements to call attention -to an important idea. - -For example, write this: - -``` -NOTE: Best practices in proton pack operation include not crossing the streams. -``` - -...to produce this: - -NOTE: Best practices in proton pack operation include not crossing the streams. - -Using `WARNING:` or `IMPORTANT:` at the beginning of the line changes the -color of the callout: - -WARNING: Crossing the streams can result in total protonic reversal! - -IMPORTANT: Don't cross the streams! - -In addition, you can use `(NOTE)`, `(WARNING)`, or `(IMPORTANT)` to get the -same effect but without `(NOTE)`, `(WARNING)`, or `(IMPORTANT)` appearing in -the rendered result. For example, this callout uses `(NOTE)`: - -(NOTE) Dr. Egon Spengler is the best resource for additional proton pack - questions. - - -Dividers -======== - -You can divide sections by putting three or more dashes on a line by -themselves. This creates a divider or horizontal rule similar to an `
` -tag, like this one: - ---- - -The dashes need to appear on their own line and be separated from other -content. For example, like this: - -``` -This section will be visually separated. - ---- - -On an entirely different topic, ... -``` - - -= Linking URIs = - -URIs are automatically linked: http://phabricator.org/ - -If you have a URI with problematic characters in it, like -"`http://comma.org/,`", you can surround it with angle brackets: - - - -This will force the parser to consume the whole URI: - -You can also use create named links, where you choose the displayed text. These -work within Phabricator or on the internet at large: - - [[/herald/transcript/ | Herald Transcripts]] - [[http://www.boring-legal-documents.com/ | exciting legal documents]] - -Markdown-style links are also supported: - - [Toil](http://www.trouble.com) - -= Linking to Objects = - -You can link to Phabricator objects, such as Differential revisions, Diffusion -commits and Maniphest tasks, by mentioning the name of an object: - - D123 # Link to Differential revision D123 - rX123 # Link to SVN commit 123 from the "X" repository - rXaf3192cd5 # Link to Git commit "af3192cd5..." from the "X" repository. - # You must specify at least 7 characters of the hash. - T123 # Link to Maniphest task T123 - -You can also link directly to a comment in Maniphest and Differential: - - T123#4 # Link to comment #4 of T123 - -See the Phabricator configuraton setting `remarkup.ignored-object-names` to -modify this behavior. - -= Embedding Objects - -You can also generate full-name references to some objects by using braces: - - {D123} # Link to Differential revision D123 with the full name - {T123} # Link to Maniphest task T123 with the full name - -These references will also show when an object changes state (for instance, a -task or revision is closed). Some types of objects support rich embedding. - -== Linking to Project Tags - -Projects can be linked to with the use of a hashtag `#`. This works by default -using the name of the Project (lowercase, underscored). Additionally you -can set multiple additional hashtags by editing the Project details. - - #qa, #quality_assurance - -== Embedding Mocks (Pholio) - -You can embed a Pholio mock by using braces to refer to it: - - {M123} - -By default the first four images from the mock set are displayed. This behavior -can be overridden with the **image** option. With the **image** option you can -provide one or more image IDs to display. - -You can set the image (or images) to display like this: - - {M123, image=12345} - {M123, image=12345 & 6789} - -== Embedding Pastes - -You can embed a Paste using braces: - - {P123} - -You can adjust the embed height with the `lines` option: - - {P123, lines=15} - -You can highlight specific lines with the `highlight` option: - - {P123, highlight=15} - {P123, highlight="23-25, 31"} - -== Embedding Images - -You can embed an image or other file by using braces to refer to it: - - {F123} - -In most interfaces, you can drag-and-drop an image from your computer into the -text area to upload and reference it. - -Some browsers (e.g. Chrome) support uploading an image data just by pasting them -from clipboard into the text area. - -You can set file display options like this: - - {F123, layout=left, float, size=full, alt="a duckling"} - -Valid options for all files are: - - - **layout** left (default), center, right, inline, link (render a link - instead of a thumbnail for images) - - **name** with `layout=link` or for non-images, use this name for the link - text - - **alt** Provide alternate text for assistive technologies. - -Image files support these options: - - - **float** If layout is set to left or right, the image will be floated so - text wraps around it. - - **size** thumb (default), full - - **width** Scale image to a specific width. - - **height** Scale image to a specific height. - -Audio and video files support these options: - - - **media**: Specify the media type as `audio` or `video`. This allows you - to disambiguate how file format which may contain either audio or video - should be rendered. - - **loop**: Loop this media. - - **autoplay**: Automatically begin playing this media. - -== Embedding Countdowns - -You can embed a countdown by using braces: - - {C123} - -= Quoting Text = - -To quote text, preface it with an `>`: - - > This is quoted text. - -This appears like this: - -> This is quoted text. - -= Embedding Media = - -If you set a configuration flag, you can embed media directly in text: - - - **remarkup.enable-embedded-youtube**: allows you to paste in YouTube videos - and have them render inline. - -This option is disabled by default because it has security and/or -silliness implications. Carefully read the description before enabling it. - -= Image Macros = - -You can upload image macros (More Stuff -> Macro) which will replace text -strings with the image you specify. For instance, you could upload an image of a -dancing banana to create a macro named "peanutbutterjellytime", and then any -time you type that string on a separate line it will be replaced with the image -of a dancing banana. - -= Memes = - -You can also use image macros in the context of memes. For example, if you -have an image macro named `grumpy`, you can create a meme by doing the -following: - - {meme, src = grumpy, above = toptextgoeshere, below = bottomtextgoeshere} - -By default, the font used to create the text for the meme is `tuffy.ttf`. For -the more authentic feel of `impact.ttf`, you simply have to place the Impact -TrueType font in the Phabricator subfolder `/resources/font/`. If Remarkup -detects the presence of `impact.ttf`, it will automatically use it. - -= Mentioning Users = - -In Differential and Maniphest, you can mention another user by writing: - - @username - -When you submit your comment, this will add them as a CC on the revision or task -if they aren't already CC'd. - -Icons -===== - -You can add icons to comments using the `{icon ...}` syntax. For example: - - {icon camera} - -This renders: {icon camera} - -You can select a color for icons: - - {icon camera color=blue} - -This renders: {icon camera color=blue} - -For a list of available icons and colors, check the UIExamples application. -(The icons are sourced from -[[ http://fortawesome.github.io/Font-Awesome/ | FontAwesome ]], so you can also -browse the collection there.) - -You can add `spin` to make the icon spin: - - {icon cog spin} - -This renders: {icon cog spin} - - -= Phriction Documents = - -You can link to Phriction documents with a name or path: - - Make sure you sign and date your [[legal/Letter of Marque and Reprisal]]! - -By default, the link will render with the document title as the link name. -With a pipe (`|`), you can retitle the link. Use this to mislead your -opponents: - - Check out these [[legal/boring_documents/ | exciting legal documents]]! - -Links to pages which do not exist are shown in red. Links to pages which exist -but which the viewer does not have permission to see are shown with a lock -icon, and the link will not disclose the page title. - -If you begin a link path with `./` or `../`, the remainder of the path will be -evaluated relative to the current wiki page. For example, if you are writing -content for the document `fruit/` a link to `[[./guava]]` is the same as a link -to `[[fruit/guava]]` from elsewhere. - -Relative links may use `../` to transverse up the document tree. From the -`produce/vegetables/` page, you can use `[[../fruit/guava]]` to link to the -`produce/fruit/guava` page. - -Relative links do not work when used outside of wiki pages. For example, -you can't use a relative link in a comment on a task, because there is no -reasonable place for the link to start resolving from. - -When documents are moved, relative links are not automatically updated: they -are preserved as currently written. After moving a document, you may need to -review and adjust any relative links it contains. - - -= Literal Blocks = - -To place text in a literal block use `%%%`: - - %%%Text that won't be processed by remarkup - [[http://www.example.com | example]] - %%% - -Remarkup will not process the text inside of literal blocks (other than to -escape HTML and preserve line breaks). - -= Tables = - -Remarkup supports simple table syntax. For example, this: - -``` -| Fruit | Color | Price | Peel? -| ----- | ----- | ----- | ----- -| Apple | red | `$0.93` | no -| Banana | yellow | `$0.19` | **YES** -``` - -...produces this: - -| Fruit | Color | Price | Peel? -| ----- | ----- | ----- | ----- -| Apple | red | `$0.93` | no -| Banana | yellow | `$0.19` | **YES** - -Remarkup also supports a simplified HTML table syntax. For example, this: - -``` - - - - - - - - - - - - - - - - - - - -
FruitColorPricePeel?
Applered`$0.93`no
Bananayellow`$0.19`**YES**
-``` - -...produces this: - - - - - - - - - - - - - - - - - - - - -
FruitColorPricePeel?
Applered`$0.93`no
Bananayellow`$0.19`**YES**
- -Some general notes about this syntax: - - - your tags must all be properly balanced; - - your tags must NOT include attributes (`` is OK, `` is - not); - - you can use other Remarkup rules (like **bold**, //italics//, etc.) inside - table cells. - -Navigation Sequences -==================== - -You can use `{nav ...}` to render a stylized navigation sequence when helping -someone to locate something. This can be useful when writing documentation. -For example, you could give someone directions to purchase lemons: - -{nav icon=home, name=Home > -Grocery Store > -Produce Section > -icon=lemon-o, name=Lemons} - -To render this example, use this markup: - -``` -{nav icon=home, name=Home > -Grocery Store > -Produce Section > -icon=lemon-o, name=Lemons} -``` - -In general: - - - Separate sections with `>`. - - Each section can just have a name to add an element to the navigation - sequence, or a list of key-value pairs. - - Supported keys are `icon`, `name`, `type` and `href`. - - The `type` option can be set to `instructions` to indicate that an element - is asking the user to make a choice or follow specific instructions. - -Keystrokes -========== - -You can use `{key ...}` to render a stylized keystroke. For example, this: - -``` -Press {key M} to view the starmap. -``` - -...renders this: - -> Press {key M} to view the starmap. - -You can also render sequences with modifier keys. This: - -``` -Use {key command option shift 3} to take a screenshot. -Press {key down down-right right LP} to activate the hadoken technique. -``` - -...renders this: - -> Use {key command option shift 3} to take a screenshot. -> Press {key down down-right right LP} to activate the hadoken technique. - - -= Fullscreen Mode = - -Remarkup editors provide a fullscreen composition mode. This can make it easier -to edit large blocks of text, or improve focus by removing distractions. You can -exit **Fullscreen** mode by clicking the button again or by pressing escape. diff --git a/documentation/Internal/Local/remarkup-examples.remarkup b/documentation/Internal/Local/remarkup-examples.remarkup deleted file mode 100644 index 24e66c0..0000000 --- a/documentation/Internal/Local/remarkup-examples.remarkup +++ /dev/null @@ -1,721 +0,0 @@ -@title Remarkup Reference -@group userguide - -Explains how to make bold text; this makes your words louder so you can win -arguments. - -= Overview = - -Phabricator uses a lightweight markup language called "Remarkup", similar to -other lightweight markup languages like Markdown and Wiki markup. - -This document describes how to format text using Remarkup. - -= Quick Reference = - -All the syntax is explained in more detail below, but this is a quick guide to -formatting text in Remarkup. - -These are inline styles, and can be applied to most text: - - **bold** //italic// `monospaced` ##monospaced## ~~deleted~~ __underlined__ - !!highlighted!! - D123 T123 rX123 # Link to Objects - {D123} {T123} # Link to Objects (Full Name) - {F123} # Embed Images - {M123} # Embed Pholio Mock - @username # Mention a User - #project # Mention a Project - [[wiki page]] # Link to Phriction - [[wiki page | name]] # Named link to Phriction - http://xyz/ # Link to web - [[http://xyz/ | name]] # Named link to web - [name](http://xyz/) # Alternate Link - -These are block styles, and must be separated from surrounding text by -empty lines: - - = Large Header = - - == Smaller Header == - - ## This is a Header As Well - - Also a Large Header - =================== - - Also a Smaller Header - --------------------- - - > Quoted Text - - Use `- ` or `* ` for bulleted lists, and `# ` for numbered lists. - Use ``` or indent two spaces for code. - Use %%% for a literal block. - Use | ... | ... for tables. - -= Basic Styling = - -Format **basic text styles** like this: - - **bold text** - //italic text// - `monospaced text` - ##monospaced text## - ~~deleted text~~ - __underlined text__ - !!highlighted text!! - -Those produce **bold text**, //italic text//, `monospaced text`, ##monospaced -text##, ~~deleted text~~, __underlined text__, and !!highlighted text!! -respectively. - -= Layout = - -Make **headers** like this: - - = Large Header = - - == Smaller Header == - - ===== Very Small Header ===== - - Alternate Large Header - ====================== - - Alternate Smaller Header - ------------------------ - -You can optionally omit the trailing `=` signs -- that is, these are the same: - - == Smaller Header == - - == Smaller Header - -This produces headers like the ones in this document. Make sure you have an -empty line before and after the header. - -Lists -===== - -Make **lists** by beginning each item with a `-` or a `*`: - - lang=text - - milk - - eggs - - bread - - * duck - * duck - * goose - -This produces a list like this: - - - milk - - eggs - - bread - -(Note that you need to put a space after the `-` or `*`.) - -You can make numbered lists with a `#` instead of `-` or `*`: - - # Articuno - # Zapdos - # Moltres - -Numbered lists can also be started with `1.` or `1)`. If you use a number other -than `1`, the list will start at that number instead. For example, this: - -``` - 200) OK - 201) Created - 202) Accepted -``` - -...produces this: - - 200) OK - 201) Created - 202) Accepted - -You can also nest lists: - -```- Body - - Head - - Arm - - Elbow - - Hand - # Thumb - # Index - # Middle - # Ring - # Pinkie - - Leg - - Knee - - Foot``` - -...which produces: - - - Body - - Head - - Arm - - Elbow - - Hand - # Thumb - # Index - # Middle - # Ring - # Pinkie - - Leg - - Knee - - Foot - -If you prefer, you can indent lists using multiple characters to show indent -depth, like this: - -```- Tree --- Branch ---- Twig``` - -As expected, this produces: - -- Tree --- Branch ---- Twig - -You can add checkboxes to items by prefacing them with `[ ]` or `[X]`, like -this: - -``` - - [X] Preheat oven to 450 degrees. - - [ ] Zest 35 lemons. -``` - -When rendered, this produces: - - - [X] Preheat oven to 450 degrees. - - [ ] Zest 35 lemons. - -Make **code blocks** by indenting two spaces: - - f(x, y); - -You can also use three backticks to enclose the code block: - - ```f(x, y); - g(f);``` - -You can specify a language for syntax highlighting with `lang=xxx`: - - lang=text - lang=html - ... - -This will highlight the block using a highlighter for that language, if one is -available (in most cases, this means you need to configure Pygments): - - lang=html - ... - -You can also use a `COUNTEREXAMPLE` header to show that a block of code is -bad and shouldn't be copied: - - lang=text - COUNTEREXAMPLE - function f() { - global $$variable_variable; - } - -This produces a block like this: - - COUNTEREXAMPLE - function f() { - global $$variable_variable; - } - -You can use `lines=N` to limit the vertical size of a chunk of code, and -`name=some_name.ext` to give it a name. For example, this: - - lang=text - lang=html, name=example.html, lines=12, counterexample - ... - -...produces this: - - lang=html, name=example.html, lines=12, counterexample -

Apple

-

Apricot

-

Avocado

-

Banana

-

Bilberry

-

Blackberry

-

Blackcurrant

-

Blueberry

-

Currant

-

Cherry

-

Cherimoya

-

Clementine

-

Date

-

Damson

-

Durian

-

Eggplant

-

Elderberry

-

Feijoa

-

Gooseberry

-

Grape

-

Grapefruit

-

Guava

-

Huckleberry

-

Jackfruit

-

Jambul

-

Kiwi fruit

-

Kumquat

-

Legume

-

Lemon

-

Lime

-

Lychee

-

Mandarine

-

Mango

-

Mangostine

-

Melon

- - -You can use the `NOTE:`, `WARNING:` or `IMPORTANT:` elements to call attention -to an important idea. - -For example, write this: - -``` -NOTE: Best practices in proton pack operation include not crossing the streams. -``` - -...to produce this: - -NOTE: Best practices in proton pack operation include not crossing the streams. - -Using `WARNING:` or `IMPORTANT:` at the beginning of the line changes the -color of the callout: - -WARNING: Crossing the streams can result in total protonic reversal! - -IMPORTANT: Don't cross the streams! - -In addition, you can use `(NOTE)`, `(WARNING)`, or `(IMPORTANT)` to get the -same effect but without `(NOTE)`, `(WARNING)`, or `(IMPORTANT)` appearing in -the rendered result. For example, this callout uses `(NOTE)`: - -(NOTE) Dr. Egon Spengler is the best resource for additional proton pack - questions. - - -Dividers -======== - -You can divide sections by putting three or more dashes on a line by -themselves. This creates a divider or horizontal rule similar to an `
` -tag, like this one: - ---- - -The dashes need to appear on their own line and be separated from other -content. For example, like this: - -``` -This section will be visually separated. - ---- - -On an entirely different topic, ... -``` - - -= Linking URIs = - -URIs are automatically linked: http://phabricator.org/ - -If you have a URI with problematic characters in it, like -"`http://comma.org/,`", you can surround it with angle brackets: - - - -This will force the parser to consume the whole URI: - -You can also use create named links, where you choose the displayed text. These -work within Phabricator or on the internet at large: - - [[/herald/transcript/ | Herald Transcripts]] - [[http://www.boring-legal-documents.com/ | exciting legal documents]] - -Markdown-style links are also supported: - - [Toil](http://www.trouble.com) - -= Linking to Objects = - -You can link to Phabricator objects, such as Differential revisions, Diffusion -commits and Maniphest tasks, by mentioning the name of an object: - - D123 # Link to Differential revision D123 - rX123 # Link to SVN commit 123 from the "X" repository - rXaf3192cd5 # Link to Git commit "af3192cd5..." from the "X" repository. - # You must specify at least 7 characters of the hash. - T123 # Link to Maniphest task T123 - -You can also link directly to a comment in Maniphest and Differential: - - T123#4 # Link to comment #4 of T123 - -See the Phabricator configuraton setting `remarkup.ignored-object-names` to -modify this behavior. - -= Embedding Objects - -You can also generate full-name references to some objects by using braces: - - {D123} # Link to Differential revision D123 with the full name - {T123} # Link to Maniphest task T123 with the full name - -These references will also show when an object changes state (for instance, a -task or revision is closed). Some types of objects support rich embedding. - -== Linking to Project Tags - -Projects can be linked to with the use of a hashtag `#`. This works by default -using the name of the Project (lowercase, underscored). Additionally you -can set multiple additional hashtags by editing the Project details. - - #qa, #quality_assurance - -== Embedding Mocks (Pholio) - -You can embed a Pholio mock by using braces to refer to it: - - {M123} - -By default the first four images from the mock set are displayed. This behavior -can be overridden with the **image** option. With the **image** option you can -provide one or more image IDs to display. - -You can set the image (or images) to display like this: - - {M123, image=12345} - {M123, image=12345 & 6789} - -== Embedding Pastes - -You can embed a Paste using braces: - - {P123} - -You can adjust the embed height with the `lines` option: - - {P123, lines=15} - -You can highlight specific lines with the `highlight` option: - - {P123, highlight=15} - {P123, highlight="23-25, 31"} - -== Embedding Images - -You can embed an image or other file by using braces to refer to it: - - {F123} - -In most interfaces, you can drag-and-drop an image from your computer into the -text area to upload and reference it. - -Some browsers (e.g. Chrome) support uploading an image data just by pasting them -from clipboard into the text area. - -You can set file display options like this: - - {F123, layout=left, float, size=full, alt="a duckling"} - -Valid options for all files are: - - - **layout** left (default), center, right, inline, link (render a link - instead of a thumbnail for images) - - **name** with `layout=link` or for non-images, use this name for the link - text - - **alt** Provide alternate text for assistive technologies. - -Image files support these options: - - - **float** If layout is set to left or right, the image will be floated so - text wraps around it. - - **size** thumb (default), full - - **width** Scale image to a specific width. - - **height** Scale image to a specific height. - -Audio and video files support these options: - - - **media**: Specify the media type as `audio` or `video`. This allows you - to disambiguate how file format which may contain either audio or video - should be rendered. - - **loop**: Loop this media. - - **autoplay**: Automatically begin playing this media. - -== Embedding Countdowns - -You can embed a countdown by using braces: - - {C123} - -= Quoting Text = - -To quote text, preface it with an `>`: - - > This is quoted text. - -This appears like this: - -> This is quoted text. - -= Embedding Media = - -If you set a configuration flag, you can embed media directly in text: - - - **remarkup.enable-embedded-youtube**: allows you to paste in YouTube videos - and have them render inline. - -This option is disabled by default because it has security and/or -silliness implications. Carefully read the description before enabling it. - -= Image Macros = - -You can upload image macros (More Stuff -> Macro) which will replace text -strings with the image you specify. For instance, you could upload an image of a -dancing banana to create a macro named "peanutbutterjellytime", and then any -time you type that string on a separate line it will be replaced with the image -of a dancing banana. - -= Memes = - -You can also use image macros in the context of memes. For example, if you -have an image macro named `grumpy`, you can create a meme by doing the -following: - - {meme, src = grumpy, above = toptextgoeshere, below = bottomtextgoeshere} - -By default, the font used to create the text for the meme is `tuffy.ttf`. For -the more authentic feel of `impact.ttf`, you simply have to place the Impact -TrueType font in the Phabricator subfolder `/resources/font/`. If Remarkup -detects the presence of `impact.ttf`, it will automatically use it. - -= Mentioning Users = - -In Differential and Maniphest, you can mention another user by writing: - - @username - -When you submit your comment, this will add them as a CC on the revision or task -if they aren't already CC'd. - -Icons -===== - -You can add icons to comments using the `{icon ...}` syntax. For example: - - {icon camera} - -This renders: {icon camera} - -You can select a color for icons: - - {icon camera color=blue} - -This renders: {icon camera color=blue} - -For a list of available icons and colors, check the UIExamples application. -(The icons are sourced from -[[ http://fortawesome.github.io/Font-Awesome/ | FontAwesome ]], so you can also -browse the collection there.) - -You can add `spin` to make the icon spin: - - {icon cog spin} - -This renders: {icon cog spin} - - -= Phriction Documents = - -You can link to Phriction documents with a name or path: - - Make sure you sign and date your [[legal/Letter of Marque and Reprisal]]! - -By default, the link will render with the document title as the link name. -With a pipe (`|`), you can retitle the link. Use this to mislead your -opponents: - - Check out these [[legal/boring_documents/ | exciting legal documents]]! - -Links to pages which do not exist are shown in red. Links to pages which exist -but which the viewer does not have permission to see are shown with a lock -icon, and the link will not disclose the page title. - -If you begin a link path with `./` or `../`, the remainder of the path will be -evaluated relative to the current wiki page. For example, if you are writing -content for the document `fruit/` a link to `[[./guava]]` is the same as a link -to `[[fruit/guava]]` from elsewhere. - -Relative links may use `../` to transverse up the document tree. From the -`produce/vegetables/` page, you can use `[[../fruit/guava]]` to link to the -`produce/fruit/guava` page. - -Relative links do not work when used outside of wiki pages. For example, -you can't use a relative link in a comment on a task, because there is no -reasonable place for the link to start resolving from. - -When documents are moved, relative links are not automatically updated: they -are preserved as currently written. After moving a document, you may need to -review and adjust any relative links it contains. - - -= Literal Blocks = - -To place text in a literal block use `%%%`: - - %%%Text that won't be processed by remarkup - [[http://www.example.com | example]] - %%% - -Remarkup will not process the text inside of literal blocks (other than to -escape HTML and preserve line breaks). - -= Tables = - -Remarkup supports simple table syntax. For example, this: - -``` -| Fruit | Color | Price | Peel? -| ----- | ----- | ----- | ----- -| Apple | red | `$0.93` | no -| Banana | yellow | `$0.19` | **YES** -``` - -...produces this: - -| Fruit | Color | Price | Peel? -| ----- | ----- | ----- | ----- -| Apple | red | `$0.93` | no -| Banana | yellow | `$0.19` | **YES** - -Remarkup also supports a simplified HTML table syntax. For example, this: - -``` - - - - - - - - - - - - - - - - - - - -
FruitColorPricePeel?
Applered`$0.93`no
Bananayellow`$0.19`**YES**
-``` - -...produces this: - - - - - - - - - - - - - - - - - - - - -
FruitColorPricePeel?
Applered`$0.93`no
Bananayellow`$0.19`**YES**
- -Some general notes about this syntax: - - - your tags must all be properly balanced; - - your tags must NOT include attributes (`` is OK, `` is - not); - - you can use other Remarkup rules (like **bold**, //italics//, etc.) inside - table cells. - -Navigation Sequences -==================== - -You can use `{nav ...}` to render a stylized navigation sequence when helping -someone to locate something. This can be useful when writing documentation. -For example, you could give someone directions to purchase lemons: - -{nav icon=home, name=Home > -Grocery Store > -Produce Section > -icon=lemon-o, name=Lemons} - -To render this example, use this markup: - -``` -{nav icon=home, name=Home > -Grocery Store > -Produce Section > -icon=lemon-o, name=Lemons} -``` - -In general: - - - Separate sections with `>`. - - Each section can just have a name to add an element to the navigation - sequence, or a list of key-value pairs. - - Supported keys are `icon`, `name`, `type` and `href`. - - The `type` option can be set to `instructions` to indicate that an element - is asking the user to make a choice or follow specific instructions. - -Keystrokes -========== - -You can use `{key ...}` to render a stylized keystroke. For example, this: - -``` -Press {key M} to view the starmap. -``` - -...renders this: - -> Press {key M} to view the starmap. - -You can also render sequences with modifier keys. This: - -``` -Use {key command option shift 3} to take a screenshot. -Press {key down down-right right LP} to activate the hadoken technique. -``` - -...renders this: - -> Use {key command option shift 3} to take a screenshot. -> Press {key down down-right right LP} to activate the hadoken technique. - - -= Fullscreen Mode = - -Remarkup editors provide a fullscreen composition mode. This can make it easier -to edit large blocks of text, or improve focus by removing distractions. You can -exit **Fullscreen** mode by clicking the button again or by pressing escape. diff --git a/documentation/Internal/documentation-style.remarkup b/documentation/Internal/documentation-style.remarkup deleted file mode 100644 index 7e46602..0000000 --- a/documentation/Internal/documentation-style.remarkup +++ /dev/null @@ -1,3 +0,0 @@ -multi word designations or names should be lowercase and minus separated - -Example: ##very-long-function-name## diff --git a/documentation/Objectives/Adaptability/highlevel.remarkup b/documentation/Objectives/Adaptability/highlevel.remarkup deleted file mode 100644 index f724e71..0000000 --- a/documentation/Objectives/Adaptability/highlevel.remarkup +++ /dev/null @@ -1,5 +0,0 @@ -High-level: - -*Focus on current task -*Program Addtitivity -*Reduce refactoring needs \ No newline at end of file diff --git a/documentation/Objectives/Adaptability/refactoring.remarkup b/documentation/Objectives/Adaptability/refactoring.remarkup deleted file mode 100644 index 5623b2a..0000000 --- a/documentation/Objectives/Adaptability/refactoring.remarkup +++ /dev/null @@ -1,4 +0,0 @@ -Refactoring - ability to quiclky adjust and apply software to a different tasks - -reduce refactoring dimensions by 2. -2D refactoring: (rigid-soft software axe, memory-computation on the fly axe) is unnecessary and covered by additive annotations. \ No newline at end of file diff --git a/documentation/Objectives/Optimization/component_level_optimization.remarkup b/documentation/Objectives/Optimization/component_level_optimization.remarkup deleted file mode 100644 index 4f97ef7..0000000 --- a/documentation/Objectives/Optimization/component_level_optimization.remarkup +++ /dev/null @@ -1,26 +0,0 @@ -У цій роботі розглядаються техніки, що представляють собою, у відмін- -ність від низькорівневих оптимізацій, зазвичай реалізованих у сучасних -компіляторах, більш абстрактний рівень компонентної оптимізації, пов'язаної -з агрегуванням і спільною взаємодією різних незалежних компонентів -усередині однієї програми. -Як правило, стандартні компоненти написані й підтримуються без -врахування того середовища в якому вони працюють у рамках кінцевої кліє- -нтської програми, тому просте їх комбінування зазвичай малоефективне й -затратно по швидкодії і пам'яті. - -, а також для мов високого рівня, що просто не надають про- -грамісту можливість «ретельно» налаштувати використовувані компоненти. - -Зазвичай, при розробці програм, оптимізації такого рівня проводяться -вручну програмістом, що, як було показано вище(у розділі 1.1), має ряд недо- -ліків. - - -There are ways for component level optimization - - state recognition (example with take (1, sort()) ) - - process recognition (example with addin one element to sorted contaier. extract CHANGES = ADDED_ELEMENT) - - State recogniton usually requires reasoning about functions, code scopes in other words CFA. To support this Xreate provides Context. - Process recogniton usually requires reasoning about variables and its transformations, in other words DFA. To support this Xreate provide variable annotations. - - To summarize, everything about component level optimization revolves around efforts to recognize states and processes. Nothing else. diff --git a/documentation/Objectives/Optimization/index.remarkup b/documentation/Objectives/Optimization/index.remarkup deleted file mode 100644 index e69de29..0000000 diff --git a/documentation/Objectives/Reliability/access_control.remarkup b/documentation/Objectives/Reliability/access_control.remarkup deleted file mode 100644 index 5f163ef..0000000 --- a/documentation/Objectives/Reliability/access_control.remarkup +++ /dev/null @@ -1 +0,0 @@ -access rights/usage control \ No newline at end of file diff --git a/documentation/Objectives/Reliability/bugs_and_review_management.remarkup b/documentation/Objectives/Reliability/bugs_and_review_management.remarkup deleted file mode 100644 index a3fb1d1..0000000 --- a/documentation/Objectives/Reliability/bugs_and_review_management.remarkup +++ /dev/null @@ -1,3 +0,0 @@ -* review triggers based on conditions -* review after related code is changed -* enable/disabled parts of code depening on external libs bugs status fetched from bugtracker, etc \ No newline at end of file diff --git a/documentation/Objectives/Reliability/component_guaranties.remarkup b/documentation/Objectives/Reliability/component_guaranties.remarkup deleted file mode 100644 index 7088aa8..0000000 --- a/documentation/Objectives/Reliability/component_guaranties.remarkup +++ /dev/null @@ -1,2 +0,0 @@ -components guaranties/invariants(expressed among other things by unit-tests). -Additionally, comply with whole infrastructure specifications&requirements(like a only permitted opened ports, etc) \ No newline at end of file diff --git a/documentation/Objectives/Reliability/index.remarkup b/documentation/Objectives/Reliability/index.remarkup deleted file mode 100644 index e69de29..0000000 diff --git a/documentation/Objectives/Reliability/krivyakin.remarkup b/documentation/Objectives/Reliability/krivyakin.remarkup deleted file mode 100644 index e69de29..0000000 diff --git a/documentation/Objectives/Reliability/metrics.remarkup b/documentation/Objectives/Reliability/metrics.remarkup deleted file mode 100644 index 4eb1570..0000000 --- a/documentation/Objectives/Reliability/metrics.remarkup +++ /dev/null @@ -1 +0,0 @@ -software metrics based on frame's scores \ No newline at end of file diff --git a/documentation/Objectives/Reliability/pointers_safety.remarkup b/documentation/Objectives/Reliability/pointers_safety.remarkup deleted file mode 100644 index b601d91..0000000 --- a/documentation/Objectives/Reliability/pointers_safety.remarkup +++ /dev/null @@ -1,3 +0,0 @@ -safety checks against invalid values (like validptr, etc) - -NOTE: there is unfinished query/ptrvalid.* in the file tree \ No newline at end of file diff --git a/documentation/Objectives/Reliability/unit-tests.remarkup b/documentation/Objectives/Reliability/unit-tests.remarkup deleted file mode 100644 index ae3cf58..0000000 --- a/documentation/Objectives/Reliability/unit-tests.remarkup +++ /dev/null @@ -1 +0,0 @@ -Each unit-test expresses code constraints/invariants(states, etc) in declarative form. Unit-tests could be checked statically as well as dynamically. \ No newline at end of file diff --git a/documentation/Objectives/Reliability/virtualization.remarkup b/documentation/Objectives/Reliability/virtualization.remarkup deleted file mode 100644 index fbfd527..0000000 --- a/documentation/Objectives/Reliability/virtualization.remarkup +++ /dev/null @@ -1 +0,0 @@ -virtualization(override external resources invokes, dependency injection) \ No newline at end of file diff --git a/documentation/Objectives/index.remarkup b/documentation/Objectives/index.remarkup deleted file mode 100644 index 8d1c8b6..0000000 --- a/documentation/Objectives/index.remarkup +++ /dev/null @@ -1 +0,0 @@ - diff --git a/documentation/Syntax/Annotations/index.remarkup b/documentation/Syntax/Annotations/index.remarkup deleted file mode 100644 index 46d9783..0000000 --- a/documentation/Syntax/Annotations/index.remarkup +++ /dev/null @@ -1,3 +0,0 @@ -==Annotations== - -==Annotation rules== \ No newline at end of file diff --git a/documentation/Syntax/Interfaces/adhoc.remarkup b/documentation/Syntax/Interfaces/adhoc.remarkup deleted file mode 100644 index e69de29..0000000 diff --git a/documentation/Syntax/Interfaces/cfa.remarkup b/documentation/Syntax/Interfaces/cfa.remarkup deleted file mode 100644 index e69de29..0000000 diff --git a/documentation/Syntax/Interfaces/dfa.remarkup b/documentation/Syntax/Interfaces/dfa.remarkup deleted file mode 100644 index e69de29..0000000 diff --git a/documentation/Syntax/Interfaces/extern_c.remarkup b/documentation/Syntax/Interfaces/extern_c.remarkup deleted file mode 100644 index e69de29..0000000 diff --git a/documentation/Syntax/Interfaces/index.remarkup b/documentation/Syntax/Interfaces/index.remarkup deleted file mode 100644 index e69de29..0000000 diff --git a/documentation/Syntax/control-flow-statements.remarkup b/documentation/Syntax/control-flow-statements.remarkup deleted file mode 100644 index b9deedd..0000000 --- a/documentation/Syntax/control-flow-statements.remarkup +++ /dev/null @@ -1,132 +0,0 @@ -==Control flow statements== - -These statements control execution flow of a program. - -=== If-Else === -The If-Else statement executes a //main-expression// branch if a specified condition is true. -If the condition is false, //alternative-expression// branch will be executed. - -SYNTAX: if (//condition//):: //type// -{ - [//declaration//. [ //declaration//.]... ] - //main-expression// -} else { - [//declaration//. [ //declaration//.]... ] - //alternative-expression// -} - -//condition// -Bool type expression(see [[types]]) in order to decide which branch of IF-ELSE statement should be executed. - -//main expression// -Executed if condition yelds ##true## - -//alternative expression// -Executed if condition yelds ##false## - -Example: - x = if (y<0) :: num - {-1} else {1} - -===Switch=== -Executes one of the given branches depending on condition. - -SYNTAX: switch (//condition//) :: //type-of-switch// -[case //variant// { - [declaration. [ declaration.]... ] - //transformation-expression// -}]... - -//condition// -Expression to determing which case branch should be executed - -//type-of-switch// -Type of switch result - -//variant// -Expression to compare against //condition//. -If the //condition// evaluation result corresponds to the //variant// then a relevant branch is executed. -Special label **default** is allowed and designates default branch executed if no other branches are selected. - -//transformation-expression// -Determines result of a switch statement if relevant branch is selected based on //condition//. - -Example: - x = 2:: num. - - y = switch (x) ::string - case 0 {"zero"} - case 1 {"one"} - case 2 {"two"} - case default {"unknown"} - - - -===Map loop=== -Iterates over input collection and stores result in another collection. -Every input collection's value transformed using //transformation-expression//. - -SYNTAX: loop map ( //input-collection// -> //alias// :: //type-of-element//) :: //type-of-collection// -{ - [declaration. [ declaration.]... ] - //transformation-expression// -} - -//input-collection// -Variable or expression to designate collection for transformation - -//alias// -Variable name to designate current collection element in scope of inner code block - -//type-of-element// -Type of collection's element - -//type-of-collection// -Type of resulting transformed collection - -//transformation-expression// -Transformation applied to an every collection element - -Example: - input = [1..10]. - twice = loop map (input -> x:: num):: [num] - { 2 * x } - -===Fold loop=== -Iterates over input collection in order to accumulate result by applying //transformation-expression// to each element and intermediate accumulator. - -SYNTAX: loop fold (//input-collection// -> //alias// :: //type-of-element//, //accumulator//->//accumulator-alias//) :: //type-of-accumulator// -{ - [declaration. [ declaration.]... ] - //transformation-expression// -} - -//input-collection// -Variable or expression to designate collection - -//alias// -Variable name to designate current collection element in scope of inner code block - -//type-of-element// -Type of collection's element - -//accumulator// -Expression to evaluate initial value of accumulator - -//accumulator-alias// -Variable name to designate current value of accumulator in scope of inner code block - -//type-of-accumulator// -Type of folding result - -//transformation-expression// -Expression applied to an every collection's element and current state of accumulator in order to -calculate accumulator value for next step of iteration. - -This is an example: - - numbers = [1..10] :: [num]. - sumOfNumbers = loop fold(numbers->x; 0->result) - {result + x} - - diff --git a/documentation/Syntax/functions.remarkup b/documentation/Syntax/functions.remarkup deleted file mode 100644 index 48af284..0000000 --- a/documentation/Syntax/functions.remarkup +++ /dev/null @@ -1,18 +0,0 @@ -==Functions== - -Xreate allows to define functions with a list of zero or more parameters and sequence of a statements as a body. - -SYNTAX: //name// = function [ (param:: type [, param:: type]... ) ] :: type; [; tag-expression ...] -{ - [declaration. [ declaration.] ] - result-expression -} - -NOTE: There is alse special function syntax. See [[Syntax/prefunctions]] - -This is an example of a simple function: - sum = function(a:: num, b:: num):: num { - a + b - } - - \ No newline at end of file diff --git a/documentation/Syntax/index.remarkup b/documentation/Syntax/index.remarkup deleted file mode 100644 index 5467fe4..0000000 --- a/documentation/Syntax/index.remarkup +++ /dev/null @@ -1,22 +0,0 @@ -This section devoted to a syntax description - -In general, syntax follows SSA form: every symbol has a single site of assignment. - -SYNTAX: -{ - [declaration.]... - //result-expression// -} - -Example: - { - t = Pi / 2 :: num. - left = sin(2 * t):: num. - right = cos(8 * t):: num. - - left + right // result expression - } - -SSA form being very simple and intuitive, however does not posssess expressiveness enough to cope -with more compilcated cases like [[loops | control-flow-statements]]. That's why there are specific syntax constructions -provided in order to keep basic SSA syntax but with different semantics suited for those compicated cases. \ No newline at end of file diff --git a/documentation/Syntax/modules.xml b/documentation/Syntax/modules.xml new file mode 100644 index 0000000..0803122 --- /dev/null +++ b/documentation/Syntax/modules.xml @@ -0,0 +1,256 @@ + + + Modules + + Xreate offers modules as a way to organize and + reuse source code. For simplicity, it's implemented as one file—one + module. + + Modules often require prior compilation of other modules for correct + work. It leads to a problem of a resolution where + required module is located. Especially since modern software products + usually have complicated and volatile file structure depending on exact + configuration and platform to build. Common practice is to rely on build + configuration tools to provide exact path for each module. + + For this reason Xreate interferes as little as possible with + resolution. Language does not support for module to directly specify any + path be it relative or absolute of other required modules. Also compiler + does not search modules in some predefined list of directories and does not + assume anything about project's file structure. It expects resolution + information already fully defined before compilation. + + However compiler has optional built-in functionality to facilitate + resolution. It is the very kind of problems the transcend level suited + excellently for. It is modeled as supply and demand + approach and lets modules to declare what they provide + and what require expressed by annotations. Compiler + then tries to satisfy requirements and find a match. Alternatively, external + tools always can be used. + +
+ Module Headers + + SYNTAX: + +module [:: //annotations-list// ] (Full form) +{ + //module-statement//... +} + +module :: //annotations-list// . (Simplified form) + +module-statement ::= + | require ( //annotation// ). (1) + | discover ( //path// ). (2) + | controller (//path//). (3) + + + + annotations-list List of annotations delimited by + semicolon + + + + annotation Any valid transcend expression + + + + path Absolute or relative path to controller + + + + Xreate recognizes number of module management statements. Those + statements should be located in specific section module {...} + of a source code which is called module header. + Module can have several headers. All headers gathered from a whole file + are combined into one before actual processing. + + + Modules processing happens before compilation. It means any data + produced in course of compilation is inaccessible at this stage + +
+ +
+ Requesting Modules + + Statement require(..) expresses which modules are + required for correct compilation. + + module { + require(logger). +} + + In this example module in question requires some other module that + provides feature called logger. There is + no way to specify direct external module location. Instead, module + expresses requirement in abstract form as propositional expression which + is later used by resolution to find exact match. + + module{require(stringslib).} +processString = function(a:: string):: string +{ + someStrFunc(a) +} + +module{require(mathlib).} +processNumber = function(a:: num):: num +{ + someMathFunc(a) +} + + Example above demonstrates using several headers in one file. It's + particularly useful if developer finds it convenient to put requirements + near the actual code that uses it. This way it can be easily spotted when + requirements are no more needed. After all, code locality improves + readability. +
+ +
+ Module Annotations + + Module can declare additional information for various uses. This is + expressed by annotations located in the header. They are called module + annotations. For instance, module annotations can be used by module + resolution to find modules that satisfy requirements of others. + + module:: status(obsolete). + + The example shows module that declares its status. It can be used by + resolution to choose most appropriate module out of number of candidates. + One way to view annotations used by resolution is to treat them as + something that module provides. + + + There are no predefined module annotations and developer can put + arbitrary information there. + +
+ +
+ Modules Resolution + + Modules resolution is a process to find exact modules locations that + match requests. Compiler does not search modules in predefined directories + and does not assume anything about project's file structure. In order to + allow developer to determine it themselves the compiler refers to two + transcend tables + + SYNTAX: + modules_resolution(//request//, //module-resolved//). (1) + modules_resolution(//request//, //module-resolved//, //module-context//). (2) + + + + request annotation used in statement + request(...) + + + + module-resolved Path or identifier of a + module that matches request + + + + module-context Path or identifier of a + module that requires other module + + + + These tables contain resolved modules for all possible requests. + Form (1) contains requests that should always be resolved to the same + module. Form (2) contains such requests for which resolution depends on + requesting module module-context. + + modules_resolution(numlib, "/path/to/numlib"). + modules_resolution(strings, "/path/to/ansi-lib", "moduleA"). + modules_resolution(strings, "/path/to/utf8-lib", "moduleB"). + + For the example above the compiler would always resolve path to + numerical lib(numlib) as "/path/to/numlib" (line 1). However + strings library would be resolved as "/path/to/ansi-lib" if + requested in moduleA(line 2) and as "/path/to/utf8-lib" if + requested in moduleB(line 3). + + When compiler encounters module request it looks up table + modules_resolution (first or second form) to find path of the + requested module. Tables can be populated by any means be it either + transcend reasoning or external tools. + + + There is no defined order or priority or fallback behavior while + looking into tables. If the same request occurs in both tables they are + considered to be ill-formed + +
+ +
+ Advanced Modules Resolution + + Xreate provide additional layer, optional helper to simplify modules + management. It introduces two more built-in statements that can be used in + module header: Discover statement and + Controller Statement. + + + + Discover Statement has the form + discover (path).It allows to specify + directory where compiler would recursively search for all xreate files + and extract module header annotations. It gathers info about all found + source files. + + + + Controller Statement has the form + controller (path) and specifies path + to modules resolution controller. Controller is a file that contains + transcend rules in order to process data gathered by discovery and + populate resolution tables as its result of work. + + + + Example below shows 3 modules: + + //First Module +module:: + name(testA); + provide(superService); + status(needToTestEvenMore). + +//Second Module +module:: + name(testB); + provide(superService); + status(needToTest). + +//Third Module +module { + require(superService). + discover(“/modules/path/”). + controller(“/path/to/controller”). +} + + Two modules offer the same feature + provide(superSerivce). Third module requires it and specifies + directory where to look up for needed files. Controller's task is to + populate resolution table if needed module is found and choose appropriate + candidate, if more than one module offer this service. + + One way to decide what to choose in this example is to look at + status of both modules. Let score be assigned to each possible status. + Let's say 0 for status(needToTestEvenMore), + 1 for status(needToTest). Then controller would + proceed with the best scoring module, Second Module in this + case. +
+
diff --git a/documentation/Syntax/packages.remarkup b/documentation/Syntax/packages.remarkup deleted file mode 100644 index 46b5187..0000000 --- a/documentation/Syntax/packages.remarkup +++ /dev/null @@ -1 +0,0 @@ -package dependencies \ No newline at end of file diff --git a/documentation/Syntax/syntax.xml b/documentation/Syntax/syntax.xml new file mode 100644 index 0000000..84567ba --- /dev/null +++ b/documentation/Syntax/syntax.xml @@ -0,0 +1,639 @@ + + + Syntax + + + + + + Literals, Expressions, Basic Statements + + Annotations + + Intrinsics: query + + + + Identifiers, Code Blocks + + Branch Statements + + Interfaces: Extern-C + + + + Functions + + Loops + + Other: Transcend, Versions + + + + Types + + Variants + + + + + + + + There are number of principles Xreate syntax based on: + + + + Follows SSA form: each identifier is defined only once and no + redefinitions allowed + + + + Order in which identifiers are defined does not influence + computation order. Identifiers are computed in order based on + dependencies between expressions. Order in which identifiers are defines + reflects preferences and what is convenient for a developer. + + + +
+ Literals and expressions + + In Xreate expressions have a form: + + SYNTAX: +//expression// [:: //type//; //annotations-list// ] + + where annotation-list is a list of annotations + delimited by semicolon. + + Expressions consist of literals and various operations as + follows: + + + + + + + + + + Literals + + numbers, strings: 5, "Nimefurahi + kukujua" + + + + Lists, records + + Record is a collection of elements of different types - + {year = 1934, month = "april"}. List is a collection + of elements of the same type without keys - {16, 8, + 3} + + + + Arithmetic operations + + Basic arithmetic operations: +, -, *, + / + + + + Relations + + ==, !=, <>, <, <=, >, >=. + Both !=, <> mean not equal + relation. Examples: 8>=3, "Blue" <> + "Green" + + + + List and struct operations + + index operation to access individual + elements of a list or a record. Example: colors = {"Green", + "Blue"}::[string]. color = colors[0]:: string. Record's + element access: date = {year = 1934, month = "april"}. year + = date["year"] + + + + Identifiers + + Example: a - b + + + + Functions + + Example: result = isOdd(6). + + + + +
+ +
+ Code Blocks + + Block is a list of expressions delimited by period. It has a + body - main expression and optionally some identifier + definitions. + + SYNTAX: +{ + [//ident// = //expression// . | //body-expression// . ].. +} + + In order to compute code block the compiler search a body expression + - only one expression that does not have assignment in that block. Result + of body computation used as a result of block computation. If any + expression includes identifiers they are computed first. + + { + a = 10:: int. + b = 2:: int. + + a + b:: int +} + + Above is an example of code block which have a+b as a + body expression. In this case body depends on identifiers a, + b so compiler computes both of them beforehand. + + Computation order depends only on dependencies between expressions. + This approach has properties as follows: + + + + Mutually independent identifiers can be evaluated in any + order + + + + Identifier gets computed only if it's required by block body + expression or other required identifier + + +
+ +
+ Functions + + SYNTAX: +//function-name// = function ([//argument//:: //type//[; //annotation-list//]]...):: //return-type// [; //annotations//]... +//function-block// + + + + function-name name of function + + + + argument formal parameter. Arguments + delimited by comma. + + + + type, return-type + formal parameter and returning value types + + + + function-block code block that holds + function definition + + + + annotations list of annotations delimited + by semicolon + + + + Below is an example of a simple function sum. It has + two arguments and returns their sum. Also it has few annotations. First + annotation entry has a special meaning - it depicts entry + point or main function in a program. Second annotation + status(needs_review) is an example that developers can + annotate function using custom annotations to express different + properties. + + sum = function(x:: int, y:: int):: int; entry; status(needs_review) +{ + x+y +} +
+ +
+ Branch Statements + +
+ IF Statement + + SYNTAX: +if (//condition//):: //type// [; //annotations// ].. + //block-true// + else + //block-false// + + IF statement executes block-true or + block-false depending on + condition evaluation result. + + Example: + + answer = if (question == "Favorite color?"):: string + {"Yellow"} else {"Don't know"}. +
+ +
+ SWITCH Statement + + switch ( //condition// ) :: //type// [; //annotations//].. +[case ( //guard// ) code-block].. +case default //default-code-block// + + + + + condition's result is used to decide + which branch to execute next + + + + guard value to match against + condition + + + + default-code-block executed if no + appropriate cases found + + + + SWITCH statement evaluation's result is that of branch whose + guard matches + condition. + + Example: + + monthName = switch(monthNum) :: string + case (1) {"Jan"} + case (2) {"Feb"} + case default {"Strange.. Don't know this month"}. +
+
+ +
+ Loop Statements + +
+ LOOP Statement + + SYNTAX: +loop ( //init-value// -> //accumulator// ) //loop-body// + + + + init-value initial value loop starts + from + + + + accumulator identifier which holds loop's + result after each iteration + + + + For each iteration accumulator assumes result + of previous iteration or init-value during first + iteration. Result of the loop-body evaluation is + used as accumulator's next iteration value and as + overall loop statement result after the last iteration. + + This notation does not have termination condition. Compiler relies + on loop body fixed point in order to decide when to interrupt loop. + Let's consider example: + + //infinite loop +answer = loop (2->x) :: int +{ + if(IsPerfect(x)):: int {x} else {x+1} +}. + + The example tests numbers for being perfect(sum of all proper + divisors equals to the number itself). While iterating accumulator + x assumes values as follows: 2, 3, 4, 5, 6, 6 ... After it + founds first perfect number any further iteration do not change result + anymore since there is no increment and it continues to test the same + number again and again. Obviously, x=6 is a fixed point in + this example. There is no point to continue going through further + iterations once fixed point is evaluated and hence loop can be safely + interrupted. + + Compiler relies on manually provided annotations to recognize when + fixed point is reached. There is special annotation final + to specify fixed point for loops. Once expression marked as + final gets evaluated it's assumed to be fixed point or in + other words compiler knows it's the very last iteration after which loop + ends. Correct code for the example above is: + + //loop exits after first perfect number is found +answer2 = loop (2->x) :: int +{ + if(IsPerfect(x))::int {x:: int; final} else {x+1} +}. + + In this case compiler able to recognize when fixed point is + reached to exit loop. After loops is done answer is + 6. +
+ +
+ LOOP FOLD Statement + + SYNTAX: +loop fold (//list// -> //element//:: //type// [; //annotations//], //init-value// -> //accumulator//):: //type// [; //annotations//] + //loop-body// + + + + list to iterate through + + + + element identifier that assumes value of + currently processed list element + + + + type, annotations + expression types and optional annotations delimited by + semicolon + + + + init-value accumulator's initial value + loop starts with + + + + accumulator identifier assumes loop-body + evaluation result after each iteration + + + + Iterates over list and stores intermediate + result in accumulator. Overall loop value is a + accumulator's value after the last iteration. If fixed point is found + during execution terminates earlier. + + numbers = {4, 8, 7, 1, 5}:: [int]. +min = loop fold(numbers->x:: int, 10->acc):: int +{ + if (acc > x):: int {x} else {acc} +}. + + Example shows code excerpt that looks for a minimal element in the + given list(and less then initial value 10). +
+ +
+ LOOP MAP Statement + + SYNTAX: +loop map ( //list// -> //element// :: //type// [; //annotations// ] ) :: //type// [; //annotations// ] + //loop-body// + + + + list to iterate through + + + + element identifier that assumes value of + currently processed list element + + + + type, annotations + type and optional annotations delimited by semicolon. + + + + loop-body + + + + Iterates over list and creates another list with elements that are + results of a transformation by loop-body of + iterated elements of the given list. + + odd_numbers = {1, 3, 5}:: [int]. +even_numbers = loop map(odd_numbers->number::int) :: [int] + { 2 * number }. + + Example demonstrates creating even_number list by + multiplying by 2 every element of odd_numbers. +
+
+ +
+ Types + + Primitive Types + + + + + + + + + + num + + i32 alias. Reserved for auto detected most + appropriate either integral of floating-point number type + + + + int + + i32 alias. Reserved for auto detected most + appropriate integral number type + + + + float + + Double precision floating-point number + + + + bool + + Boolean type + + + + i8, i32, i64 + + Signed integers. 8, 32, 64 bit wide respectively + + + + string + + Pointer to a null terminated ANSI char string. Reserved for + auto detected most appropriate string type. + + + + * + + Unspecified type. Example x = {amount=200, + currency="USD"}::*. + + + + + + Compound types: + + + + + + + + + + [ element-type ] + + List of elements of the same type + element-type. Example: [int] - + list of int's + + + + {key:: + type, ...} + + List of elements of different type possibly with named + keys. Examples: {int, string}, {name::string, + age::int} + + + + variant {option :: + (type, ...}, ...} + + Holds a single element of type of one out of number of + options. Examples: variant {FullAddress:: {string, string, + string}, ShortAddress:: {string}} + + + + slave identifier + + Type determined by Transcend. Example: slave + unit_test + + + + compound-type [ + key ] + + Accessing elements of compound type. Example: Bio = + type {birth_year:: int, name:: string}. Year = type + Bio[birth_year]. + + + + + + New types defined as: + + type-name = type (parameters...) type-definition . + + Example: + + Tuple = type {string, int}. +Int = type Tuple[1]. //accessing by index +
+ +
+ Variants and SWITCH VARIANT Instruction + + SYNTAX: +switch variant ( condition [-> alias ] [:: type [; annotations... ] ] ) :: type [; annotations... ] +[ case ( guard ) case-branch ]... + + + + condition expression of variant type + + + + alias identifier to denote unwrapped + content of condition withing case branches. + + + + guard name of variant to match against + actual condition's variant + + + + case-branch block of code to execute in + case of matched variant. Content is accessible by using alias Within + the branch . + + + + Sometimes it is useful for a variable to have value of different + types depending on some conditions, in other words it has + variant type. + + Let's consider example with variable month of + variant type Month: + + Month = type variant { + MonName:: {string}, + MonNumber:: {int} +}. + +month = MonName("April"):: Month. + + Variable month holds value of either + string or int type. Value is not accessible + directly. It should be unwrapped before using. Xreate + supports switch variant instruction for this + operation. + + As an example below is nextMonth function + definition: + + nextMonth = funcrtion(month:: Month):: Month +{ + switch variant(month):: Month + case (MonName) + { + // + } + case + +} +
+
diff --git a/documentation/Syntax/types.remarkup b/documentation/Syntax/types.remarkup deleted file mode 100644 index e69de29..0000000 diff --git a/documentation/development/files.remarkup b/documentation/development/files.remarkup deleted file mode 100644 index c6dc0a3..0000000 --- a/documentation/development/files.remarkup +++ /dev/null @@ -1,46 +0,0 @@ -|Filename|Description|Unit-tests -| ----- | ----- | ----- -| analysis/cfagraph.*, /pass/cfapass.* | [[Analysis/cfa|CFA]] | tests/cfa.cpp -| analysis/DominatorsTreeAnalysisProvider.* | [[Analysis/dominators_analysis|Dominators analysis]] | tests/cfa.cpp -| query/context.* |[[Concepts/context|CFA/Context support]] | tests/context.cpp -| compilation/latecontextcompiler2.*, serialization/expressionserializer* | [[Concepts/context#late-context|Late context support]] | tests/context.cpp, tests/ExpressionSerializer.cpp -| src/contextrule.h | [[Concepts/context#context-rules|Context rules support]] | -| analysis/dfagraph.*, /pass/dfapass.* | [[Analysis/dfa|DFA]] | tests/dfa.cpp -| compilation/advanced.* | Additional constructions compilation | -| compilation/containers.*, query/containers.* |[[Concepts/containers|Containers support]]|tests/containers.cpp -| pass/interpretationpass.*, compilation/targetinterpretation.* | [[Concepts/dsl|DSL/Interpretation]] | tests/interpretation.cpp -| pass/adhocpass.*| [[Concepts/adhocs|"Adhocs" feature support]] |tests/adhoc.cpp -| src/ast.*, pass/compilepass.* | [[Syntax|Main compilation routines]] | tests/compilation.cpp, tests/basic.cpp, tests/loops.cpp, tests/ast.cpp, tests/types.cpp -| pass/loggerpass.* | Logging support | -| pass/rulespass.* | logic rules support | -| src/transcendlayer.* | [[Articles/logic_inference|Logic inference support]] | -| src/llvmlayer.* | Low level byte code compilation| -| src/ExternLayer.* | Foreign Function Interface(FFI/C) support | tests/externc.cpp -| src/passmanager.* | Manages analysis and compilation passes| - - ---- -analysis - file:///private/prg/code/xreate/cpp/src/analysis/aux.h - file:///private/prg/code/xreate/cpp/src/analysis/aux.cpp - -compilation - file:///private/prg/code/xreate/cpp/src/compilation/targets.h - file:///private/prg/code/xreate/cpp/src/compilation/transformations.h - file:///private/prg/code/xreate/cpp/src/compilation/transformations.cpp - -pass/ - file:///private/prg/code/xreate/cpp/src/pass/abstractpass.h - file:///private/prg/code/xreate/cpp/src/pass/abstractpass.cpp - -query: - -src - src/attachments.* - file:///private/prg/code/xreate/cpp/src/serialization.h - file:///private/prg/code/xreate/cpp/src/utils.h - -tests - file:///private/prg/code/xreate/cpp/tests/testClangAPI.cpp - file:///private/prg/code/xreate/cpp/tests/testJson.cpp - file:///private/prg/code/xreate/cpp/tests/testLibXml2.cpp diff --git a/documentation/development/index.remarkup b/documentation/development/index.remarkup deleted file mode 100644 index e69de29..0000000 diff --git a/documentation/index.remarkup b/documentation/index.remarkup deleted file mode 100644 index f35aacc..0000000 --- a/documentation/index.remarkup +++ /dev/null @@ -1,20 +0,0 @@ -1. Main idea behind Xreate is to employ logic inference to address practical day-to-day programming problems. -2. Xreate's programs blend adaptability and safety found in high-level languages with computational efficiency and small memory footprint found in low-level ones - -Xreate focused on: - -Adaptability. Easy to write, support, adapt, adjust components or whole program to comply with new changed requirements or environment in general. -Single Responsibility. Sere SSA in lexic, Time Mahine. - - -Lexic. Xreate borrows as much lexic from existing top ranked languages as possible to have immediatly recognizible code -No cryptic symbols found in hacker languages. -Builtin operators overload is a powerfull technique ound in some languages isn't suported for many developers got confused. Current advice is to use DSL. -However it's for community to decide. - -Optimization -Zero-overhead abstractions - -Safety. Program correctness and safeguards in compilcated cases - -Virtualization \ No newline at end of file diff --git a/documentation/res/diagram-context-propagation-interfunction-mixed.dia b/documentation/res/diagram-context-propagation-interfunction-mixed.dia deleted file mode 100644 index 7344d2a..0000000 Binary files a/documentation/res/diagram-context-propagation-interfunction-mixed.dia and /dev/null differ diff --git a/documentation/res/diagram-context-propagation-interfunction-static.dia b/documentation/res/diagram-context-propagation-interfunction-static.dia deleted file mode 100644 index 0625f96..0000000 Binary files a/documentation/res/diagram-context-propagation-interfunction-static.dia and /dev/null differ diff --git a/documentation/res/diagram-logic_inference-overview.dia b/documentation/res/diagram-logic_inference-overview.dia deleted file mode 100644 index 4ed194b..0000000 Binary files a/documentation/res/diagram-logic_inference-overview.dia and /dev/null differ diff --git a/grammar/modules.ATG b/grammar/modules.ATG index 43aaacf..0dbb88f 100644 --- a/grammar/modules.ATG +++ b/grammar/modules.ATG @@ -1,96 +1,97 @@ #include "modules.h" COMPILER Modules ModuleRecord module; int nextToken() { scanner->ResetPeek(); return scanner->Peek()->kind; } bool checkParametersList() { return la->kind == _ident && nextToken() == _lparen; } CHARACTERS letter = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz". digit = "0123456789". any = ANY - '"'. cr = '\r'. lf = '\n'. tab = '\t'. TOKENS string = '"' { any } '"'. ident = (letter | '_') {letter | digit | '_'}. lparen = '('. + tagcolon = "::". COMMENTS FROM "/*" TO "*/" NESTED COMMENTS FROM "//" TO lf IGNORE cr + lf + tab PRODUCTIONS Block = '{' { string | Block | ANY } '}'. Modules = { ModulesInterface | SkipXreateOperators }. -ModulesInterface = "module" '{' - {ModulesStatement} -'}'. +ModulesInterface = "module" (. Expression query; .) + [ tagcolon MetaSimpExpr (. module.addProperty(query); .) + {';' MetaSimpExpr (. module.addProperty(query); .) + }] + ('{' {ModulesStatement} '}' | '.'). + -ModulesStatement = (. std::wstring path; Expression query; .) -( "require" '(' MetaSimpExpr ')' '.' (. module.addModuleQuery(query); .) - - | "include" "controller" '(' string (. module.addControllerPath(Atom(t->val).get()); .) - ')' '.' +ModulesStatement = (. std::wstring path; Expression query; .) +( "require" '(' MetaSimpExpr ')' '.' (. module.addRequest(query); .) + | "controller" '(' string (. module.addControllerPath(Atom(t->val).get()); .) + ')' '.' | "discover" '(' string (. module.addDiscoveryPath(Atom(t->val).get()); .) - ')' '.' - | MetaSimpExpr '.' (. module.addProperty(query); .) + ')' '.' ). MetaSimpExpr= (. Expression e2; .) ( '-' MetaSimpExpr (. e = Expression(Operator::NEG, {e2}); .) -| IF(checkParametersList()) ident (. e = Expression(Operator::CALL, {Expression(Atom(t->val))}); .) - '(' [ MetaCalleeParams ] ')' -| ident (. e = Expression(Atom(t->val)); .) +| ident (. e = Expression(Operator::CALL, {Expression(Atom(t->val))}); .) + ['(' MetaCalleeParams ')' ] ). MetaCalleeParams = (. Expression e2; .) MetaSimpExpr (. e.addArg(Expression(e2)); .) {',' MetaSimpExpr (. e.addArg(Expression(e2)); .) }. SkipXreateOperators = { "rule" {ANY} Block | "interface" {ANY} Block | "import" {ANY} '.' | "case" "context" {ANY} Block - | {ANY} '=' + | ident '=' ( "function" {ANY} Block | "type" {ANY} '.' ) }. END Modules. diff --git a/grammar/xreate.ATG b/grammar/xreate.ATG index c7fde77..c8660e7 100644 --- a/grammar/xreate.ATG +++ b/grammar/xreate.ATG @@ -1,710 +1,707 @@ //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; std::string field; .) ( TList -| TStruct +| TRecord | TVariant | TSlave | TypeTerm (. typ = typ3; .) | IF (checkIndex()) Ident lbrack 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] | '*' (.typ = TypeAnnotation(); .) ) . TypeIndex = ( number (. name = Atom(t->val).get(); .) | string (. name = Atom(t->val).get(); .) ) . TList = (. TypeAnnotation ty; .) - lbrack Type rbrack (. typ = TypeAnnotation(TypeOperator::LIST, {ty}); .) + lbrack Type rbrack (. typ = TypeAnnotation(TypeOperator::LIST_ARRAY, {ty}); .) . -TStruct = (. TypeAnnotation t; std::wstring key; size_t keyCounter=0; .) +TRecord = (. 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()); .) + ) (. typ = TypeAnnotation(TypeOperator::LIST_RECORD, {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}); .) + (. + 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.addBindings({Atom(varEl)}); + block->addBinding(Atom(varEl), move(tagsEl)); + .) + BDecl<&*block> + (. e.addBlock(block); .) + + | "fold" 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 - (. + .) + tagcolon ExprAnnotations + (. block->addBinding(Atom(varEl), move(tagsEl)); block->addBinding(Atom(varAcc), Expression()); - .) - BDecl<&*block> - (. e.addBlock(block); .) - ) -). + .) + BDecl<&*block> + (. e.addBlock(block); .) + | lparen Expr implic Ident rparen + (. + e = Expression(Operator::INF, {eAcc}); + e.addBindings({Atom(varAcc)}); + block->addBinding(Atom(varAcc), Expression()); + .) + tagcolon ExprAnnotations 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 | "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)); .) + "include" ListLiteral 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 */.) + | ListLiteral + | ListRangeLiteral | 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; .) +ListLiteral = (. 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}); .) + ) (. keys.push_back(Atom(key)); e = Expression(Operator::LIST, {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. +ListRangeLiteral = (. Expression eFrom, eTo; .) + lbrack Expr ".." Expr rbrack (. e = Expression(Operator::LIST_RANGE, {eFrom, eTo}); .) +. + 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. +SkipModulesSection = "module" {ANY} (lcurbrack {ANY} rcurbrack | '.'). END Xreate. diff --git a/scripts/containers/Containers_Implementation_LinkedList1.xreate b/scripts/containers/Containers_Implementation_LinkedList1.xreate index 6e26185..7808a4b 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"] + 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("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/dsl/regexp.xreate b/scripts/dsl/regexp.xreate index 1bfb6e6..73d03f9 100644 --- a/scripts/dsl/regexp.xreate +++ b/scripts/dsl/regexp.xreate @@ -1,76 +1,76 @@ /* Any copyright is dedicated to the Public Domain. * http://creativecommons.org/publicdomain/zero/1.0/ */ interface(extern-c){ xml2 = library:: pkgconfig("libxml-2.0"). include { - xml2 = ["string.h"] + xml2 = {"string.h"} }. } Matcher = type variant {Sequence, ZeroOrMore, Text}. matchText = function(text::string, matcher::string, posStart::i64):: i64 { textLength = strlen(text):: i64. matcherLength = strlen(matcher):: i64. if(textLength >= posStart + matcherLength):: i64{ if(strncmp(text + posStart, matcher, matcherLength) == 0):: i64 { matcherLength } else {-1:: i64} } else {-2:: i64} } -matchSequence = function(text::string, pattern::undefType; interpretation(force), posStart::i64):: i64; interpretation(suppress){ +matchSequence = function(text::string, pattern::undefType; i12n(on), posStart::i64):: i64; i12n(off){ textLength = length(text):: i64. loop fold(pattern-> matcher:: undefType, posStart->pos):: i64{ recognizedSymbols = match(text, matcher, pos):: i64. if (recognizedSymbols > (0::i64)):: i64{ pos+recognizedSymbols } else { pos:: i64; break } } } -matchZeroOrMore= function(text::string, matcher::undefType; interpretation(force), posStart::i64):: i64; interpretation(suppress){ +matchZeroOrMore= function(text::string, matcher::undefType; i12n(on), posStart::i64):: i64; i12n(off){ textLength = length(text):: i64. loop fold inf(posStart->pos):: i64{ recognizedSymbols = match(text, matcher, pos):: i64. if (recognizedSymbols > (0::i64)):: i64{ pos+recognizedSymbols } else { pos:: i64; break } } } -match = function(text::string, pattern::undefType; interpretation(force), posStart::i64)::i64; interpretation(suppress){ +match = function(text::string, pattern::undefType; i12n(on), posStart::i64)::i64; i12n(off){ key= pattern[0]::Matcher. switch variant(key) :: int case (Sequence) {matchSequence(text, pattern[1], posStart)} case (ZeroOrMore) {matchZeroOrMore(text, pattern[1], posStart)} case (Text) {matchText(text, pattern[1], posStart)} } main = function:: i64; entry { patternAB = - [Sequence(), - [[ZeroOrMore(), [Text(), "a"]], - [Text(), "b"]]] :: undefType; interpretation(force). + {Sequence(), + {{ZeroOrMore(), {Text(), "a"}}, + {Text(), "b"}}} :: undefType; i12n(on). -// matchers = ["The ", "only ", "way "] :: [string]; interpretation(force). +// matchers = ["The ", "only ", "way "] :: [string]; i12n(on). match("aaab", patternAB, 0):: i64 } diff --git a/scripts/exploitation/test1.xreate b/scripts/exploitation/test1.xreate index a0c0024..75dc1a5 100644 --- a/scripts/exploitation/test1.xreate +++ b/scripts/exploitation/test1.xreate @@ -1,32 +1,32 @@ interface(extern-c){ xml2 = library:: pkgconfig("libxml-2.0"). include { - xml2 = ["scripts/exploitation/test1.h"] + xml2 = {"scripts/exploitation/test1.h"} }. } import raw ("scripts/exploitation/exploitation.lp"). import raw ("scripts/exploitation/test1.assembly.lp"). guard:: explInitRealImpl { openFile = function(filePrev:: FILE_P):: FILE_P { fopen("/tmp/test", "w")::FILE_P } } guard:: explInitBogusImpl { openFile = function(filePrev:: FILE_P):: FILE_P { filePrev::int } } test = function::int; entry { seq { f0 = undef:: FILE_P. f0 } { f1 = openFile(f0):: FILE_P; expl_init(r1). f1 /*first attempt to open file*/} { f2 = openFile(f1):: FILE_P; expl_init(r1). f2 /*second attempt to open file*/} { sizeWritten = fwrite("WriteAttempt", 12, 1, f2):: int; expl_user(r1). sizeWritten } { fclose(f2)::int; expl_use(r1)} { sizeWritten :: int} } diff --git a/scripts/virtualization/test1.xreate b/scripts/virtualization/test1.xreate index c2cbe11..3ad7ce8 100644 --- a/scripts/virtualization/test1.xreate +++ b/scripts/virtualization/test1.xreate @@ -1,47 +1,47 @@ interface(extern-c){ externalLibs = library:: pkgconfig("libxml-2.0"). include { - externalLibs = ["scripts/virtualization/test1.h"] + externalLibs = {"scripts/virtualization/test1.h"} }. } import raw ("scripts/virtualization/test1.assembly.lp"). import raw ("scripts/cfa/context.lp"). DictSizo = type slave dict_sizo. Sizo = type slave sizo. virt_getPrefix = function:: string { 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", sizoId) } { buf } } 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:: int; entry { seq { context::attachedSizo(domainA). openFile("test1") } { context::attachedSizo(domainB). openFile("test1") } { 0 } } diff --git a/scripts/virtualization/test2.xreate b/scripts/virtualization/test2.xreate index 47856be..0051bd4 100644 --- a/scripts/virtualization/test2.xreate +++ b/scripts/virtualization/test2.xreate @@ -1,57 +1,57 @@ interface(extern-c){ externalLibs = library:: pkgconfig("libxml-2.0"). include { - externalLibs = ["scripts/virtualization/test1.h"] + externalLibs = {"scripts/virtualization/test1.h"} }. } 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) { 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. 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.xreate b/scripts/virtualization/test3.xreate index 37d93f6..468a25d 100644 --- a/scripts/virtualization/test3.xreate +++ b/scripts/virtualization/test3.xreate @@ -1,57 +1,57 @@ interface(extern-c){ externalLibs = library:: pkgconfig("libxml-2.0"). include { - externalLibs = ["scripts/virtualization/test1.h"] + 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/tools/phabricator/administration/docker-compose.yml b/tools/phabricator/administration/docker-compose.yml deleted file mode 100644 index 7de0f56..0000000 --- a/tools/phabricator/administration/docker-compose.yml +++ /dev/null @@ -1,26 +0,0 @@ -version: '2' - -services: - - phabricator_db: - image: yesnault/docker-phabricator-mysql - ports: - - '8082:3306' - - phabricator: - image: yesnault/docker-phabricator - links: - - "phabricator_db:database" - depends_on: - - phabricator_db - ports: - - '8081:80' - volumes: - - phabricator_volume:/opt/ - - -volumes: - phabricator_volume: - driver: local - - diff --git a/tools/phabricator/patches/all/1-blockrule-syntax.patch b/tools/phabricator/patches/all/1-blockrule-syntax.patch deleted file mode 100644 index 097f863..0000000 --- a/tools/phabricator/patches/all/1-blockrule-syntax.patch +++ /dev/null @@ -1,42 +0,0 @@ -diff --git a/src/markup/engine/remarkup/blockrule/PhutilRemarkupNoteBlockRule.php b/src/markup/engine/remarkup/blockrule/PhutilRemarkupNoteBlockRule.php -index e80f3e1..4c33173 100644 ---- a/src/markup/engine/remarkup/blockrule/PhutilRemarkupNoteBlockRule.php -+++ b/src/markup/engine/remarkup/blockrule/PhutilRemarkupNoteBlockRule.php -@@ -2,10 +2,13 @@ - - final class PhutilRemarkupNoteBlockRule extends PhutilRemarkupBlockRule { - -+ public $additionalData = ""; -+ - public function getMatchingLineCount(array $lines, $cursor) { - $num_lines = 0; - -- if (preg_match($this->getRegEx(), $lines[$cursor])) { -+ $matches = array(); -+ if (preg_match($this->getRegEx(), $lines[$cursor], $matches)) { - $num_lines++; - $cursor++; - -@@ -19,6 +22,14 @@ final class PhutilRemarkupNoteBlockRule extends PhutilRemarkupBlockRule { - } - } - -+ //extract type of Note -+ if ($num_lines>0) -+ if (idx($matches, 'showword')) { -+ $this->additionalData = $matches['showword']; -+ } else { -+ $this->additionalData = $matches['hideword']; -+ } -+ - return $num_lines; - } - -@@ -104,6 +115,7 @@ final class PhutilRemarkupNoteBlockRule extends PhutilRemarkupBlockRule { - 'NOTE', - 'IMPORTANT', - 'WARNING', -+ 'SYNTAX' - ); - - foreach ($words as $k => $word) { \ No newline at end of file diff --git a/tools/phabricator/patches/local/1-blockrules.patch b/tools/phabricator/patches/local/1-blockrules.patch deleted file mode 100644 index dfe0d73..0000000 --- a/tools/phabricator/patches/local/1-blockrules.patch +++ /dev/null @@ -1,65 +0,0 @@ -diff --git a/src/markup/engine/PhutilRemarkupEngine.php b/src/markup/engine/PhutilRemarkupEngine.php -index d883154..9a44c2f 100644 ---- a/src/markup/engine/PhutilRemarkupEngine.php -+++ b/src/markup/engine/PhutilRemarkupEngine.php -@@ -123,6 +123,7 @@ final class PhutilRemarkupEngine extends PhutilMarkupEngine { - - $blocks = $this->splitTextIntoBlocks($text); - -+ - $output = array(); - foreach ($blocks as $block) { - $output[] = $this->markupBlock($block); -@@ -133,15 +134,16 @@ final class PhutilRemarkupEngine extends PhutilMarkupEngine { - $this->storage = null; - $metadata = $this->metadata; - -- - return array( - 'output' => $output, - 'storage' => $map, - 'metadata' => $metadata, - ); -+ -+ - } - -- private function splitTextIntoBlocks($text, $depth = 0) { -+ public function splitTextIntoBlocks($text, $depth = 0) { - // Apply basic block and paragraph normalization to the text. NOTE: We don't - // strip trailing whitespace because it is semantic in some contexts, - // notably inlined diffs that the author intends to show as a code block. -@@ -164,7 +166,7 @@ final class PhutilRemarkupEngine extends PhutilMarkupEngine { - $curr_block = array( - 'start' => $cursor, - 'num_lines' => $num_lines, -- 'rule' => $block_rule, -+ 'rule' => clone $block_rule, - 'is_empty' => self::isEmptyBlock($text, $cursor, $num_lines), - 'children' => array(), - ); -diff --git a/src/markup/engine/remarkup/blockrule/PhutilRemarkupHeaderBlockRule.php b/src/markup/engine/remarkup/blockrule/PhutilRemarkupHeaderBlockRule.php -index cbcb143..6e91488 100644 ---- a/src/markup/engine/remarkup/blockrule/PhutilRemarkupHeaderBlockRule.php -+++ b/src/markup/engine/remarkup/blockrule/PhutilRemarkupHeaderBlockRule.php -@@ -16,13 +16,13 @@ final class PhutilRemarkupHeaderBlockRule extends PhutilRemarkupBlockRule { - } - } - -- if ($num_lines) { -- $cursor++; -- while (isset($lines[$cursor]) && !strlen(trim($lines[$cursor]))) { -- $num_lines++; -- $cursor++; -- } -- } -+// if ($num_lines) { -+// $cursor++; -+// while (isset($lines[$cursor]) && !strlen(trim($lines[$cursor]))) { -+// $num_lines++; -+// $cursor++; -+// } -+// } - - return $num_lines; - } \ No newline at end of file