diff --git a/coco/xreate.ATG b/coco/xreate.ATG index fbe17ca..6574680 100644 --- a/coco/xreate.ATG +++ b/coco/xreate.ATG @@ -1,454 +1,454 @@ //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 xreate; using namespace std; COMPILER Xreate xreate::AST root; // current program unit struct { std::stack scopesOld; xreate::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 skipIdent() { int kind = 0; scanner->ResetPeek(); while ((kind = scanner->Peek()->kind) == _colon) if (scanner->Peek()->kind != _ident) return 0; return kind; } bool checkParametersList() { return la->kind == _ident && skipIdent() == _lparen; } bool checkInfix() { return la->kind == _ident && skipIdent() == _ident; } bool checkIndex() { return la->kind == _ident && skipIdent() == _lbrack; } bool checkFuncDecl() { if (la->kind != _ident) return false; int xkind = skipIdent(); Token* y = scanner->Peek(); return xkind == _assign && y->kind == _function; } bool checkAssignment() { scanner->ResetPeek(); Token* x = scanner->Peek(); return la->kind == _ident && x->kind == _assign; } CHARACTERS letter = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz". any = ANY - '"'. digit = "0123456789". cr = '\r'. lf = '\n'. tab = '\t'. TOKENS ident = (letter | '_') {letter | digit | '_'}. number = digit {digit}. string = '"' { any } '"'. function = "function". lparen = '('. rparen = ')'. lbrack = '['. rbrack = ']'. equal = "==". assign = '='. implic = '-' '>'. colon = ':'. tagcolon = "::". COMMENTS FROM "/*" TO "*/" NESTED COMMENTS FROM "//" TO lf IGNORE cr + lf + tab PRODUCTIONS Xreate = { ( RuleDecl | InterfaceData | Imprt | IF(checkFuncDecl()) FDecl | TDecl ) }. Ident = ident {':' ident} (. name = t->val; .). FDecl<> = (. std::wstring fname; std::wstring varname; TypeAnnotation typIn; TypeAnnotation typOut; .) Ident assign function (. Function* f = new Function(fname); CodeScope* entry = f->getEntryScope(); .) ( Type (. f->setReturnType(typOut); .) | '(' [Ident tagcolon Type (. f->addArg(std::move(varname), move(typIn)); .) {',' Ident tagcolon Type (. f->addArg(std::move(varname), move(typIn));.) }] ')' tagcolon Type (. f->setReturnType(typOut); .) {';' FnTag } ) BDecl (. entry->__body.bindType(move(typOut)); root.add(f); .) . /** * TYPES * */ TypeTerm = (. std::wstring tid; .) ("string" | "int" | "num" | "float" | "bool") (. typ = Atom(t->val); .) . Type = (. TypeAnnotation typ2; TypeAtom typ3; std::wstring tid, field; .) ( TList | TStruct | TypeTerm (. typ = TypeAnnotation(typ3); .) |IF (checkIndex()) Ident lbrack Ident (. typ = TypeAnnotation(TypeOperator::ACCESS, {}); typ.__valueCustom = Atom(tid).get(); typ.fields.push_back(Atom(field).get()); .) {',' Ident (. typ.fields.push_back(Atom(field).get()); .) } rbrack | Ident (. typ = TypeAnnotation(TypeOperator::CUSTOM, {}); typ.__valueCustom = Atom(tid).get(); .) ['(' Type (. typ.__operator = TypeOperator::CALL; typ.__operands.push_back(typ2); .) {',' Type (. typ.__operands.push_back(typ2); .) } ')'] ) . TList = (. TypeAnnotation ty; .) '[' Type (. typ = TypeAnnotation(TypeOperator::ARRAY, {ty}); .) {',' Type (. typ.__operator = TypeOperator::TUPLE; typ.__operands.push_back(ty); .) }']' . TStruct = (. TypeAnnotation t; std::wstring field; .) '{' Ident tagcolon Type (. typ = TypeAnnotation(TypeOperator::STRUCT, {t}); typ.fields.push_back(Atom(field).get()); .) {',' Ident tagcolon Type} (. typ.__operands.push_back(t); typ.fields.push_back(Atom(field).get()); .) '}'. TDecl = (. std::wstring ttag; TypeAnnotation t; std::wstring tname, arg; std::vector> args; .) Ident assign "type" ( "alias" Type (. root.add(move(t), Atom(tname)); .) | Ident ['(' Ident (. args.push_back(Atom(arg)); .) {',' Ident (. args.push_back(Atom(arg)); .) } ')'] Type (. t.addBindings(move(args)); root.add(move(t), Atom(tname)); .) ) '.' . VDecl = (. std::wstring vname; Expression e; TypeAnnotation typ;.) Ident assign ExprTyped (. f->addDeclaration(move(vname), move(typ), move(e)); .) . BDecl = (. Expression body; TypeAnnotation typ; pushContextScope(scope); .) '{' { ( IF(checkAssignment()) VDecl '.' - | ExprTyped (. scope->setBody(body); popContextScope(); .) -)} + | ExprTyped (. scope->setBody(body);.) +)} (. popContextScope(); .) '}'. IfDecl = (. Expression cond; ManagedScpPtr blockTrue = root.add(new xreate::CodeScope(context.scope)); ManagedScpPtr blockFalse = root.add(new xreate::CodeScope(context.scope)); TypeAnnotation typIf; .) "if" '(' Expr ')' tagcolon Type BDecl<&*blockTrue> "else" BDecl<&*blockFalse> (. e = Expression(Operator::IF, {cond}); e.addBlock(blockTrue); e.addBlock(blockFalse); .) . LoopDecl = (. Expression eIn, eAcc, eFilters; std::wstring varEl, varAcc; TypeAnnotation typEl, typAcc; ManagedScpPtr block = root.add(new xreate::CodeScope(context.scope)); .) "loop" ("map" '(' Expr implic Ident tagcolon Type ')' tagcolon Type BDecl<&*block> (. e = Expression(Operator::MAP, {eIn}); e.addBindings({Atom(varEl)}); block->addArg(Atom(varEl), move(typEl)); e.addBlock(block); .) |"fold" '(' Expr implic Ident tagcolon Type ['|' Expr ] ',' Expr implic Ident tagcolon Type ')' tagcolon Type BDecl<&*block> (. e = Expression(Operator::FOLD, {eIn, eAcc}); e.addBindings({Atom(varEl), Atom(varAcc)}); block->addArg(Atom(varEl), move(typEl)); block->addArg(Atom(varAcc), move(typAcc)); e.addBlock(block); .) ). SwitchDecl = (. TypeAnnotation typ; eSwitch = Expression(Operator::SWITCH, {}); .) // ["switch" [tagcolon Type {';' MetaSimpExpr}]] CaseDecl {CaseDecl} . CaseDecl = (. Expression inner(Operator::CASE, {}); ManagedScpPtr scopeCond = root.add(new xreate::CodeScope(context.scope)); ManagedScpPtr scopeBody = root.add(new xreate::CodeScope(&*scopeCond)); .) "case" ( "default" | CaseParams<&*scopeCond> ) BDecl<&*scopeBody> (. inner.addBlock(scopeCond); inner.addBlock(scopeBody); outer.addArg(move(inner)); .) . CaseParams = (. Expression e; Expression guard(Operator::LOGIC_AND, {}); pushContextScope(scope); .) CaseParam {',' CaseParam } (. scope->setBody(guard); popContextScope(); .). CaseParam = (. TypeAnnotation argtyp; Expression condition; .) ( IF(checkAssignment()) VDecl | ExprTyped (. guard.addArg(move(condition)); .) ). /*============================ INTERFACES ===============================*/ Imprt<> = "import" "raw" '(' string (. root.__rawImports.push_back(Atom(t->val).get()); .) ')' '.' . InterfaceData<> = "interface" '(' ( "dfa" ')' InterfaceDFA | "extern-c" ')' InterfaceExternC | "cfa" ')' InterfaceCFA ). InterfaceExternC<> = (.xreate::ExternData data; .) '{' {IncludeExternDecl | LibExternDecl } '}' (. root.addExternData(move(data)); .) . LibExternDecl = (. std::wstring pkgname, libname; .) Ident assign "library" tagcolon "pkgconfig" '(' string (. pkgname = t->val; .) ')' '.' (. data.addLibrary(Atom(libname), Atom(pkgname)); .) . IncludeExternDecl = (. Expression inc; .) "include" StructLiteral '.' (. data.addIncludeDecl(move(inc)); .) . InterfaceDFA<> = '{' { InstructDecl } '}' . InstructDecl = (.Operator op; Expression tag; Expression scheme; std::vector& tags = scheme.operands; tags.push_back(Expression()); /* return value */ .) "operator" InstructAlias tagcolon '(' (.scheme.setOp(op); .) [ MetaSimpExpr (. tags.push_back(tag); .) { ',' MetaSimpExpr (. tags.push_back(tag); .) } ] ')' [ implic MetaSimpExpr (. tags[0] = tag; .) ] (. root.addDFAData(move(scheme)); .) '.'. InstructAlias = ( "map" (. op = Operator::MAP; .) | "list_range" (. op = Operator::LIST_RANGE; .) | "list" (. op = Operator::LIST; .) | "fold" (. op = Operator::FOLD; .) | "index" (. op = Operator::INDEX; .) ). InterfaceCFA<> = '{' { InstructCFADecl } '}' . InstructCFADecl<> = (.Operator op; Expression tag; Expression scheme; std::vector& tags = scheme.operands; .) "operator" InstructAlias tagcolon (. scheme.setOp(op); .) [ MetaSimpExpr (. tags.push_back(tag); .) { ',' MetaSimpExpr (. tags.push_back(tag); .) } ] '.' (. root.addInterfaceData(CFA, move(scheme)); .). /*============================ METAPROGRAMMING ===============================*/ // TagsDecl = (. Expression tag; TagModifier mod = TagModifier::NONE; .) // ':' { MetaSimpExpr (. /*f.addTag(std::move(tag), mod); */ .) // }. FnTag = (. Expression tag; TagModifier mod = TagModifier::NONE; .) MetaSimpExpr ['-' TagMod] (. f->addTag(std::move(tag), mod); .). TagMod = ( "assert" (. mod = TagModifier::ASSERT; .) | "require" (. mod = TagModifier::REQUIRE; .) ). RuleDecl<> = "rule" tagcolon (. RuleArguments args; RuleGuards guards; DomainAnnotation typ; std::wstring arg; .) '(' Ident tagcolon Domain (. args.add(arg, typ); .) {',' Ident tagcolon Domain (. args.add(arg, typ); .) } ')' ["case" RGuard {',' RGuard}] '{' RBody '}' . Domain = ( "function" (. dom = DomainAnnotation::FUNCTION; .) | "variable" (. dom = DomainAnnotation::VARIABLE; .) ). RGuard= (. Expression e; .) MetaExpr (. guards.add(std::move(e)); .). MetaExpr= (.Operator op; Expression e2; .) MetaExpr2 [MetaOp MetaExpr2 (. e = Expression(op, {e, e2}); .) ]. MetaExpr2= ( '(' MetaExpr ')' | MetaSimpExpr ). MetaSimpExpr= (. std::wstring i1, infix; Expression e2; .) ( '-' MetaSimpExpr (. e = Expression(Operator::NEG, {e2}); .) | IF(checkParametersList()) Ident (. e = Expression(Operator::CALL, {Expression(Atom(i1))}); .) '(' [ CalleeParams ] ')' | 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(Atom(i1)); .) ). 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 ===============================*/ ExprTyped = (. Expression tag; .) Expr [tagcolon Type (. e.bindType(move(typ)); .) {';' MetaSimpExpr (. e.tags.emplace(tag.getValueString(), move(tag)); .) }] . Expr< Expression& e> (. Operator op; Expression e2; .) = SimExpr< e> [ RelOp< op> SimExpr< e2> (. e = Expression(op, {e, e2}); .) ]. SimExpr< Expression& e> (. Operator op; Expression e2; .) = Term< e> { AddOp< op> Term< e2> (. e = Expression(op, {e, e2});.) }. Term< Expression& e> (. Operator op; Expression e2; .) = Factor< e> { MulOp< op> Factor< e2> (. e = Expression(op, {e, e2}); .) }. Factor< Expression& e> (. std::wstring name; TypeAnnotation typ; .) = (IF (checkParametersList()) Ident< name> (. e = Expression(Operator::CALL, {Atom(name)}); .) '(' [CalleeParams] ')' |IF (checkIndex()) Ident lbrack CalleeParams rbrack (. e.setOp(Operator::INDEX); e.setValue({Atom(name)}); .) | Ident< name> (. e = Expression(Atom(name)); .) | ListLiteral (. /* tuple */.) | StructLiteral (. /* struct */.) | LoopDecl | IfDecl | SwitchDecl | number (. e = Expression(Atom(t->val)); .) | string (. e = Expression(Atom(t->val)); .) | '-' Factor< e> (. e = Expression(Operator::NEG, {e}); .) | '(' Expr ')' ). StructLiteral = (. std::wstring key; Expression val; std::list> keys; .) '{' Ident '=' Expr (. keys.push_back(Atom(key)); e = Expression(Operator::LIST_NAMED, {val}); .) {',' Ident '=' Expr (.e.addArg(move(val)); keys.push_back(Atom(key)); .) } '}' (. e.addBindings(keys.begin(), keys.end()); .) . ListLiteral = (. Expression eFrom, eTo; .) '[' [ Expr (. e.addArg(std::move(eFrom)); .) (".." Expr (. e.addArg(std::move(eTo)); e.setOp(Operator::LIST_RANGE); .) |{',' Expr (. e.addArg(std::move(eFrom)); .) } (. e.setOp(Operator::LIST); .) ) ] ']'. CalleeParams = (. Expression e2; TypeAnnotation typ; .) ExprTyped (. e.addArg(std::move(e2)); .) {',' ExprTyped (. e.addArg(std::move(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 | '<' (. op = Operator::LSS; .) | '>' (. op = Operator::GTR; .) ). END Xreate. diff --git a/config/default.json b/config/default.json index a0de9f7..7d03a30 100644 --- a/config/default.json +++ b/config/default.json @@ -1,50 +1,54 @@ { "containers": { "id": { "implementations": "impl_fulfill_cluster", "clusters": "var_cluster", "prototypes": "proto_cluster", "linkedlist": "linkedlist" }, "impl": { "solid": "solid", "onthefly": "on_the_fly" } }, "logging": { "id": "logging" }, "function-entry": "entry", "clasp": { "bindings" : { "variable": "bind", "function": "bind_func", "scope": "bind_scope" }, "nonevalue": "nonevalue", "ret": { "symbol": "retv", "tag": "ret" } }, "tests": { "template": "default", "templates": { + "basic": "EntryFunction*", "default": "*-", "types": "Types*-", "containers": "Containers*-", "ast": "AST*", "non-containers": "*-Containers*", - "libxml2": "libxml2*", "log": "Logging*", - "cfg": "CFG.testLoopContextExists" + "clang": "ClangAPI*" + "cfg": "CFG.*", + "skip": "SkipDetection*", + "raw-xml": "libxml2*", + "xml": "Xml.*" } } } diff --git a/cpp/CMakeLists.txt b/cpp/CMakeLists.txt index d3e4c7b..269bdff 100644 --- a/cpp/CMakeLists.txt +++ b/cpp/CMakeLists.txt @@ -1,150 +1,149 @@ cmake_minimum_required(VERSION 2.8.11) project(xreate) find_package(LLVM REQUIRED CONFIG) set(LLVM_VERSION ${LLVM_VERSION_MAJOR}.${LLVM_VERSION_MINOR}) link_directories(${LLVM_LIBRARY_DIRS}) set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_LIST_DIR}) message ("MPATH:" ${CMAKE_MODULE_PATH}) message(STATUS "Found LLVM ${LLVM_PACKAGE_VERSION}") message(STATUS "Using LLVMConfig.cmake in: ${LLVM_DIR}") #find_package(Clang REQUIRED clangTooling libClang) set(CMAKE_BUILD_TYPE Debug) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++14 -D_GNU_SOURCE -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS") set(POTASSCO_PATH "/opt/potassco/gringo" CACHE PATH "Path to gringo sources") set (LIBCLASP_PATH ${POTASSCO_PATH}/build/debug) link_directories(${LIBCLASP_PATH}) FILE (GLOB TEST_FILES ./tests/*.cpp) message("TEST: " ${TEST_FILES}) set(SOURCE_FILES ${TEST_FILES} ./src/ast.cpp ./src/llvmlayer.cpp ./src/clasplayer.cpp #./src/main.cpp ./src/utils.cpp ./src/passmanager.cpp ./src/pass/abstractpass.cpp ./src/pass/dfgpass.cpp ./src/pass/compilepass.cpp ./src/pass/cfgpass.cpp ./src/pass/logging.cpp #./src/pass/rulespass.cpp ./src/instructions/instr-containers.cpp ./src/query/containers.cpp ./src/query/ptrvalid.cpp ./src/attachments.cpp #${POTASSCO_PATH}/app/shared/src/clingocontrol.cc #${POTASSCO_PATH}/app/pyclingo/src/clingo_lib.cc ) set(COCO_PATH ${CMAKE_HOME_DIRECTORY}/../coco/) set(COCO_SOURCE_FILES ${COCO_PATH}/Parser.h ${COCO_PATH}/Scanner.h ${COCO_PATH}/Parser.cpp ${COCO_PATH}/Scanner.cpp ) INCLUDE_DIRECTORIES(${LLVM_INCLUDE_DIRS}) INCLUDE_DIRECTORIES("/usr/include/libxml2") INCLUDE_DIRECTORIES(${COCO_PATH} ./src) INCLUDE_DIRECTORIES(${POTASSCO_PATH}/libgringo ${POTASSCO_PATH}/libclasp ${POTASSCO_PATH}/libclingo ${POTASSCO_PATH}/libprogram_opts ) include_directories(${CMAKE_HOME_DIRECTORY}/../vendors/jeayeson/include/) #execute_process(COMMAND ${COCO_PATH}/gen-xreate WORKING_DIRECTORY OUTPUT_VARIABLE COCO_OUTPUT) message(STATUS "COCO GRAMMAR BUILD STATUS:" ${COCO_OUTPUT}) include_directories(${LLVM_INCLUDE_DIRS}) add_definitions(${LLVM_DEFINITIONS}) -add_executable(xreate ${SOURCE_FILES} ${COCO_SOURCE_FILES} tests/testLibXml2.cpp src/ExternLayer.cpp src/ExternLayer.h) +add_executable(xreate ${SOURCE_FILES} ${COCO_SOURCE_FILES} src/ExternLayer.cpp src/ExternLayer.h) set(COCO_TARGET grammar) add_custom_target(${COCO_TARGET} WORKING_DIRECTORY ${COCO_PATH} ) add_custom_command(TARGET ${COCO_TARGET} PRE_BUILD COMMAND ${COCO_PATH}/gen-grammar WORKING_DIRECTORY ${COCO_PATH} ) add_custom_target (coverage COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/src/code-coverage.sh WORKING_DIRECTORY ${CMAKE_BINARY_DIR}) message(STATUS "BINARY DIR" ${CMAKE_BINARY_DIR}) #add_dependencies(${PROJECT_NAME} coverageTarget) llvm_map_components_to_libnames(llvm_libs support core irreader all native nativecodegen) message(STATUS "LLVM LIBS: " ${llvm_libs}) set(LIBCLASP_LIBS clingo clasp gringo program_opts reify ) message(STATUS "CLANG LIBS: " ${CLANG_LIBS}) message(STATUS "CLASP LIBS: " ${LIBCLASP_LIBS}) -add_definitions(-DWITH_THREADS=0) +add_definitions(-DWITH_THREADS=1) FUNCTION(PREPEND var prefix) SET(listVar "") FOREACH(f ${ARGN}) LIST(APPEND listVar "${prefix}/${f}") ENDFOREACH(f) SET(${var} "${listVar}" PARENT_SCOPE) ENDFUNCTION(PREPEND) find_package(GTest REQUIRED) INCLUDE_DIRECTORIES(${GTEST_INCLUDE_DIRS}) -# -fprofile-arcs -ftest-coverage -O0 -set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -g -Wall") +set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -g -Wall -fprofile-arcs -ftest-coverage -O0") set(CLANG_LIBS clangCodeGen clangASTMatchers clangQuery clangTooling clangFrontend clangSerialization clangDriver clangParse clangSema clangAnalysis clangAST clangEdit clangLex clangBasic ) target_link_libraries(xreate ${GTEST_LIBRARIES} LLVM-${LLVM_VERSION} ${LIBCLASP_LIBS} ${CLANG_LIBS} pthread xml2 gcov tbb) diff --git a/cpp/src/ExternLayer.cpp b/cpp/src/ExternLayer.cpp index 6d8c5c1..3a866ab 100644 --- a/cpp/src/ExternLayer.cpp +++ b/cpp/src/ExternLayer.cpp @@ -1,276 +1,282 @@ // // Created by pgess on 4/21/15. // #include "ExternLayer.h" #include #include #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 #include #include using namespace xreate; using namespace std; using namespace clang; using namespace clang::driver; using namespace clang::tooling; using namespace clang::ast_matchers; using namespace llvm; 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); - //TODO implement Expression parsing(Array of Expr as vector); - int indexLib, indexHeaders; + //TODO ?? implement Expression parsing(Array of Expr as vector); for(size_t i=0, size=e.operands.size(); i 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), __datalayout(llvm->module) +ExternLayer::ExternLayer(LLVMLayer *llvm) + : __datalayout(llvm->module), __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; if (linebuf[linelen-1 ] == ' ') linebuf[linelen-1] = 0; 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 (linebuf[linelen-1 ] == ' ') - linebuf[linelen-1] = 0; + if (linelen==1 && linebuf[0]==' ') continue; + if (linebuf[linelen-1 ] == ' ') + linebuf[linelen-1] = 0; + if (linelen>=2 && linebuf[0] == '-' && linebuf[1] == 'l'){ + libs.push_back(linebuf + 2); + } else { + libs.push_back(linebuf); + } llvm::outs() << '<' << linebuf << "> "; - libs.push_back(linebuf); - free(linebuf); linebuf = 0; } pclose(flags); return (libs); } void ExternLayer::loadLibraries(vector&& libs){ string msgErr; for (const string& lib: libs) { - if (!llvm::sys::DynamicLibrary::LoadLibraryPermanently(lib.c_str(), &msgErr)){ - llvm::errs()<<"\n"<__externdata); + // TODO use default include path from 'clang -xc++ -E' list code; std::vector args{ "-I/usr/include" ,"-I/usr/local/include" - ,"-I/usr/lib/llvm-3.6/lib/clang/3.6.0/include" + ,"-I/usr/lib/llvm-3.6/lib/clang/3.6.2/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'; } - //TODO uncomment loadLibraries - //loadLibraries(move(libs)); + loadLibraries(move(libs)); ast = buildASTFromCodeWithArgs(boost::algorithm::join(code, "\n"), args); __cgo.reset(new CodeGenOptions); __datalayout = llvm::DataLayout(ast->getASTContext().getTargetInfo().getTargetDescription()); __cgm.reset(new CodeGen::CodeGenModule(ast->getASTContext(), *__cgo, *__llvm->module, __datalayout, ast->getASTContext().getDiagnostics())); }; 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 __cgm->getTypes().ConvertType(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; } 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()); assert(! callback.typeResult.isNull()); const QualType& tyFuncQual = callback.typeResult; llvm::Type *tyRaw = __cgm->getTypes().ConvertType(tyFuncQual); llvm::FunctionType* tyRawFunc = llvm::dyn_cast(tyRaw); llvm::Function* function = llvm::Function::Create(tyRawFunc, llvm::GlobalValue::ExternalLinkage, name, __llvm->module); __functions.emplace(name, function); return function; } diff --git a/cpp/src/ast.cpp b/cpp/src/ast.cpp index 6db5f2f..ea80e4b 100644 --- a/cpp/src/ast.cpp +++ b/cpp/src/ast.cpp @@ -1,642 +1,642 @@ #include "ast.h" #include "ExternLayer.h" #include #include #include using namespace std; namespace xreate{ 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 (int i=0; i elTy = expandType(t.__operands.at(0)); return ExpandedType(TypeAnnotation(tag_array, elTy, t.__size)); } case TypeOperator::STRUCT: { assert(t.__operands.size()); std::vector&& pack = expandOperands(t.__operands); auto tnew = TypeAnnotation(TypeOperator::STRUCT, move(pack)); tnew.fields = t.fields; return ExpandedType(move(tnew)); }; 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: { std::string alias = t.__valueCustom; /* if (signatures.count(alias)) { return ExpandedType(TypeAnnotation(TypeOperator::LINK, {t})); } signatures[alias].emplace(t); */ //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::STRUCT); 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::TUPLE: { assert(t.__operands.size()); std::vector pack; pack.reserve(t.__operands.size()); std::transform(t.__operands.begin(), t.__operands.end(), std::inserter(pack, pack.end()), [this](const TypeAnnotation& t){ return expandType(t); }); return ExpandedType(TypeAnnotation(TypeOperator::TUPLE, move(pack))); } case TypeOperator::NONE: { return ExpandedType(TypeAnnotation(t)); } default: assert(false); } assert(false); return ExpandedType(TypeAnnotation()); } }; TypeAnnotation::TypeAnnotation() { } TypeAnnotation::TypeAnnotation(const Atom &typ) : __value(typ.get()) { ; } 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::ARRAY, {typ}) { __size=size; } 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(params.size()); std::transform(params.begin(), params.end(), std::inserter(bindings, bindings.end()), [](const Atom& ident){return ident.get(); }); } Expression::Expression(const Atom& number) : __state(NUMBER), op(Operator::NONE), __valueD(number.get()) { } Expression::Expression(const Atom& a) : __state(STRING), op(Operator::NONE), __valueS(a.get()) { } Expression::Expression(const Atom &ident) : __state(IDENT), op(Operator::NONE), __valueS(ident.get()) { if (ident.get() == "null") { __state = NONE; } } Expression::Expression(const Operator &oprt, std::initializer_list params) : __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::NONE: __state = INVALID; break; default: __state = COMPOUND; break; } } void Expression::addArg(Expression &&arg) { operands.push_back(arg); } void Expression::addBindings(std::initializer_list> params) { addBindings(params.begin(), params.end()); } void Expression::bindType(TypeAnnotation&& t) { type = 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(); } bool Expression::isNone() const{ return (op == Operator::NONE && __state == NONE); } bool Expression::isValid() const{ return (__state != INVALID); } Expression::Expression() - : op(Operator::NONE), __state(INVALID) + : __state(INVALID), op(Operator::NONE) {} AST::AST() { } 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[f->getName()] = __functions.size()-1; } void AST::add(MetaRuleAbstract *r) { __rules.push_back(r); } void AST::add(TypeAnnotation&& t, Atom&& alias){ __indexTypeAliases.emplace(alias.get(), 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) { if (! __indexFunctions.count(name)) { return ManagedFnPtr::Invalid(); } return ManagedPtr(__indexFunctions.at(name), &__functions); } 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);} Expanded AST::expandType(const TypeAnnotation &t) const { return TypesResolver(this)(t); } 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)); } Function::Function(const Atom& name) : __entry(new CodeScope(0)) { __name = name.get(); } void Function::addTag(Expression&& tag, const TagModifier mod) { __tags.emplace_back(tag, mod); } const std::vector& Function::getAnnotations() const { return __tags; } CodeScope* Function::getEntryScope() const { return __entry; } void CodeScope::addArg(Atom && name, TypeAnnotation&& typ) { - VID id = registerVar(std::move(const_cast(name.get())), std::move(typ)); + registerVar(std::move(const_cast(name.get())), std::move(typ)); __args.push_back(name.get()); } ; void Function::addArg(Atom && name, TypeAnnotation&& typ) { __entry->addArg(move(name), move(typ)); } void Function::setReturnType(const TypeAnnotation &rtyp) { __entry->__definitions[0] = rtyp; } const std::string& Function::getName() const { return __name; } CodeScope::CodeScope(CodeScope* parent) :__parent(parent) {} CodeScope::~CodeScope() {} VID CodeScope::registerVar(std::string&& name, TypeAnnotation &&typ) { __vartable[name] = ++__vCounter; __definitions[__vCounter] = typ; return __vCounter; } void CodeScope::addDeclaration(const Atom &&name, TypeAnnotation &&typ, Expression&& body) { VID id = registerVar(std::move(const_cast(name.get())), move(typ)); __declarations[id] = body; } void CodeScope::setBody(const Expression &body) { __body = body; } TypeAnnotation& CodeScope::findDefinition(const Symbol& symbol) { CodeScope* self = symbol.scope; assert(self->__definitions.count(symbol.identifier)); return self->__definitions[symbol.identifier]; } Symbol CodeScope::findSymbol(const std::string &name) { //search var in current block if (__vartable.count(name)) { VID vId = __vartable.at(name); Symbol result{vId, this}; return result; } //search in parent scope if (__parent) { return __parent->findSymbol(name); } //exception: Ident not found - assert(false); + assert(false && "Symbol not found"); } bool CodeScope:: hasDeclaration(const Symbol& symbol) { CodeScope* self = symbol.scope; return (self->__declarations.count(symbol.identifier)); } const Expression& CodeScope::findDeclaration(const Symbol& symbol) { CodeScope* self = symbol.scope; if (! self->__declarations.count(symbol.identifier)) { // no declaration exists assert(false); } return self->__declarations[symbol.identifier]; } 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)), __condition(condition), __message(message.get()) + : MetaRuleAbstract(std::move(args), std::move(guards)), __message(message.get()), __condition(condition) {} RuleWarning::~RuleWarning(){} void RuleWarning::compile(ClaspLayer& layer) { layer.addRuleWarning(*this); } bool operator< (const Symbol& s1, const Symbol& s2) { return (s1.scope < s2.scope) || (s1.scope==s2.scope && s1.identifier #include #include #include #include #include #include #include "attachments.h" #include "utils.h" #include namespace llvm{ class Value; } namespace xreate { struct String_t{}; struct Identifier_t {}; struct Number_t {}; struct Type_t {}; template class Atom {}; +//DEBT hold for all atoms/identifiers Parser::Token data, like line:col position template<> class Atom { public: Atom(const std::wstring& value) { char buffer[32]; wcstombs(buffer, value.c_str(), 32); __value = buffer; } Atom(std::string && name): __value(name) {} const std::string& get() const{return __value; } private: std::string __value; }; template<> class Atom { public: Atom(wchar_t* value) { __value = wcstol(value, 0, 10); } Atom(int value) : __value(value) {} double get()const {return __value; } private: double __value; }; template<> class Atom { public: Atom(const std::wstring& value) : __value(++value.begin(), --value.end()) {} const std::string& get() const {return __value; } private: std::string __value; }; enum class TypePrimitive {Bool, Int, Float, Num, String, I32, I8}; template<> class Atom { public: Atom(wchar_t* value) { char buffer_[32]; wcstombs(buffer_, value, 32); std::string buffer(buffer_); if (buffer=="bool"){ __value = TypePrimitive ::Bool; } else if (buffer=="int") { __value = TypePrimitive::Int; } else if (buffer=="float") { __value = TypePrimitive::Float; } else if (buffer=="num") { __value = TypePrimitive::Num; } else if (buffer=="string") { __value = TypePrimitive::String; } } Atom() { } TypePrimitive get() const { return __value; } private: TypePrimitive __value; }; typedef Atom TypeAtom; enum class TypeOperator{NONE, CALL, CUSTOM, ARRAY, TUPLE, STRUCT, ACCESS, LINK}; struct llvm_array_tag {}; struct struct_tag{}; const llvm_array_tag tag_array = llvm_array_tag(); const struct_tag tag_struct = struct_tag(); 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); bool operator< (const TypeAnnotation& t) const; // TypeAnnotation (struct_tag, std::initializer_list); 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 { ADD, SUB, MUL, DIV, EQU, LSS, GTR, NEG, LIST, LIST_RANGE, LIST_NAMED, CALL, NONE, IMPL/* implication */, MAP, FOLD, INDEX, IF, SWITCH, CASE, LOGIC_AND }; class Function; class AST; class CodeScope; class MetaRuleAbstract; template struct ManagedPtr { static ManagedPtr Invalid(){ return ManagedPtr(); } ManagedPtr(): __storage(0) {} ManagedPtr(unsigned int id, const std::vector* storage) : __id(id), __storage(storage) {} Target& operator*() const { assert(isValid() && "Invalid Ptr"); return *__storage->at(__id); } void operator=(const ManagedPtr& other) { __id = other.__id; __storage = other.__storage; } bool operator == (const ManagedPtr& other) { return isValid() && (__id == other.__id); } Target* operator->() const noexcept { assert(isValid() && "Invalid Ptr"); return __storage->at(__id); } inline bool isValid() const { return (__storage) && (0 <= __id) && (__id < __storage->size()); } inline operator bool() const { return isValid(); } ManagedPtr& operator++() { ++__id; return *this; } inline unsigned int id() { return __id; } private: unsigned int __id =0; const std::vector * __storage=0; }; typedef ManagedPtr ManagedFnPtr; typedef ManagedPtr ManagedScpPtr; typedef ManagedPtr ManagedRulePtr; const ManagedScpPtr NO_SCOPE = ManagedScpPtr(UINT_MAX, 0); struct Expression { friend class CodeScope; friend class ClaspLayer; friend class CFGPass; 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 addBlock(ManagedScpPtr scope); const std::vector& getOperands() const; double getValueDouble() const; const std::string& getValueString() const; void setValue(const Atom&& v); bool isNone() const; bool isValid() const; - Operator op; enum {INVALID, COMPOUND, IDENT, NUMBER, STRING, NONE} __state = INVALID; + Operator op; std::vector bindings; std::map __indexBindings; std::vector operands; TypeAnnotation type; std::map tags; std::list blocks; private: std::string __valueS; double __valueD; }; template void Expression::addBindings(InputIt paramsBegin, InputIt paramsEnd) { size_t index = bindings.size(); std::transform(paramsBegin, paramsEnd, std::inserter(bindings, bindings.end()), [&index, this] (const Atom atom){ std::string key = atom.get(); this->__indexBindings[key] = index++; return key; }); } typedef std::list ExpressionList; enum class TagModifier {NONE, ASSERT, REQUIRE}; enum class DomainAnnotation {FUNCTION, VARIABLE}; class RuleArguments: public std::vector> { public: void add(const Atom& name, DomainAnnotation typ); }; class RuleGuards: public std::vector { public: void add(Expression&& e); }; class ClaspLayer; class LLVMLayer; class MetaRuleAbstract { public: MetaRuleAbstract(RuleArguments&& args, RuleGuards&& guards); virtual ~MetaRuleAbstract(); virtual void compile(ClaspLayer& layer) =0; protected: RuleArguments __args; RuleGuards __guards; }; class RuleWarning: public MetaRuleAbstract { friend class ClaspLayer; public: RuleWarning(RuleArguments&& args, RuleGuards&& guards, Expression&& condition, Atom&& message); virtual void compile(ClaspLayer& layer); ~RuleWarning(); private: std::string __message; Expression __condition; }; typedef unsigned int VID; /* class Expression: ExpressionAbstract { friend class CFGPass; public: llvm::Value* compile(LLVMLayer& l, Function* f, std::string* hintRetVar=0) const; }; */ typedef std::pair VariableDefinition; typedef std::pair VariableDeclaration; typedef std::pair Tag; struct Symbol { VID identifier; CodeScope * scope; }; struct SymbolTags_t{}; template<> struct AttachmentsDict { typedef std::map Data; static const unsigned int key = 2; }; bool operator< (const Symbol& s1, const Symbol& s2); bool operator== (const Symbol& s1, const Symbol& s2); class CodeScope { friend class Function; friend class PassManager; public: CodeScope(CodeScope* parent=0); void setBody(const Expression& body); void addDeclaration(const Atom &&name, TypeAnnotation &&typ, Expression&& body); void addArg(Atom && name, TypeAnnotation&& typ); //TODO exclude forceCompile partz Symbol findSymbol(const std::string &name); static const Expression& findDeclaration(const Symbol& symbol); static TypeAnnotation& findDefinition(const Symbol& symbol); static bool hasDeclaration(const Symbol& symbol); ~CodeScope(); std::vector __args; Expression __body; //TODO move __body to __declarations[0] SymbolAttachments attachments; std::map __vartable; /** * definition of return type has variable index Zero(0) */ //TODO move __definitions to SymbolsAttachments data std::unordered_map __definitions; std::unordered_map __declarations; protected: VID __vCounter=1; CodeScope* __parent; std::list __storage; VID registerVar(std::string&& name, TypeAnnotation &&typ); }; class Function { friend class Expression; friend class CodeScope; friend class AST; public: Function(const Atom& name); void addArg(Atom && name, TypeAnnotation&& typ); void addTag(Expression&& tag, const TagModifier mod); void setReturnType(const TypeAnnotation& rtyp); const std::string& getName() const; const std::vector& getAnnotations() const; CodeScope* getEntryScope() const; CodeScope* __entry; std::string __name; private: std::vector __tags; }; class ExternData; struct ExternEntry { std::string package; std::vector headers; }; typedef Expanded ExpandedType; enum ASTInterface { CFA, DFA, Extern }; class AST { public: AST(); //TASK extern and DFA interfaces move into addINterfaceData /** * DFA Interface */ void addDFAData(Expression&& data); /** * Extern Interface */ void addExternData(ExternData&& data); void addInterfaceData(const ASTInterface& interface, Expression&& data ); void add(Function* f); void add(MetaRuleAbstract* r); ManagedScpPtr add(CodeScope* scope); std::string getModuleName(); ManagedPtr findFunction(const std::string& name); template ManagedPtr begin(); std::vector __externdata; std::list __dfadata; //TODO move to more appropriate place std::list __rawImports; //TODO move to more appropriate place - std::multimap __interfacesData; + std::multimap __interfacesData; //TODO CFA data here. private: std::vector __rules; std::vector __functions; std::vector __scopes; std::map __indexFunctions; // ***** TYPES SECTION ***** public: std::map __indexTypeAliases; ExpandedType expandType(const TypeAnnotation &t) const; ExpandedType findType(const std::string& name); void add(TypeAnnotation&& t, Atom&& alias); private: ExpandedType expandType(const TypeAnnotation &t, std::map scope, const std::vector &args = std::vector()) const; // ***** TYPES SECTION END ***** }; template<> ManagedPtr AST::begin(); template<> ManagedPtr AST::begin(); template<> ManagedPtr AST::begin(); } #endif // AST_H diff --git a/cpp/src/clasplayer.cpp b/cpp/src/clasplayer.cpp index 751e072..c074c43 100644 --- a/cpp/src/clasplayer.cpp +++ b/cpp/src/clasplayer.cpp @@ -1,611 +1,623 @@ #include "clasplayer.h" -#include // for defining logic programs -#include // unfounded set checkers -#include // for enumerating answer sets -#include - #include -#include #include "utils.h" #include #include +#include using namespace std; namespace xreate { void ClaspLayer::printWarnings(std::ostream& out) { const std::string warningTag = "warning"; auto warningsRange = __model.equal_range(warningTag); for (auto warning=warningsRange.first; warning!= warningsRange.second; ++warning) { unsigned int warningId; Gringo::Value params; std::tie(warningId, params) = parse(warning->second); cout << "Warning: " << __warnings.at(warningId) << " "; params.print(out); out< warnings; cout << "Model: " << endl; const string& atomBindVar = Config::get("clasp.bindings.variable"); const string& atomBindFunc = Config::get("clasp.bindings.function"); for (Gringo::Value atom : model.atoms(Gringo::Model::ATOMS)) { atom.print(cout); cout <<" | "<< endl; if (*atom.name() == atomBindVar || *atom.name() == atomBindFunc){ string name = *std::get<1>(parse(atom)).name(); __model.emplace(move(name), move(atom)); continue; } __model.emplace(*atom.name(), move(atom)); } return true; } list multiplyLists(list> &&lists) { typedef list StringList; assert(lists.size()); StringList result(*lists.begin()); lists.pop_front(); boost::format concat("%s, %s"); for (StringList &list: lists) { StringList::const_iterator end = result.end(); for (StringList::iterator expr1I = result.begin(); expr1I != end; ++expr1I) { if (list.size() == 0) continue; StringList::const_iterator expr2I = list.begin(); for (int expr2No = 0, size = list.size() - 1; expr2No < size; ++expr2No, ++expr1I) result.push_back(str(concat %(*expr1I) %(*expr2I))); *expr1I = str(concat %(*expr1I) %(*expr2I)); } } return result; } void ClaspLayer::setCFAData(CFAGraph &&graph) { cfagraph = graph; } void ClaspLayer::addDFAData(DFAGraph &&graph) { dfaData = graph; std::set symbols; ostream &cout = __partGeneral; cout << endl << "%\t\tStatic analysis: DFA" << endl; std::vector>::iterator i1; std::vector::iterator i2; - boost::format format3Args("(%1%, %2%, %3%)"); + boost::format formatDfaConnection("dfa_connection(%1%, %2%, %3%)."); boost::format format2Args("(%1%, %2%)"); for (i1= dfaData.__edges.begin(), i2 = dfaData.__data.begin(); i1!= dfaData.__edges.end(); ++i1, ++i2 ) { string edgeName; switch (*i2) { case DFGConnection::OPT: edgeName = "opt"; break; case DFGConnection::ALIAS: edgeName = "alias"; break; case DFGConnection::PROTO: edgeName = "proto"; break; } - cout << "dfa_connection"<< (format3Args - %(format2Args %(i1->first.identifier) %(i1->first.scope)) - %(format2Args %(i1->second.identifier) %(i1->second.scope)) - %edgeName) - << "." <first.identifier) %(i1->first.scope)).str() + %(format2Args %(i1->second.identifier) %(i1->second.scope)).str() + %edgeName + << " %" <first) << " - " << getHintForPackedSymbol(i1->second) + <first); symbols.insert(i1->second); } boost::format formatBind("bind(%1%, %2%)."); for (const pair& tag: dfaData.__tags) { for (string variant: compile(tag.second)) { cout << (formatBind % (format2Args %(tag.first.identifier) %(tag.first.scope)) % (variant)) + << "%" << getHintForPackedSymbol(tag.first) << endl; } symbols.insert(tag.first); } for (const SymbolPacked& s: symbols) { - cout << "v(" << format2Args % (s.identifier) % arg(s.scope) << ")."< tagRaw = compile(tag.first); assert(tagRaw.size() == 1); cout << formatBind % (atomBinding) % (function.second) % (tagRaw.front()) << endl; ++counterTags; } } if (counterTags == 0) { cout << "%no tags at all" << endl; } //show scope tags: boost::format formatScope("scope(%1%)."); for (auto scope: __indexScopes) { //std::string function = scope.first. cout << formatScope % scope.second << std::endl; } counterTags = 0; - boost::format formatScopeBind("(%1%(%2%, %3%)."); + boost::format formatScopeBind("%1%(%2%, %3%)."); for (auto entry: cfagraph.__scopeTags) { ScopePacked scopeId = entry.first; const Expression& tag = entry.second; list tagRaw = compile(tag); assert(tagRaw.size() == 1); cout << formatScopeBind % atomBindingScope % scopeId %(tagRaw.front()) << endl; ++counterTags; } if (counterTags == 0) { cout << "%no tags at all" << endl; } cout << endl << "%\t\tStatic analysis: CFA" << endl; boost::format formatCall("call(%1%, %2%)."); for (const auto &relation: cfagraph.__relations) { const ScopePacked scopeFrom = relation.first; const string& functionTo = cfagraph.__nodesFunction.left.at(relation.second); cout << formatCall % (scopeFrom) % (functionTo) << endl; } } void ClaspLayer::addRuleWarning(const RuleWarning &rule) { //__partGeneral << rule << endl; list domains; boost::format formatDef("%1%(%2%)"); std::transform(rule.__args.begin(), rule.__args.end(), std::inserter(domains, domains.begin()), [&formatDef](const std::pair &argument) { string domain; switch (argument.second) { case DomainAnnotation::FUNCTION: domain = "function"; break; case DomainAnnotation::VARIABLE: domain = "variable"; break; } return boost::str(formatDef % domain % argument.first); }); list vars; std::transform(rule.__args.begin(), rule.__args.end(), std::inserter(vars, vars.begin()), [](const std::pair &argument) { return argument.first.c_str(); }); list> guardsRaw; std::transform(rule.__guards.begin(), rule.__guards.end(), std::inserter(guardsRaw, guardsRaw.begin()), [this](const Expression &guard) { return compile(guard); }); const list& guards = multiplyLists(std::move(guardsRaw)); list &&branches = compileNeg(rule.__condition); boost::format formatWarning("warning(%1%, (%2%)):- %3%, %4%, %5%."); for (const string &guardsJoined: guards) for (const string &branch: branches) { unsigned int hook = registerWarning(string(rule.__message)); __partGeneral << formatWarning %(hook) %(boost::algorithm::join(vars, ", ")) %(branch) %(guardsJoined) %(boost::algorithm::join(domains, ", ")) < ClaspLayer::compile(const Expression &e) const { list result; switch (e.op) { case Operator::CALL: { assert(e.__state == Expression::COMPOUND); std::list> operands; std::transform(e.operands.begin(), e.operands.end(), std::inserter(operands, operands.begin()), [this](const Expression &e) { return compile(e); }); list &&operands_ = multiplyLists(std::move(operands)); result.push_back(boost::str(boost::format("%1%(%2%)") % (e.__valueS) % (boost::algorithm::join(operands_, ", ")))); break; } case Operator::NEG: { assert(e.operands.size() == 1); const Expression &op = e.operands.at(0); list &&rawOp = compile(op); assert(rawOp.size() == 1); result.push_back((boost::format("not %1%")%(rawOp.front())).str()); break; }; case Operator::NONE: { switch (e.__state) { case Expression::IDENT: result.push_back(e.__valueS); break; case Expression::NUMBER: result.push_back(to_string(e.__valueD)); break; default: assert(true); } break; } + + default: break; } if (e.isNone()){ result.push_back(e.__valueS); } assert(result.size()); return result; } std::list ClaspLayer::compileNeg(const Expression &e) const { list result; switch (e.op) { case Operator::IMPL: { assert(e.__state == Expression::COMPOUND); assert(e.operands.size() == 2); list operands1 = compile(e.operands.at(0)); list operands2 = compile(e.operands.at(1)); boost::format formatNeg("%1%, not %2%"); for (const auto &op1: operands1) for (const auto &op2: operands2) { result.push_back(boost::str(formatNeg %(op1) % (op2))); } break; } case Operator::NEG: { assert(e.operands.size() == 1); const Expression &op = e.operands.at(0); list &&rawOp = compile(op); assert(rawOp.size() == 1); result.push_back(rawOp.front()); break; }; default: assert(true); } return result; } unsigned int ClaspLayer::registerWarning(std::string &&message) { static int warningId = 0; __warnings.emplace(warningId, message); return warningId++;; } void ClaspLayer::involveImports() { ostream &out = __partGeneral; for (string fn: ast->__rawImports) { std::ifstream file(fn); if (!file) continue; while(!file.eof()){ string line; std::getline(file, line); out << line << endl; } } } void ClaspLayer::addRawScript(std::string&& script){ __partGeneral << script; } void ClaspLayer::run() { involveImports(); involveCFAData(); ostringstream program; program << __partTags.str() << __partGeneral.str(); cout << FYEL(program.str()) << endl; - const char *argv[] = {nullptr, nullptr}; + std::vector args{"clingo", nullptr}; DefaultGringoModule moduleDefault; - ClingoLib ctl(moduleDefault, 2, argv); - - //prg.add("p", ["t"], "q(t).") - Gringo::FWStringVec vars{}; - ctl.add("base", vars, program.str()); + Gringo::Scripts scriptsDefault(moduleDefault); + ClingoLib ctl(scriptsDefault, 0, args.data()); - //prg.ground([("p", [2])]) - Gringo::Control::GroundVec vals{std::make_pair("base", Gringo::FWValVec {})}; - ctl.ground(vals, Gringo::Any()); + ctl.add("base", {}, program.str()); + ctl.ground({{"base", {}}}, nullptr); - //solve - Gringo::Control::Assumptions as; - Gringo::SolveResult result = ctl.solve(Gringo::Control::ModelHandler([&](Gringo::Model const &model) { - return this->onModel(model); - }), std::move(as)); +// solve + Gringo::SolveResult result = ctl.solve([this](Gringo::Model const &model) { + this->onModel(model); + return true; + }, {}); if (result == Gringo::SolveResult::SAT) { cout << FGRN("SUCCESSFULLY") << endl; } else { cout << FRED("UNSUCCESSFULLY") << endl; } - // invoke all query plugins to process clasp data +// invoke all query plugins to process clasp data for (IQuery* q: __queries) { q->init(this); } } ClaspLayer::ClaspLayer() { } - ClaspLayer::ModelRange + ClaspLayer::ModelFragment ClaspLayer::query(const std::string& atom) { if (! __model.count(atom)){ return boost::none; } - return ModelRange(__model.equal_range(atom)); + return ModelFragment(__model.equal_range(atom)); } ScopePacked ClaspLayer::pack(CodeScope* scope) { auto pos = __indexScopes.emplace(scope, __indexScopes.size()); if (pos.second) __registryScopes.push_back(scope); return pos.first->second; } SymbolPacked ClaspLayer::pack(const Symbol& symbol, std::string hintSymbolName) { SymbolPacked result; result.scope = pack(symbol.scope); result.identifier = symbol.identifier; + __indexSymbolNameHints.emplace(result, hintSymbolName); return result; } Symbol ClaspLayer::unpack(const SymbolPacked& symbol) { return Symbol{symbol.identifier, __registryScopes[symbol.scope]}; }; - + std::string + ClaspLayer::getHintForPackedSymbol(const SymbolPacked& symbol){ + auto result = __indexSymbolNameHints.find(symbol); + return (result == __indexSymbolNameHints.end())? "" : result->second; + } /* void AspOutPrinter::reportSolution(const Clasp::Solver&, const Clasp::Enumerator&, bool complete) { if (complete) std::cout << "No more models!" << std::endl; else std::cout << "More models possible!" << std::endl; } void AspOutPrinter::reportModel(const Clasp::Solver& s, const Clasp::Enumerator&) { std::cout << "Model " << s.stats.solve.models << ": \n"; // get the symbol table from the solver const Clasp::AtomIndex& symTab = *s.strategies().symTab; for (Clasp::AtomIndex::const_iterator it = symTab.begin(); it != symTab.end(); ++it) { // print each named atom that is true w.r.t the current assignment } std::cout << std::endl; } */ /***************************************** * CFAGraph ***************************************** */ void CFAGraph::addFunctionNodeTags(const std::string& function, const std::vector&tags) { unsigned int fid = registerNodeFunction(function); for (Tag tag: tags){ __functionTags.emplace(fid, tag); } } void CFAGraph::addScopeNodeTags(const ScopePacked& scope, const std::vector& tags){ for (Expression tag: tags){ __scopeTags.emplace(scope, tag); } } void CFAGraph::addLink(const ScopePacked& scopeFrom, const std::string& functionTo) { unsigned int idFuncTo = registerNodeFunction(functionTo); __relations.emplace(scopeFrom, idFuncTo); } unsigned int CFAGraph::registerNodeFunction(const std::string& fname){ auto pos = __nodesFunction.left.insert(make_pair(__nodesFunction.size(), fname)); return pos.first->first; } /***************************************** * DFAGraph ***************************************** */ class VisitorAddTag: public boost::static_visitor<> { public: void operator()(const SymbolPacked& symbol){ __graph->__tags.emplace(symbol, move(__tag)); } void operator()(SymbolTransient& symbol){ symbol.tags.push_back(move(__tag)); } void operator()(const SymbolInvalid& symbol){ assert(false && "Undefined behaviour"); } VisitorAddTag(DFAGraph* const dfagraph, Expression&& tag): __graph(dfagraph), __tag(tag) {} private: DFAGraph* const __graph; Expression __tag; }; class VisitorAddLink: public boost::static_visitor<> { public: void operator()(const SymbolPacked& nodeFrom){ if (!__graph->linkExists(__nodeTo, nodeFrom)) { __graph->__edges.emplace_back(__nodeTo, nodeFrom); __graph->__data.push_back(__link); DFAGraph::EdgeId eid = __graph->__edges.size()-1; __graph->__outEdges.emplace(nodeFrom, eid); } } - void operator()(const SymbolTransient& symbol){ + void operator()(const SymbolTransient& symbolFrom){ + if (__link != DFGConnection::ALIAS){ + assert(false && "Undefined behaviour"); + } + + for (const Expression& tag: symbolFrom.tags){ + __graph->__tags.emplace(__nodeTo, tag); + } } - void operator()(const SymbolInvalid& symbol){ + void operator()(const SymbolInvalid&){ + if (__link == DFGConnection::ALIAS) return; + if (__link == DFGConnection::OPT) return; + assert(false && "Undefined behaviour"); } VisitorAddLink(DFAGraph* const dfagraph, const SymbolPacked& nodeTo, DFGConnection link): __graph(dfagraph), __nodeTo(nodeTo), __link(link) {} private: DFAGraph* const __graph; SymbolPacked __nodeTo; DFGConnection __link; }; bool DFAGraph::linkExists(const SymbolPacked& node1, const SymbolPacked& node2) { auto range = __outEdges.equal_range(node2); for(std::multimap::iterator edge = range.first; edge != range.second; ++edge) { if (__edges[edge->second].second == node1) return true; } return false; } void DFAGraph::addLink(const SymbolPacked& nodeTo, const SymbolNode& nodeFrom, DFGConnection link) { VisitorAddLink visitor(this, nodeTo, link); boost::apply_visitor(visitor, nodeFrom); } void DFAGraph::addTag(SymbolNode& node, Expression&& tag) { VisitorAddTag visitor(this, move(tag)); boost::apply_visitor(visitor, node); } bool operator==(const SymbolPacked& s1, const SymbolPacked& s2) { return s1.identifier == s2.identifier && s1.scope == s2.scope; } bool operator<(const SymbolPacked& s1, const SymbolPacked& s2) { return s1.scope < s2.scope || (s1.scope == s2.scope && s1.identifier < s2.identifier); } void ClaspLayer::registerdQuery(IQuery *query) { __queries.push_back(query); } } diff --git a/cpp/src/clasplayer.h b/cpp/src/clasplayer.h index 85acd90..c89196a 100644 --- a/cpp/src/clasplayer.h +++ b/cpp/src/clasplayer.h @@ -1,200 +1,202 @@ #ifndef CLASPLAYER_H #define CLASPLAYER_H #include -#include +#include #include #include #include #include #include namespace xreate { typedef unsigned int ScopePacked; class CFAGraph { friend class ClaspLayer; public: void addFunctionNodeTags(const std::string& function, const std::vector&tags); void addScopeNodeTags(const ScopePacked& scope, const std::vector&tags); void addLink(const ScopePacked& scopeFrom, const std::string& functionTo); //void print(std::ostream &cout) const; private: std::map __relations; boost::bimap __nodesFunction; std::multimap __functionTags; std::multimap __scopeTags; unsigned int registerNodeFunction(const std::string& fname); }; struct SymbolPacked { VID identifier; ScopePacked scope; }; struct SymbolTransient{ std::list tags; }; struct SymbolInvalid{}; typedef boost::variant SymbolNode; bool operator==(const SymbolPacked& s1, const SymbolPacked& s2); bool operator<(const SymbolPacked& s1, const SymbolPacked& s2); enum class DFGConnection{ ALIAS, OPT, PROTO}; class VisitorAddTag; class VisitorAddLink; class DFAGraph { friend class ClaspLayer; friend class VisitorAddTag; friend class VisitorAddLink; public: void addTag(SymbolNode& node, Expression&& tag); void addLink(const SymbolPacked& nodeTo, const SymbolNode& nodeFrom, DFGConnection link); bool linkExists(const SymbolPacked& node1, const SymbolPacked& node2); private: typedef unsigned int EdgeId; std::vector> __edges; std::multimap __outEdges; std::vector __data; std::multimap __tags; }; class IQuery { public: virtual void init(ClaspLayer* clasp)=0; virtual ~IQuery() {} }; class ClaspLayer { public: AST *ast; DFAGraph dfaData; CFAGraph cfagraph; ClaspLayer(); void registerdQuery(IQuery* query); void addFunctionTags(const std::string &function, const std::vector &tags); void setCFAData(CFAGraph &&graph); void addDFAData(DFAGraph &&graph); void addRuleWarning(const RuleWarning &rule); void run(); template static std::tuple parse(const Gringo::Value& atom); typedef std::multimap::const_iterator ModelIterator; - typedef boost::optional> ModelRange; - ModelRange query(const std::string& atom); + typedef boost::optional> ModelFragment; + ModelFragment query(const std::string& atom); ScopePacked pack(CodeScope* scope); SymbolPacked pack(const Symbol& symbol, std::string hintSymbolName=""); Symbol unpack(const SymbolPacked& symbol); + std::string getHintForPackedSymbol(const SymbolPacked& symbol); void addRawScript(std::string&& script); private: // all query plugins to process clasp data std::list __queries; std::multimap __model; std::map __warnings; std::ostringstream __partTags; std::ostringstream __partGeneral; + std::map __indexSymbolNameHints; std::unordered_map __indexScopes; std::vector __registryScopes; void printWarnings(std::ostream& out); bool onModel(Gringo::Model const &model); std::list compile(const Expression &e) const; std::list compileNeg(const Expression &e) const; unsigned int registerWarning(std::string &&message); void involveImports(); void involveCFAData(); }; template struct ParseImplAtom { static typ get(const Gringo::Value& atom) { return atom.num(); } }; template<> struct ParseImplAtom { static std::string get(const Gringo::Value& atom) { return *atom.string(); }}; template<> struct ParseImplAtom { static SymbolPacked get(const Gringo::Value& atom) { auto result = ClaspLayer::parse(atom); return SymbolPacked{std::get<0>(result), std::get<1>(result)}; }}; template<> struct ParseImplAtom { static Gringo::Value get(const Gringo::Value& atom) { return atom; }}; template struct Parse_Impl { static void parse(Tuple& tup, Gringo::FWValVec::const_iterator arg) { const size_t tupleSize = std::tuple_size::value; typedef typename std::tuple_element::type ElType; ElType& el = std::get(tup); Gringo::Value atom = *arg; el = ParseImplAtom::get(atom); Parse_Impl::parse(tup, ++arg); } }; template struct Parse_Impl { static void parse(Tuple& tup, Gringo::FWValVec::const_iterator arg) {} }; template std::tuple ClaspLayer::parse(const Gringo::Value& atom) { typedef std::tuple Tuple; Tuple tup; Parse_Impl::value>::parse(tup, atom.args().begin()); return tup; } } #endif diff --git a/cpp/src/instructions/instr-containers.cpp b/cpp/src/instructions/instr-containers.cpp index 5f7bfbc..793aec7 100644 --- a/cpp/src/instructions/instr-containers.cpp +++ b/cpp/src/instructions/instr-containers.cpp @@ -1,470 +1,501 @@ #include "instr-containers.h" #include "llvmlayer.h" #include "ast.h" #include "query/containers.h" #include "query/ptrvalid.h" using namespace std; using namespace llvm; using namespace xreate; using namespace xreate::containers; #define NAME(x) (hintRetVar.empty()? x : hintRetVar) - +#define UNUSED(x) (void)(x) #define EXPAND_CONTEXT \ LLVMLayer* llvm = context.pass->man->llvm; \ CompilePass::CodeScopeUnit* scope = context.scope; \ CompilePass::FunctionUnit* function = context.function; \ Instructions::Instructions(CompilePass::Context ctx) : context(ctx), tyNum (static_cast (ctx.pass->man->llvm->toLLVMType(ExpandedType(TypeAnnotation(TypePrimitive::Num))))) {} llvm::Value* Instructions::compileMapSolid(const Expression &expr, const std::string hintRetVar) { EXPAND_CONTEXT //initialization std::string varIn = expr.getOperands()[0].getValueString(); Symbol symbolIn = scope->scope->findSymbol(varIn); 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->__args[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::getGlobalContext(), "loop", function->raw); llvm::BasicBlock *blockBeforeLoop = builder.GetInsertBlock(); llvm::BasicBlock *blockAfterLoop = llvm::BasicBlock::Create(llvm::getGlobalContext(), "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); CompilePass::CodeScopeUnit* 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, blockLoop); //next iteration checks: Value* condAfter = builder.CreateICmpSLE(stateLoopNext, rangeTo); builder.CreateCondBr(condAfter, blockLoop, blockAfterLoop); //finalization: builder.SetInsertPoint(blockAfterLoop); return dataOut; } Value* Instructions::compileArrayIndex(const Symbol &dataSymbol, std::vector indexes, std::string hintRetVar) { EXPAND_CONTEXT + UNUSED(function); //TODO find out symbol identifier in order to name it in raw llvm; llvm::Value* data = scope->compileSymbol(dataSymbol); const Expression& decl = CodeScope::findDeclaration(dataSymbol); if (decl.op == Operator::LIST) { assert(indexes.size() == 1); return llvm->builder.CreateExtractElement(data, indexes[0], NAME("el")); } indexes.insert(indexes.begin(), llvm::ConstantInt::get(tyNum, 0)); Value *pEl = llvm->builder.CreateGEP(data, llvm::ArrayRef(indexes)); return llvm->builder.CreateLoad(pEl, NAME("el")); } Value* Instructions::compileStructIndex(llvm::Value* aggregate, const ExpandedType& t, const std::string& idx){ EXPAND_CONTEXT - + UNUSED(scope); TypeUtils types(llvm); std::vector&& fields = types.getStructFields(t); for (unsigned i=0, size = fields.size(); i refs; llvm::IntegerType* tyInt = llvm::Type::getInt32Ty(llvm::getGlobalContext()); llvm::ConstantInt* zero = llvm::ConstantInt::get(tyInt, 0, false); llvm::BasicBlock *blockSafe = llvm::BasicBlock::Create(llvm::getGlobalContext(), "safe", function->raw); // safety check: not null ptr Symbol s; if (! QueryPtrValid::assertValidPtr(s)){ PointerType* tyAggr = dyn_cast(aggregate->getType()); llvm::Value* null = llvm::ConstantPointerNull::get(tyAggr); Value* condNull = llvm->builder.CreateICmpNE(aggregate, null); llvm::BasicBlock *blockException = llvm::BasicBlock::Create(llvm::getGlobalContext(), "exception", function->raw); llvm->builder.CreateCondBr(condNull, blockSafe, blockException); llvm->initExceptionBlock(blockException); } llvm->builder.SetInsertPoint(blockSafe); std::vector indexes; //dereference pointer if (types.isPointer(t)){ indexes.push_back(zero); } indexes.push_back(ConstantInt::get(tyInt, i)); Value* addr = llvm->builder.CreateGEP(aggregate, indexes); return llvm->builder.CreateLoad(addr); } } assert(false && "not found required struct field"); } llvm::Value* Instructions::compileFold(const Expression& fold, const std::string& hintRetVar) { EXPAND_CONTEXT assert(fold.op == Operator::FOLD); //initialization: Symbol varInSymbol = scope->scope->findSymbol(fold.getOperands()[0].getValueString()); Implementation info = Query::queryImplementation(varInSymbol); Iterator* it = Iterator::create(context, varInSymbol); llvm::Value* rangeFrom = it->begin(); llvm::Value* rangeTo = 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::Value* valSat; + llvm::Value* valSat = nullptr; bool flagHasSaturation = false; //false; // TODO add `saturation` ann. llvm::BasicBlock *blockBeforeLoop = llvm->builder.GetInsertBlock(); llvm::BasicBlock *blockLoop = llvm::BasicBlock::Create(llvm::getGlobalContext(), "fold", function->raw); llvm::BasicBlock *blockAfterLoop = llvm::BasicBlock::Create(llvm::getGlobalContext(), "postfold", function->raw); llvm::BasicBlock *blockEarly = llvm::BasicBlock::Create(llvm::getGlobalContext(), "earlyret", function->raw); // * initial check Value* condBefore = llvm->builder.CreateICmpNE(rangeFrom, rangeTo); llvm->builder.CreateCondBr(condBefore, blockLoop, blockEarly); llvm->builder.SetInsertPoint(blockEarly); llvm->builder.CreateRet(accumInit); + //TODO implement saturation; add unittests; // Saturation check if (flagHasSaturation) { Value* condSat = llvm->builder.CreateICmpNE(accumInit, valSat); llvm->builder.CreateCondBr(condSat, blockLoop, blockAfterLoop); } // * create phi llvm->builder.SetInsertPoint(blockLoop); llvm::PHINode *accum = llvm->builder.CreatePHI(tyNum, 2, NAME("accum")); accum->addIncoming(accumInit, blockBeforeLoop); llvm::PHINode *stateLoop = llvm->builder.CreatePHI(rangeFrom->getType(), 2, "foldIt"); stateLoop->addIncoming(rangeFrom, blockBeforeLoop); // * loop body CodeScope* scopeLoop = fold.blocks.front(); CompilePass::CodeScopeUnit* loopUnit = function->getScopeUnit(scopeLoop); Value* elIn = it->get(stateLoop); loopUnit->bindArg(accum, move(varAccum)); loopUnit->bindArg(elIn, move(varEl)); Value* accumNext = loopUnit->compile(); // * break checks, continue checks if (flagHasSaturation) { llvm::BasicBlock *blockChecks = llvm::BasicBlock::Create(llvm::getGlobalContext(), "checks", function->raw); Value* condSat = llvm->builder.CreateICmpNE(accumNext, valSat); llvm->builder.CreateCondBr(condSat, blockChecks, blockAfterLoop); llvm->builder.SetInsertPoint(blockChecks); } // * computing next iteration state Value *stateLoopNext = it->move(stateLoop); accum->addIncoming(accumNext, llvm->builder.GetInsertBlock()); stateLoop->addIncoming(stateLoopNext, llvm->builder.GetInsertBlock()); // * next iteration checks Value* condAfter = llvm->builder.CreateICmpNE(stateLoopNext, rangeTo); llvm->builder.CreateCondBr(condAfter, blockLoop, blockAfterLoop); // finalization: llvm->builder.SetInsertPoint(blockAfterLoop); return accum; } llvm::Value* Instructions::compileIf(const Expression& exprIf, const std::string& hintRetVar) { EXPAND_CONTEXT //initialization: const Expression& condExpr = exprIf.getOperands()[0]; llvm::IRBuilder<>& builder = llvm->builder; llvm::BasicBlock *blockAfter = llvm::BasicBlock::Create(llvm::getGlobalContext(), "ifAfter", function->raw); llvm::BasicBlock *blockTrue = llvm::BasicBlock::Create(llvm::getGlobalContext(), "ifTrue", function->raw); llvm::BasicBlock *blockFalse = llvm::BasicBlock::Create(llvm::getGlobalContext(), "ifFalse", function->raw); llvm::Value* cond = scope->process(condExpr); llvm->builder.CreateCondBr(cond, blockTrue, blockFalse); builder.SetInsertPoint(blockTrue); CodeScope* scopeTrue = exprIf.blocks.front(); llvm::Value* resultTrue = function->getScopeUnit(scopeTrue)->compile(); builder.CreateBr(blockAfter); builder.SetInsertPoint(blockFalse); CodeScope* scopeFalse = exprIf.blocks.back(); llvm::Value* resultFalse = function->getScopeUnit(scopeFalse)->compile(); builder.CreateBr(blockAfter); builder.SetInsertPoint(blockAfter); llvm::PHINode *ret = builder.CreatePHI(tyNum, 2, NAME("if")); ret->addIncoming(resultTrue, blockTrue); ret->addIncoming(resultFalse, blockFalse); return ret; } + +//TODO implement switch llvm::Value* Instructions::compileSwitch(const Expression& exprSwitch, const std::string& hintRetVar){ EXPAND_CONTEXT - llvm::IRBuilder<>& builder = llvm->builder; - + UNUSED(scope); + UNUSED(function); + UNUSED(llvm); + return nullptr; + //llvm::IRBuilder<>& builder = llvm->builder; //builder.CreateSwitch() - } llvm::Value* Instructions::compileConstantArray(const Expression &expr, const std::string& hintRetVar) { EXPAND_CONTEXT + UNUSED(scope); + UNUSED(function); const size_t& __size = expr.getOperands().size(); const Expression& __data = expr; ArrayType* typList = (ArrayType*) (llvm->toLLVMType(ExpandedType(TypeAnnotation(tag_array, TypePrimitive::I32, __size)))); Type*typI32 = llvm->toLLVMType(ExpandedType(TypeAnnotation(TypePrimitive::I32))); std::vector list; list.reserve(__size); const std::vector operands = __data.getOperands(); std::transform(operands.begin(), operands.end(), std::inserter(list, list.begin()), [typI32](const Expression& e){return ConstantInt::get(typI32, e.getValueDouble());}); Value* listSource = ConstantArray::get(typList, ArrayRef(list)); /* Value* listDest = l.builder.CreateAlloca(typList, ConstantInt::get(typI32, __size), *hintRetVar); l.buil1der.CreateMemCpy(listDest, listSource, __size, 16); */ return listSource; } llvm::Value* Instructions::compileConstantStringAsPChar(const string& data, const std::string& hintRetVar) { EXPAND_CONTEXT + UNUSED(function); + UNUSED(scope); - size_t size = data.size(); Type* typPchar = PointerType::getUnqual(Type::getInt8Ty(llvm::getGlobalContext())); //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::getGlobalContext(), data); Value* rawPtrData = llvm->builder.CreateAlloca(rawData->getType(), ConstantInt::get(Type::getInt32Ty(llvm::getGlobalContext()), 1, false)); llvm->builder.CreateStore(rawData, rawPtrData); return llvm->builder.CreateCast(llvm::Instruction::BitCast, rawPtrData, typPchar, hintRetVar); } template class IteratorForward; template<> class IteratorForward : public Iterator { private: LLVMLayer* llvm; const xreate::Symbol current; const Symbol source; const ImplementationLinkedList linkedlist; CodeScope* const sourceScope; //TODO initialize ans mark as const (three fields) CompilePass::CodeScopeUnit* sourceUnit; - CompilePass::FunctionUnit* function; + CompilePass::FunctionUnit* function; //TODO is used somewhere? const Expression& sourceDecl; CompilePass::Context context; llvm::Type* sourceRawType =nullptr; public: IteratorForward(CompilePass::Context ctx, const xreate::Symbol& s, const ImplementationRec& implementation) - : context(ctx), source(implementation.source), current(s), sourceScope(source.scope), sourceDecl(CodeScope::findDeclaration(source)), - linkedlist(source), sourceUnit(new CompilePass::CodeScopeUnit(source.scope, ctx.function, ctx.pass)), llvm(ctx.pass->man->llvm) + : llvm(ctx.pass->man->llvm), current(s), source(implementation.source), linkedlist(source), sourceScope(source.scope), sourceUnit(new CompilePass::CodeScopeUnit(source.scope, ctx.function, ctx.pass)), + sourceDecl(CodeScope::findDeclaration(source)), + context(ctx) { } llvm::Value* begin() { switch(sourceDecl.op) { case xreate::Operator::LIST: { sourceRawType = Type::getInt32Ty(llvm::getGlobalContext()); return ConstantInt::get(Type::getInt32Ty(llvm::getGlobalContext()), 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* 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); return sourceUnit->process(sourceDecl.operands.at(1)); }; + + default: break; } //return null pointer if (linkedlist){ return ConstantPointerNull::getNullValue(sourceRawType); } + + assert(false && "Unknown declaration"); + return nullptr; } llvm::Value* get(Value* index,const std::string& hintRetVar="") override{ const Expression& currentDecl = CodeScope::findDeclaration(current); switch (currentDecl.op) { case xreate::Operator::LIST: { - llvm::Value* currentValue = sourceUnit->process(currentDecl); //TODO re check is it right scope(source) to compilation currentDecl + //TODO re check is it right scope(source) to compilation currentDecl. Write unittests for this. + //llvm::Value* currentValue = sourceUnit->process(currentDecl); return Instructions(context).compileArrayIndex(current, 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(); const std::string& varIn = currentDecl.getOperands()[0].getValueString(); std::string varEl = currentDecl.bindings[0]; const Symbol& symbIn = current.scope->findSymbol(varIn); auto it = std::unique_ptr(Iterator::create(context, symbIn)); Value* elIn = it->get(index, varEl); CompilePass::CodeScopeUnit* unitLoop = function->getScopeUnit(scopeLoop); unitLoop->bindArg(elIn, std::move(varEl)); return unitLoop->compile(); } case xreate::Operator::NONE: { assert(currentDecl.__state==Expression::IDENT); const Symbol& symbIn = current.scope->findSymbol(currentDecl.getValueString()); 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* move(Value* index, const std::string& hintRetVar) override{ switch(sourceDecl.op) { case xreate::Operator::LIST: case xreate::Operator::LIST_RANGE: return llvm->builder.CreateAdd(index, llvm::ConstantInt::get(llvm::Type::getInt32Ty(llvm::getGlobalContext()), 1), hintRetVar); + + default: break; } if (linkedlist){ ExpandedType tySource = llvm->ast->expandType(sourceScope->findDefinition(source)); assert(tySource->__operator == TypeOperator::ARRAY && "Linked list implementation has to have ARRAY type"); assert(tySource->__operands.size()); return Instructions(context).compileStructIndex(index, ExpandedType(TypeAnnotation(tySource->__operands.at(0))), linkedlist.fieldPointer); } + + assert(false && "Unknown declaration"); + return nullptr; } }; Iterator* Iterator::create(CompilePass::Context context, const Symbol& var){ const Implementation& data = Query::queryImplementation(var); switch(data.impl){ case ON_THE_FLY: return new IteratorForward(context, var, data.extract()); default: assert(true); } + + assert(false && "Unknown declaration"); + return nullptr; } diff --git a/cpp/src/llvmlayer.cpp b/cpp/src/llvmlayer.cpp index 2afa47c..0e34bb4 100644 --- a/cpp/src/llvmlayer.cpp +++ b/cpp/src/llvmlayer.cpp @@ -1,249 +1,246 @@ #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 using namespace llvm; using namespace xreate; using namespace std; LLVMLayer::LLVMLayer(AST* root) - :builder(getGlobalContext()), ast(root) -{ + : ast(root), builder(getGlobalContext()) { module = new llvm::Module(root->getModuleName(), llvm::getGlobalContext()); 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))); jit = builder .setEngineKind(llvm::EngineKind::JIT) .setErrorStr(&ErrStr) .setVerifyModules(true) .create(); } void LLVMLayer::print(){ llvm::PassManager PM; PM.addPass(llvm::PrintModulePass(llvm::outs(), "banner")); PM.run(*module); } llvm::BasicBlock* LLVMLayer::initExceptionBlock(llvm::BasicBlock* blockException){ initExceptionsSupport(); PointerType* tyInt8P = PointerType::getInt8PtrTy(llvm::getGlobalContext()); Value* nullInt8P = llvm::ConstantPointerNull::get(tyInt8P); builder.SetInsertPoint(blockException); llvm::Function* fAllocate = module->getFunction("__cxa_allocate_exception"); llvm::Function* fThrow = module->getFunction("__cxa_throw"); auto exception = builder.CreateCall(fAllocate, ConstantInt::get(IntegerType::getInt64Ty(getGlobalContext()), 4)); vector throwParams{exception, nullInt8P, nullInt8P}; builder.CreateCall(fThrow, ArrayRef(throwParams)); builder.CreateUnreachable(); return blockException; } 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::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::STRUCT: case TypeOperator::TUPLE: { assert(t.__operands.size()); 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(llvm::getGlobalContext(), pack, false); }; case TypeOperator::LINK: { llvm::StructType* conjuction = llvm::StructType::create(llvm::getGlobalContext()); 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); }; case TypeOperator::NONE: { switch (t.__value) { case TypePrimitive::Bool: return llvm::Type::getInt1Ty(llvm::getGlobalContext()); case TypePrimitive::I32: case TypePrimitive::Int: case TypePrimitive::Num: return llvm::Type::getInt32Ty(llvm::getGlobalContext()); case TypePrimitive::I8: return llvm::Type::getInt8Ty(llvm::getGlobalContext()); case TypePrimitive::Float: return llvm::Type::getDoubleTy(llvm::getGlobalContext()); case TypePrimitive::String: return llvm::Type::getInt8PtrTy(llvm::getGlobalContext()); default: assert(false); } } default: assert(false); } assert(false); return nullptr; } void LLVMLayer::initExceptionsSupport(){ Type* typInt8Ptr = PointerType::get(IntegerType::get(module->getContext(), 8), 0); if (!module->getFunction("__cxa_throw")) { std::vector fThrowSignature{typInt8Ptr, typInt8Ptr, typInt8Ptr}; FunctionType* tyFThrow = FunctionType::get( /*Result=*/Type::getVoidTy(module->getContext()), /*Params=*/fThrowSignature, /*isVarArg=*/false); llvm::Function::Create( /*Type=*/tyFThrow, /*Linkage=*/GlobalValue::ExternalLinkage, /*Name=*/"__cxa_throw", module); // (external, no body) } if (!module->getFunction("__cxa_allocate_exception")) { std::vectorfAllocateSignature{IntegerType::get(module->getContext(), 64)}; FunctionType* tyFAllocate = FunctionType::get( /*Result=*/typInt8Ptr, /*Params=*/fAllocateSignature, /*isVarArg=*/false); llvm::Function::Create( /*Type=*/tyFAllocate, /*Linkage=*/GlobalValue::ExternalLinkage, /*Name=*/"__cxa_allocate_exception", module); // (external, no body) } } bool TypeUtils::isStruct(const ExpandedType& ty){ const TypeAnnotation& t = ty.get(); if (t.__operator==TypeOperator::STRUCT) { 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; - const clang::PointerType* tPtr = raw->getAs(); clang::QualType pointee = raw->getPointeeType(); - const clang::Type * pointeeRaw = pointee.getTypePtr(); 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::STRUCT) ? t.get().fields : llvm->layerExtern->getStructFields( llvm->layerExtern->lookupType(t.get().__valueCustom)); } diff --git a/cpp/src/pass/abstractpass.cpp b/cpp/src/pass/abstractpass.cpp index 8ca4dc2..7eac8f0 100644 --- a/cpp/src/pass/abstractpass.cpp +++ b/cpp/src/pass/abstractpass.cpp @@ -1,15 +1,36 @@ #include "abstractpass.h" #include "attachments.h" #include "passmanager.h" using namespace std; namespace xreate { + template<> + void defaultValue(){}; + void AbstractPassBase::finish() {} AbstractPassBase::AbstractPassBase(PassManager *manager) : man(manager) { } + + template<> + void + AbstractPass::processSymbol(const std::string& ident, PassContext context) + { + const Symbol& symbol = context.scope->findSymbol(ident); + + if (__visitedSymbols.isCached(symbol)) + return; + + if (CodeScope::hasDeclaration(symbol)) { + __visitedSymbols.setCachedValue(symbol); + + PassContext context2 = context; + context2.scope = symbol.scope; + process(CodeScope::findDeclaration(symbol), context2, ident); + } + } } diff --git a/cpp/src/pass/abstractpass.h b/cpp/src/pass/abstractpass.h index da48e1c..81667b4 100644 --- a/cpp/src/pass/abstractpass.h +++ b/cpp/src/pass/abstractpass.h @@ -1,123 +1,169 @@ #ifndef ABSTRACTPASS_H #define ABSTRACTPASS_H #include "ast.h" #include "passmanager.h" #include using namespace std; namespace xreate { struct PassContext { CodeScope* scope = 0; ManagedFnPtr function; ManagedRulePtr rule; std::string varDecl; PassContext() {} PassContext&& updateScope(CodeScope* scopeNew) { PassContext context2{*this}; context2.scope = scopeNew; return std::move(context2); } ~PassContext(){} }; class PassManager; class AbstractPassBase { public: AbstractPassBase(PassManager* manager); virtual void run()=0; virtual void finish(); PassManager* man; }; + template + Output defaultValue(); + + template + class SymbolCache: private std::map{ + public: + bool isCached(const Symbol& symbol){ + return this->count(symbol); + } + + Output setCachedValue(const Symbol& symbol, Output&& value){ + this->emplace(symbol, value); + return value; + } + + Output getCachedValue(const Symbol& symbol){ + assert(this->count(symbol)); + return this->at(symbol); + } + }; + + template<> + class SymbolCache: private std::set{ + public: + bool isCached(const Symbol& symbol){ + bool result = this->count(symbol) > 0; + return result; + } + void setCachedValue(const Symbol& symbol){ + this->insert(symbol); + } + + void getCachedValue(const Symbol& symbol){ + } + }; + template class AbstractPass: public AbstractPassBase { private: - std::set __visitedSymbols; - Output __defaultValue; + SymbolCache __visitedSymbols; + + Output processSymbol(const std::string& ident, PassContext context){ + const Symbol& symbol = context.scope->findSymbol(ident); + + if (__visitedSymbols.isCached(symbol)) + return __visitedSymbols.getCachedValue(symbol); + if (CodeScope::hasDeclaration(symbol)) { + PassContext context2 = context; + context2.scope = symbol.scope; + Output&& result = process(CodeScope::findDeclaration(symbol), context2, ident); + return __visitedSymbols.setCachedValue(symbol, std::move(result)); + } + + return defaultValue(); + } public: - AbstractPass(PassManager* manager, Output defaultValue=Output()) - : AbstractPassBase(manager), __defaultValue(defaultValue) {} + AbstractPass(PassManager* manager) + : AbstractPassBase(manager){} //NOTE implement processFnCall virtual void processFnCall(ManagedFnPtr function, PassContext context) {} virtual void process(ManagedRulePtr rule) {} virtual Output process(ManagedFnPtr function){ PassContext context; context.function = function; return process(function->getEntryScope(), context); } virtual Output process(CodeScope* scope, PassContext context, const std::string& hintBlockDecl=""){ context.scope = scope; return process(scope->__body, context); } virtual Output process(const Expression& expression, PassContext context, const std::string& varDecl=""){ switch (expression.__state) { case Expression::COMPOUND: - assert(expression.op != Operator::MAP || expression.op == Operator::MAP && expression.blocks.size()); + assert(expression.op != Operator::MAP || (expression.op == Operator::MAP && expression.blocks.size())); for (const Expression &op: expression.getOperands()) { process(op, context); } for (CodeScope* scope: expression.blocks) { process(scope, context); } if (expression.op == Operator::CALL) { const std::string &calleeName = expression.getValueString(); ManagedFnPtr callee = man->root->findFunction(calleeName); if (callee) processFnCall(callee, context); } break; case Expression::IDENT: assert(context.scope); + return processSymbol(expression.getValueString(), context); - std::string ident = expression.getValueString(); - const Symbol& symbol = context.scope->findSymbol(ident); - - if (__visitedSymbols.count(symbol)) {assert(false && "Invalid state");} - __visitedSymbols.insert(symbol); - - PassContext context2 = context; - context2.scope = symbol.scope; - if (CodeScope::hasDeclaration(symbol)) { - return process(CodeScope::findDeclaration(symbol), context2, ident); - } - - break; + default: + break; } + + return defaultValue(); } void run() { ManagedRulePtr rule = man->root->begin(); while (rule.isValid()) { process(rule); ++rule; } ManagedFnPtr f = man->root->begin(); while (f.isValid()) { process(f); ++f; } } }; + + template<> + void + AbstractPass::processSymbol(const std::string& ident, PassContext context); } #endif diff --git a/cpp/src/pass/compilepass.cpp b/cpp/src/pass/compilepass.cpp index ed0d8b2..0fde4db 100644 --- a/cpp/src/pass/compilepass.cpp +++ b/cpp/src/pass/compilepass.cpp @@ -1,454 +1,457 @@ #include "compilepass.h" #include "clasplayer.h" #include #include #include "query/containers.h" #include "instructions/instr-containers.h" #include "ExternLayer.h" using namespace std; using namespace xreate; using namespace llvm; CompilePass::CodeScopeUnit::CodeScopeUnit(CodeScope* codeScope, FunctionUnit* f, CompilePass* compilePass) : scope(codeScope), pass(compilePass), function(f) {} void CompilePass::CodeScopeUnit::bindArg(llvm::Value* var, std::string&& name) { assert(scope->__vartable.count(name)); VID id = scope->__vartable.at(name); __rawVars[id] = var; } llvm::Value* CompilePass::CodeScopeUnit::convertType(llvm::Value* source, llvm::Type* tyTarget){ LLVMLayer* llvm = pass->man->llvm; if (tyTarget->isIntegerTy() && source->getType()->isIntegerTy()) { llvm::IntegerType* tyTargetInt = llvm::dyn_cast(tyTarget); llvm::IntegerType* tySourceInt = llvm::dyn_cast(source->getType()); if (tyTargetInt->getBitWidth() < tySourceInt->getBitWidth()){ return llvm->builder.CreateCast(llvm::Instruction::Trunc, source, tyTarget); } if (tyTargetInt->getBitWidth() > tySourceInt->getBitWidth()){ return llvm->builder.CreateCast(llvm::Instruction::SExt, source, tyTarget); } } assert(false && "no automatic type conversion possible"); } llvm::Value* CompilePass::CodeScopeUnit::process(const Expression& expr, const std::string& hintVarDecl){ #define VARNAME(x) (hintVarDecl.empty()? x: hintVarDecl) llvm::Value *left; llvm::Value *right; LLVMLayer& l = *pass->man->llvm; CompilePass::Context context{function, this, pass}; containers::Instructions instructions = containers::Instructions(context); switch (expr.op) { case Operator::ADD: case Operator::SUB: case Operator::MUL: case Operator::DIV: case Operator::EQU: case Operator::LSS: case Operator::GTR: assert(expr.__state == Expression::COMPOUND); assert(expr.operands.size() == 2); left = process(expr.operands[0]); right = process(expr.operands[1]); if (left->getType()!= right->getType()) { right = convertType(right, left->getType()); } break; default:; } switch (expr.op) { case Operator::ADD: return l.builder.CreateAdd(left, right, VARNAME("tmp_add")); break; case Operator::SUB: return l.builder.CreateSub(left, right, VARNAME("tmp_sub")); break; case Operator::MUL: return l.builder.CreateMul(left, right, VARNAME("tmp_mul")); break; case Operator::DIV: return l.builder.CreateSDiv(left, right, VARNAME("tmp_div")); break; case Operator::EQU: left->dump(); right->dump(); return l.builder.CreateICmpEQ(left, right, VARNAME("tmp_equ")); break; case Operator::LSS: return l.builder.CreateICmpSLT(left, right, VARNAME("tmp_lss")); break; case Operator::GTR: return l.builder.CreateICmpSGT(left, right, VARNAME("tmp_gtr")); break; case Operator::NEG: left = process(expr.operands[0]); return l.builder.CreateNeg(left, VARNAME("tmp_neg")); break; case Operator::CALL: { assert(expr.__state == Expression::COMPOUND); std::string fname = expr.getValueString(); 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); } ); FunctionUnit* calleeUnit = pass->getFunctionUnit(string(fname)); // external function if (!calleeUnit) { llvm::Function* external = pass->man->llvm->layerExtern->lookupFunction(fname); return l.builder.CreateCall(external, args, hintVarDecl); } if (calleeUnit->isInline()) { return calleeUnit->compileInline(move(args), this->function); } llvm::BasicBlock* blockPrev = pass->man->llvm->builder.GetInsertBlock(); llvm::Value* callee = calleeUnit->compile(); pass->man->llvm->builder.SetInsertPoint(blockPrev); return l.builder.CreateCall(callee, args, hintVarDecl); } case Operator::IF: { return instructions.compileIf(expr, hintVarDecl); } case Operator::SWITCH: { return nullptr; //instructions.compileSwitch(); } case Operator::LIST: { return instructions.compileConstantArray(expr, hintVarDecl); }; case Operator::LIST_RANGE: { assert(false); //no compilation phase for a range list // return InstructionList(this).compileConstantArray(expr, l, hintRetVar); }; case Operator::LIST_NAMED: { typedef Expanded ExpandedType; ExpandedType tyRaw = l.ast->expandType(expr.type); const std::vector fields = (tyRaw.get().__operator == TypeOperator::CUSTOM)? l.layerExtern->getStructFields(l.layerExtern->lookupType(tyRaw.get().__valueCustom)) : tyRaw.get().fields; std::map indexFields; for(size_t i=0, size = fields.size(); i(l.toLLVMType(tyRaw)); llvm::Value* record = llvm::UndefValue::get(tyRecord); - for (int i=0; igetElementType(fieldId); result = llvm::UndefValue::get(tyNullField); } else { result = process(operand); } assert (result); record = l.builder.CreateInsertValue(record, result, llvm::ArrayRef({fieldId})); } return record; }; case Operator::MAP: { assert(expr.blocks.size()); return instructions.compileMapSolid(expr, VARNAME("map")); }; case Operator::FOLD: { return instructions.compileFold(expr, VARNAME("fold")); }; case Operator::INDEX: { //TODO allow multiindex assert(expr.operands.size()==1); const std::string &ident = expr.getValueString(); Symbol s = scope->findSymbol(ident); const TypeAnnotation& t = s.scope->findDefinition(s); const ExpandedType& t2 = pass->man->root->expandType(t); switch (t2.get().__operator) { case TypeOperator::STRUCT: case TypeOperator::CUSTOM: { Expression idx = expr.operands.at(0); assert(idx.__state == Expression::STRING); std::string idxField = idx.getValueString(); llvm::Value* aggr = compileSymbol(s, ident); return instructions.compileStructIndex(aggr, t2, idxField); }; case TypeOperator::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(s, indexes, VARNAME(string("el_") + ident)); }; default: assert(false); } }; case Operator::NONE: assert(expr.__state != Expression::COMPOUND); switch (expr.__state) { case Expression::IDENT: { const std::string &ident = expr.getValueString(); Symbol s = scope->findSymbol(ident); return compileSymbol(s, ident); } case Expression::NUMBER: { int literal = expr.getValueDouble(); return llvm::ConstantInt::get(llvm::Type::getInt32Ty(llvm::getGlobalContext()), literal); } case Expression::STRING: { return instructions.compileConstantStringAsPChar(expr.getValueString(), hintVarDecl); }; - + default: { + break; + } }; break; + default: break; + } assert(false); return 0; } llvm::Value* CompilePass::CodeScopeUnit::compile(const std::string& hintBlockDecl){ if (raw != nullptr) return raw; if (!hintBlockDecl.empty()) { llvm::BasicBlock *block = llvm::BasicBlock::Create(llvm::getGlobalContext(), hintBlockDecl, function->raw); pass->man->llvm->builder.SetInsertPoint(block); } raw = process(scope->__body); return raw; } llvm::Value* CompilePass::CodeScopeUnit::compileSymbol(const Symbol& s, std::string hintRetVar) { CodeScope* scope = s.scope; CodeScopeUnit* self = function->getScopeUnit(scope); if (self->__rawVars.count(s.identifier)) { return self->__rawVars[s.identifier]; } return self->__rawVars[s.identifier] = self->process(scope->findDeclaration(s), hintRetVar); } bool CompilePass::FunctionUnit::isInline(){ Symbol ret = Symbol{0, function->__entry}; bool flagOnTheFly = SymbolAttachments::get(ret, false); return flagOnTheFly; } llvm::Function* CompilePass::FunctionUnit::compile(){ if (raw != nullptr) return raw; std::vector types; LLVMLayer* llvm = pass->man->llvm; CodeScope* entry = function->__entry; std::transform(entry->__args.begin(), entry->__args.end(), std::inserter(types, types.end()), [this, llvm, entry](const std::string &arg)->llvm::Type* { assert(entry->__vartable.count(arg)); VID argid = entry->__vartable.at(arg); assert(entry->__definitions.count(argid)); return llvm->toLLVMType(pass->man->root->expandType(entry->__definitions.at(argid))); }); llvm::FunctionType *ft = llvm::FunctionType::get(llvm->toLLVMType(pass->man->root->expandType(entry->__definitions[0])), types, false); raw = llvm::cast(llvm->module->getOrInsertFunction(function->__name, ft)); CodeScopeUnit* entryCompilation = getScopeUnit(entry); llvm::Function::arg_iterator fargsI = raw->arg_begin(); for (std::string &arg : entry->__args) { VID argid = entry->__vartable[arg]; entryCompilation->__rawVars[argid] = fargsI; fargsI->setName(arg); ++fargsI; } const std::string blockName = "entry"; llvm->builder.CreateRet(entryCompilation->compile(blockName)); llvm->moveToGarbage(ft); return raw; } -//TEST FunctionUnit::compileInline llvm::Value* CompilePass::FunctionUnit::compileInline(std::vector &&args, CompilePass::FunctionUnit* outer){ CodeScopeUnit* entryCompilation = outer->getScopeUnit(function->__entry); for(int i=0, size = args.size(); ibindArg(args.at(i), string(entryCompilation->scope->__args.at(i))); } return entryCompilation->compile(); } CompilePass::CodeScopeUnit* CompilePass::FunctionUnit::getScopeUnit(CodeScope* scope){ if (!scopes.count(scope)){ CodeScopeUnit* unit = new CodeScopeUnit(scope, this, pass); scopes.emplace(scope, std::unique_ptr(unit)); } return scopes.at(scope).get(); } CompilePass::CodeScopeUnit* CompilePass::FunctionUnit::getEntry(){ return getScopeUnit(function->getEntryScope()); } CompilePass::CodeScopeUnit* CompilePass::FunctionUnit::getScopeUnit(ManagedScpPtr scope){ return getScopeUnit(&*scope); } CompilePass::FunctionUnit* CompilePass::getFunctionUnit(const CompilePass::FunctionQuery& f){ ManagedFnPtr fkey = man->root->findFunction(f.name); //external functions: if (!fkey){ return nullptr; } if (!functions.count(&*fkey)){ functions.emplace(&*fkey, std::unique_ptr(new FunctionUnit(fkey, this))); } return functions.at(&*fkey).get(); } void CompilePass::run(){ //Find out main function; - ClaspLayer::ModelRange model = man->clasp->query(Config::get("function-entry")); + ClaspLayer::ModelFragment model = man->clasp->query(Config::get("function-entry")); assert(model && "Error: No entry function found"); assert(model->first != model->second && "Error: Ambiguous entry function"); string nameMain = std::get<0>(ClaspLayer::parse(model->first->second)); FunctionUnit* unitMain = getFunctionUnit(move(nameMain)); entry = unitMain->compile(); } llvm::Function* CompilePass::getEntryFunction(){ assert(entry); return entry; } //CODESCOPE COMPILATION PHASE //FIND SYMBOL(compilation phase): //if (!forceCompile) //{ // return result; //} // //search in already compiled vars //if (__rawVars.count(vId)) //{ // return result; //} //if (!__declarations.count(vId)) { // //error: symbol is uncompiled scope arg // assert(false); //} //const Expression& e = __declarations.at(vId); //__rawVars[vId] = process(e, l, name); //FIND FUNCTION //llvm::Function* //CompilePass::findFunction(const std::string& name){ // ManagedFnPtr calleeFunc = man->root->findFunction(name); // assert(calleeFunc.isValid()); // return nullptr; //} diff --git a/cpp/src/pass/dfgpass.cpp b/cpp/src/pass/dfgpass.cpp index 197541f..5520d2f 100644 --- a/cpp/src/pass/dfgpass.cpp +++ b/cpp/src/pass/dfgpass.cpp @@ -1,184 +1,187 @@ #include "dfgpass.h" #include "passmanager.h" #include "clasplayer.h" #include -using namespace xreate; using namespace std; +namespace xreate{ DFGPass::DFGPass(PassManager* manager) : AbstractPass(manager), clasp(man->clasp) {} SymbolNode DFGPass::process(ManagedFnPtr function){ SymbolNode symbolRet = AbstractPass::process(function); if (SymbolPacked* symbolRetPacked = boost::get(&symbolRet)){ Expression retExpr(Operator::CALL, {Atom(Config::get("clasp.ret.symbol")), Atom(boost::str(boost::format("(%1%, %2%)") %(symbolRetPacked->identifier) % (symbolRetPacked->scope))) }); const std::vector tag{{retExpr, TagModifier::NONE}}; clasp->cfagraph.addFunctionNodeTags(function->getName(), tag); } else if (SymbolTransient* symbT = boost::get(&symbolRet)){ std::vector tags; tags.reserve(symbT->tags.size()); const std::string stmntRetTag = Config::get("clasp.ret.tag"); std::transform(symbT->tags.begin(), symbT->tags.end(), std::inserter(tags, tags.begin()), [&stmntRetTag](const Expression& e) { Expression tag(Operator::CALL, {Atom(string(stmntRetTag)), e}); return Tag{e, TagModifier::NONE}; }); clasp->cfagraph.addFunctionNodeTags(function->getName(), tags); } + + return SymbolInvalid(); } SymbolNode DFGPass::process(const Expression& expression, PassContext context, const std::string& decl) { // write down adhoc expression tags: if (expression.tags.size() && decl.length()) { for (pair tag: expression.tags) { - SymbolNode nodeThis = clasp->pack(context.scope->findSymbol(decl), decl); + SymbolNode nodeThis = clasp->pack(context.scope->findSymbol(decl), context.function->getName() + ":" + decl); __context.graph.addTag(nodeThis, Expression(tag.second)); } } switch(expression.__state) { - case Expression::IDENT: + case Expression::IDENT: { const string& ident = expression.getValueString(); SymbolNode nodeFrom = AbstractPass::process(expression, context, decl); - SymbolPacked nodeTo = clasp->pack(context.scope->findSymbol(ident)); + SymbolPacked nodeTo = clasp->pack(context.scope->findSymbol(ident), context.function->getName() + ":" + ident); __context.graph.addLink(nodeTo, nodeFrom, DFGConnection::ALIAS); return nodeTo; + } + + default: break; } //special case for NONE value: if (expression.isNone()){ return SymbolTransient{{Atom(Config::get("clasp.nonevalue"))}}; } switch(expression.op) { case Operator::CALL: { const string &name = expression.getValueString(); std::vector operands; operands.reserve(expression.getOperands().size()); for (const Expression &op: expression.getOperands()) { operands.push_back(process(op, context)); } ManagedFnPtr function = man->root->findFunction(name); if (!function) return SymbolInvalid(); // set calling relations: CodeScope *scopeRemote = function->getEntryScope(); - std::vector::iterator op = operands.begin(); - for (const std::string &arg: scopeRemote->__args) { - const Symbol &nodeRemote = scopeRemote->findSymbol(arg); - - SymbolPacked* operandPacked = boost::get(&*op); - assert(operandPacked); - __context.graph.addLink(clasp->pack(nodeRemote), *operandPacked, DFGConnection::OPT); - ++op; + std::vector::iterator nodeActual = operands.begin(); + for (const std::string &identFormal: scopeRemote->__args) { + const Symbol &symbolFormal = scopeRemote->findSymbol(identFormal); + __context.graph.addLink(clasp->pack(symbolFormal, name + ":" + identFormal), *nodeActual, DFGConnection::OPT); + ++nodeActual; } //TODO need SymbolTransient::connection mark in order to represent OPT connection - return clasp->pack(Symbol{0, scopeRemote}); + return clasp->pack(Symbol{0, scopeRemote}, name + ": *retv"); } + + default: break; } - std::vector operands; + + + SymbolNode result = AbstractPass::process(expression, context, decl); if (expression.__state != Expression::COMPOUND){ - AbstractPass::process(expression, context, decl); - return SymbolInvalid(); + return result; } + std::vector operands; if (__signatures.count(expression.op)) { const Expression &scheme = __signatures.at(expression.op); operands.reserve(expression.getOperands().size()); if (expression.op == Operator::CALL || expression.op == Operator::INDEX){ string caption = expression.getValueString(); operands.push_back(process(Expression(move(caption)), context, "")); } for (const Expression &op: expression.getOperands()) { operands.push_back(process(op, context)); } std::vector::iterator arg = operands.begin(); std::vector::const_iterator tag = ++scheme.getOperands().begin(); while (tag != scheme.getOperands().end()) { if (tag->__state != Expression::INVALID) { __context.graph.addTag(*arg, Expression(*tag)); } ++arg; ++tag; } Expression retTag = *scheme.getOperands().begin(); if (retTag.__state != Expression::INVALID) { - return SymbolTransient{{retTag}}; + __context.graph.addTag(result, move(retTag)); } } - // adhoc for MAP case, TODO reorganize code in more clear manner - if (expression.op == Operator::MAP) { + // adhoc for MAP case, TODO reorganize code in more clear manner + if (expression.op == Operator::MAP) { SymbolNode nodeFrom; - if (operands.size()) { - nodeFrom = operands.at(0); - } else { - nodeFrom = process(expression.getOperands().at(0), context); - } + if (operands.size()) { + nodeFrom = operands.at(0); + } else { + nodeFrom = process(expression.getOperands().at(0), context); + } - assert(!decl.empty()); - SymbolPacked nodeTo = clasp->pack(context.scope->findSymbol(decl)); + assert(!decl.empty()); + SymbolPacked nodeTo = clasp->pack(context.scope->findSymbol(decl), context.function->getName() + ":" + decl); SymbolPacked* nodeFromPacked = boost::get(&nodeFrom); assert(nodeFromPacked); __context.graph.addLink(move(nodeTo), *nodeFromPacked, DFGConnection::PROTO); - } - - if (__signatures.count(expression.op) || expression.op == Operator::MAP) { - for (CodeScope* scope: expression.blocks) { - AbstractPass::process(scope, context); - } - - return SymbolInvalid(); - } + } - return SymbolInvalid(); + return result; } void DFGPass::run() { init(); return AbstractPass::run(); } void DFGPass::init() { for (const Expression& scheme: man->root->__dfadata) { __signatures.emplace(scheme.op, scheme); } } void DFGPass::finish() { man->clasp->addDFAData(move(__context.graph)); } + +template<> +SymbolNode defaultValue(){return SymbolInvalid();}; + +} diff --git a/cpp/src/pass/environmenttestspass.cpp b/cpp/src/pass/environmenttestspass.cpp new file mode 100644 index 0000000..bac56b7 --- /dev/null +++ b/cpp/src/pass/environmenttestspass.cpp @@ -0,0 +1,30 @@ +/* + * environmenttestspass.cpp + * + * Created on: Nov 17, 2015 + * Author: pgess + */ + +#include +#include + +void +EnvironmentTestsPass::run(){ + + list arftefacts = solver->query("depends(env())"); + + //check artifacts + for (artefact: artifacts){ + Function funcProbe = findProberForArtefact(artefact); + + result = funcProbe->run(); + results->save(result); + } + + for (artefact: artefacts){ + if (results->getResult(artefact)){ + Function funcProvider = findProviderForArtefact(artefact); + funcProvider->run(); + } + } +} diff --git a/cpp/src/pass/environmenttestspass.h b/cpp/src/pass/environmenttestspass.h new file mode 100644 index 0000000..651acda --- /dev/null +++ b/cpp/src/pass/environmenttestspass.h @@ -0,0 +1,17 @@ +/* + * environmenttestspass.h + * + * Created on: Nov 17, 2015 + * Author: pgess + */ + +#ifndef SRC_PASS_ENVIRONMENTTESTSPASS_H_ +#define SRC_PASS_ENVIRONMENTTESTSPASS_H_ + + + +class EnvironmentTestsPass { + +} + +#endif /* SRC_PASS_ENVIRONMENTTESTSPASS_H_ */ diff --git a/cpp/src/query/containers.cpp b/cpp/src/query/containers.cpp index 0881b47..662f41e 100644 --- a/cpp/src/query/containers.cpp +++ b/cpp/src/query/containers.cpp @@ -1,161 +1,163 @@ // // Created by pgess on 3/14/15. // #include #include "query/containers.h" using namespace std; using namespace xreate::containers; using namespace xreate; Implementation Query::queryImplementation(xreate::Symbol const &s) { typedef SymbolAttachments attach; if (attach::exists(s)) { return attach::get(s); } return Implementation::create(s); } void Query::init(ClaspLayer* clasp) { if (flagIsDataLoaded) return; map prototypes; map roots; //read all proto data auto range = clasp->query(Config::get("containers.id.prototypes")); if (range) for(ClaspLayer::ModelIterator atom = range->first; atom != range->second; ++atom) { auto data = ClaspLayer::parse(atom->second); Symbol root = clasp->unpack(get<0> (data)); Symbol prototype = clasp->unpack(get<1> (data)); prototypes[root] = prototype; } // fill implementation data for a data sources: range = clasp->query(Config::get("containers.id.implementations")); if (range) for(ClaspLayer::ModelIterator atom = range->first; atom != range->second; ++atom) { auto data = ClaspLayer::parse(atom->second); Symbol var = clasp->unpack(get<0>(data)); string implSerialized = get<1>(data); //data source, has no prototypes: if (!prototypes.count(var)) { Implementation impl = Implementation::create(var); SymbolAttachments::put(var, move(impl)); continue; } roots.emplace(move(var), move(implSerialized)); } //fill implementation data for a cluster roots for (const pair & root: roots) { Symbol prototype = prototypes[root.first]; while (prototypes.count(prototype)) { prototype = prototypes.at(prototype); } SymbolAttachments::put(root.first, Implementation(SymbolAttachments::get(prototype))); } // read cluster data and fill implementation data for cluster members range = clasp->query(Config::get("containers.id.clusters")); if (range) for(ClaspLayer::ModelIterator atom = range->first; atom != range->second; ++atom) { auto info = ClaspLayer::parse(atom->second); Symbol root = clasp->unpack(get<0>(info)); Symbol child = clasp->unpack(get<1>(info)); if (!(child == root)) { Implementation rootImpl = SymbolAttachments::get(root); SymbolAttachments::put(child, move(rootImpl)); } } flagIsDataLoaded = true; } //static ImplementationData* create(Symbol var, std::string implSerialized, const ImplementationData* implPrototype); Implementation Implementation::create(const Symbol &var) { Expression varDecl = CodeScope::findDeclaration(var); switch (varDecl.op) { case Operator::LIST_RANGE: { ImplementationRec rec{var}; return {ON_THE_FLY, rec}; } case Operator::LIST: { return {SOLID, ImplementationRec {varDecl.getOperands().size()}}; } + + default: break; }; ImplementationLinkedList ill(var); if (ill){ return ill.getImplementationData(); } assert(false && "Unable to determine proper implementation for the symbol"); } Implementation Implementation::create(const Symbol& var, const std::string& implSerialized) { Expression varDecl = CodeScope::findDeclaration(var); if (implSerialized == Config::get("containers.impl.solid")) { return {SOLID, ImplementationRec{varDecl.operands.size()}}; } else if (implSerialized == Config::get("containers.impl.onthefly")) { return {ON_THE_FLY, ImplementationRec{var}}; } assert(false && "unable to determine proper implementation for the symbol"); } ImplementationLinkedList::ImplementationLinkedList(const Symbol& source) : flagIsValid(false), s(source){ const Expression& sourceExpr = CodeScope::findDeclaration(source); if (sourceExpr.tags.count(Config::get("containers.id.linkedlist"))){ flagIsValid = true; Expression tagLinkedlist = sourceExpr.tags.at(Config::get("containers.id.linkedlist")); assert(tagLinkedlist.operands.size() == 2); fieldPointer = tagLinkedlist.operands.at(0).getValueString(); terminator = tagLinkedlist.operands.at(1); } } ImplementationLinkedList:: operator bool () const{ return flagIsValid; } Implementation ImplementationLinkedList::getImplementationData() const { return {ON_THE_FLY, ImplementationRec{s}}; } diff --git a/cpp/tests/CFGtests.cpp b/cpp/tests/CFGtests.cpp index 44e92ef..cbda26a 100644 --- a/cpp/tests/CFGtests.cpp +++ b/cpp/tests/CFGtests.cpp @@ -1,62 +1,62 @@ /* * testsCFG.cpp * * Created on: Jul 17, 2015 * Author: pgess */ #include "passmanager.h" #include "pass/dfgpass.h" #include "gtest/gtest.h" using namespace xreate; using namespace std; TEST(CFG, testFunctionAnnotationsClasp){ string&& program = "f2 = function()::int; annotationF2 {\n" " 0\n" "}\n" "\n" "f1 = function():: int; entry; annotationF1 {\n" " f2() + 10\n" "}"; PassManager* man = PassManager::prepareForCode(move(program)); man->runWithoutCompilation(); - ClaspLayer::ModelRange answer = man->clasp->query("annotationF1"); + ClaspLayer::ModelFragment answer = man->clasp->query("annotationF1"); int countNoneValue = 0; if (answer) countNoneValue = std::distance(answer->first, answer->second); EXPECT_EQ(1, countNoneValue); answer = man->clasp->query("annotationF2"); countNoneValue = 0; if (answer) countNoneValue = std::distance(answer->first, answer->second); - EXPECT_EQ(1, countNoneValue); + EXPECT_EQ(1, countNoneValue); } TEST(CFG, testLoopContextExists){ PassManager* man = PassManager::prepareForCode ( "interface(cfa){\n" " operator fold:: annotation1.\n" "}\n" "\n" "main = function() :: int; entry {\n" " x = [1..10]:: [int].\n" " sum = loop fold (x->el:: int, 0->sum:: int):: [int] {\n" " el + sum + f1()\n" " }. \n" " sum\n" "}" "f1 = function()::int {\n" " x = 0:: int. " " x\n" "}" ); man->runWithoutCompilation(); } diff --git a/cpp/tests/DFGtests.cpp b/cpp/tests/DFGtests.cpp index fd82f58..7371367 100644 --- a/cpp/tests/DFGtests.cpp +++ b/cpp/tests/DFGtests.cpp @@ -1,42 +1,42 @@ /* * DFGtests.cpp * * Created on: Jul 23, 2015 * Author: pgess */ #include "passmanager.h" #include "pass/dfgpass.h" #include "gtest/gtest.h" using namespace xreate; using namespace std; TEST(DFG, testFunctionRetSymbolExists){ PassManager* man = PassManager::prepareForCode ("test = function():: int; entry {\n" " data = [1..5]::[int].\n" " \n" " result = loop fold(data->i::int, 0->sum::int)::int{\n" " if (i==3)::int {valNull = null. valNull} else {i+sum}\n" " }.\n" " \n" " result\n" "}"); man->runWithoutCompilation(); - ClaspLayer::ModelRange answer = man->clasp->query(Config::get("clasp.ret.symbol")); + ClaspLayer::ModelFragment answer = man->clasp->query(Config::get("clasp.ret.symbol")); if (answer) EXPECT_EQ(1, std::distance(answer->first, answer->second)); for (auto functionIt = answer->first; functionIt != answer->second; ++functionIt){ auto ret = ClaspLayer::parse(functionIt->second); ASSERT_EQ("test", std::get<0>(ret)); SymbolPacked symbolRet = std::get<0>(ClaspLayer::parse(std::get<1>(ret))); ASSERT_EQ(3, symbolRet.identifier); ASSERT_EQ(0, symbolRet.scope); } } diff --git a/cpp/tests/ast.cpp b/cpp/tests/ast.cpp index 2929080..7c4de20 100644 --- a/cpp/tests/ast.cpp +++ b/cpp/tests/ast.cpp @@ -1,41 +1,49 @@ /* * ast.cpp * * Created on: Jun 11, 2015 * Author: pgess */ #include "gtest/gtest.h" #include "passmanager.h" #include "Parser.h" using namespace std; using namespace xreate; TEST(AST, Containers1){ FILE* input = fopen("scripts/testspass/Containers_Implementation_LinkedList1.xreate","r"); Scanner scanner(input); Parser parser(&scanner); parser.Parse(); const AST& ast = parser.root; fclose(input); } -TEST(AST, CFAData) { +TEST(AST, InterfacesDataCFA) { PassManager* man = PassManager::prepareForCode ("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, DISABLED_InterfacesDataDFA){ + +} + +TEST(AST, DISABLED_InterfacesDataExtern){ + +} + diff --git a/cpp/tests/compilation.cpp b/cpp/tests/compilation.cpp new file mode 100644 index 0000000..c305e3e --- /dev/null +++ b/cpp/tests/compilation.cpp @@ -0,0 +1,5 @@ +#include "gtest/gtest.h" + +//TEST FunctionUnit::compileInline +TEST(Compilation, DISABLED_functionInline1){ +} diff --git a/cpp/tests/containers.cpp b/cpp/tests/containers.cpp index 4c149bc..611ccfe 100644 --- a/cpp/tests/containers.cpp +++ b/cpp/tests/containers.cpp @@ -1,57 +1,54 @@ /* * containers.cpp * * Created on: Jun 9, 2015 * Author: pgess */ #include "gtest/gtest.h" #include "passmanager.h" #include "Parser.h" #include "query/containers.h" using namespace std; using namespace xreate; using namespace containers; -TEST(Containers, DISABLED_DFAData1){ -} - TEST(Containers, ContanierLinkedList1){ FILE* input = fopen("scripts/testspass/Containers_Implementation_LinkedList1.xreate","r"); assert(input != nullptr); Scanner scanner(input); Parser parser(&scanner); parser.Parse(); AST& ast = parser.root; CodeScope* body = ast.findFunction("test")->getEntryScope(); Symbol symb_chilrenRaw = body->findSymbol("childrenRaw"); 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/testspass/Containers_Implementation_LinkedList1.xreate","r"); assert(input != nullptr); Scanner scanner(input); std::unique_ptr program(PassManager::prepareForCode(scanner)); void* mainPtr = program->run(); int (*main)() = (int (*)())(intptr_t)mainPtr; int answer = main(); ASSERT_EQ(16, answer); fclose(input); } diff --git a/cpp/tests/diagnostic-messages.cpp b/cpp/tests/diagnostic-messages.cpp new file mode 100644 index 0000000..b46cdf0 --- /dev/null +++ b/cpp/tests/diagnostic-messages.cpp @@ -0,0 +1,28 @@ +/* + * diagnostic-messages.cpp + * + * Created on: Oct 27, 2015 + * Author: pgess + */ + +#include "gtest/gtest.h" + +using namespace std; + +TEST(Diagnostic_DFA, DISABLED_recursion1){ + + //Error while processing recursion, Should be some diagnostic complaints + std::string code = \ + "test1 = function()::[int] {\n" + " varRecursion = loop map(varRecursion->el:: int)::[int]{\n" + " el\n" + " }.\n" + " \n" + " varRecursion\n" + "}"; + + PassManager* man = PassManager::prepareForCode(code); + DFGPass* pass = new DFGPass(man); + pass->run(); + pass->finish(); +} diff --git a/cpp/tests/externc.cpp b/cpp/tests/externc.cpp index ae6287a..ba12e3c 100644 --- a/cpp/tests/externc.cpp +++ b/cpp/tests/externc.cpp @@ -1,104 +1,104 @@ #include "gtest/gtest.h" #include "passmanager.h" #include "Scanner.h" #include "Parser.h" #include #include using namespace std; TEST(InterfaceExternC, testAST){ std::string code = " \ interface(extern-c){ \ xml2 = library:: pkgconfig(\"libxml-2.0\"). \ \ include { \ xml2 = [\"libxml/tree.h\"] \ }. \ } \ "; Scanner scanner(reinterpret_cast(code.c_str()), code.size()); 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("-lxml2", args.at(0)); + 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\ }. \n\ }\n" "main= function():: int; entry{arc4random() }"; std::unique_ptr program(PassManager::prepareForCode(move(code))); void* entryPtr = program->run(); int (*entry)() = (int (*)())(intptr_t)entryPtr; int answer = 24; answer = entry(); cout << answer; ASSERT_NE(24, answer); } TEST(InterfaceExternC, testStructFields1){ FILE* input = fopen("scripts/testspass/Containers_Implementation_LinkedList1.xreate","r"); assert(input != nullptr); Scanner scanner(input); Parser parser(&scanner); parser.Parse(); AST& ast = parser.root; CodeScope* body = ast.findFunction("test")->getEntryScope(); Symbol symbTree = body->findSymbol("tree"); const TypeAnnotation& tTree = CodeScope::findDefinition(symbTree); const ExpandedType& t2Tree = ast.expandType(tTree); 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/pointers.cpp b/cpp/tests/pointers.cpp new file mode 100644 index 0000000..e2e05a9 --- /dev/null +++ b/cpp/tests/pointers.cpp @@ -0,0 +1,9 @@ +#include "gtest/gtest.h" + +TEST(Pointers, DISABLED_validptr1){ + +} + +TEST(Pointers, DISABLED_localscopeptr1){ + +} diff --git a/cpp/tests/safety.cpp b/cpp/tests/safety.cpp index 2af6879..e69de29 100644 --- a/cpp/tests/safety.cpp +++ b/cpp/tests/safety.cpp @@ -1,9 +0,0 @@ -#include "gtest/gtest.h" - -/** - * Safety checks: - * (*) valid ptr (not null) - */ -TEST(Safety, validptr1){ - -} diff --git a/cpp/tests/skipdetection.cpp b/cpp/tests/skipdetection.cpp index 5ccb14b..c1ba1a2 100644 --- a/cpp/tests/skipdetection.cpp +++ b/cpp/tests/skipdetection.cpp @@ -1,32 +1,32 @@ /* * skipdetection.cpp * * Created on: Jul 10, 2015 * Author: pgess */ #include "passmanager.h" #include "clasplayer.h" #include "gtest/gtest.h" using namespace xreate; using namespace std; TEST(SkipDetection, testNoneValueTagExists){ PassManager* man = PassManager::prepareForCode ("test = function():: int; entry {\n" " data = [1..5]::[int].\n" " \n" " result = loop fold(data->i::int, 0->sum::int)::int{\n" " if (i==3)::int {valNull = null. valNull} else {i+sum}\n" " }.\n" " \n" " result\n" "}"); man->runWithoutCompilation(); - ClaspLayer::ModelRange answer = man->clasp->query(Config::get("clasp.nonevalue")); + ClaspLayer::ModelFragment answer = man->clasp->query(Config::get("clasp.nonevalue")); int countNoneValue = 0; if (answer) countNoneValue = std::distance(answer->first, answer->second); EXPECT_EQ(1, countNoneValue); } diff --git a/cpp/tests/testBasic.cpp b/cpp/tests/testBasic.cpp index 9cb9a5c..1f1acb5 100644 --- a/cpp/tests/testBasic.cpp +++ b/cpp/tests/testBasic.cpp @@ -1,26 +1,26 @@ #include "gtest/gtest.h" #include "passmanager.h" #include "Scanner.h" #include "Parser.h" #include #include using namespace std; using namespace xreate; -TEST(EntryFunction, test1){ +TEST(Basic, functionEntry1){ std::unique_ptr program(PassManager::prepareForCode( "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); } diff --git a/cpp/tests/testClangAPI.cpp b/cpp/tests/testClangAPI.cpp index 15bcd61..0005ad2 100644 --- a/cpp/tests/testClangAPI.cpp +++ b/cpp/tests/testClangAPI.cpp @@ -1,190 +1,190 @@ // // Created by pgess on 4/16/15. // #include "gtest/gtest.h" #include #include "clang/Driver/Options.h" #include "clang/AST/AST.h" #include "clang/AST/ASTContext.h" #include "clang/AST/ASTConsumer.h" #include "clang/AST/RecursiveASTVisitor.h" #include "clang/Frontend/ASTConsumers.h" #include "clang/Frontend/FrontendActions.h" #include "clang/Frontend/CompilerInstance.h" #include "clang/Tooling/CommonOptionsParser.h" #include "clang/Tooling/Tooling.h" #include "clang/Rewrite/Core/Rewriter.h" #include "clang/ASTMatchers/ASTMatchers.h" #include "clang/ASTMatchers/ASTMatchFinder.h" #include "clang/CodeGen/CodeGenAction.h" #include "/opt/llvm-toolchain-3.6-3.6/clang/lib/CodeGen/CodeGenTypes.h" #include "/opt/llvm-toolchain-3.6-3.6/clang/lib/CodeGen/CodeGenModule.h" #include "clang/CodeGen/CodeGenABITypes.h" #include "llvm/IR/LLVMContext.h" #include "clang/Basic/TargetInfo.h" #include using namespace std; using namespace clang; using namespace clang::driver; using namespace clang::tooling; using namespace clang::ast_matchers; using namespace llvm; /* class PrintFunctionsConsumer : public ASTConsumer { public: bool HandleTopLevelDecl(DeclGroupRef DG) override { for (DeclGroupRef::iterator i = DG.begin(), e = DG.end(); i != e; ++i) { const Decl *D = *i; if (const NamedDecl *ND = dyn_cast(D)) llvm::errs() << "top-level-decl: \"" << ND->getNameAsString() << "\"\n"; } return true; } }; class PFAction : public ASTFrontendAction { public: virtual std::unique_ptr CreateASTConsumer(CompilerInstance &CI, StringRef file) { return llvm::make_unique(); } }; */ class PrinterType : public MatchFinder::MatchCallback { public : virtual void run(const MatchFinder::MatchResult &Result) { ASTContext* C = Result.Context; llvm::Module* M = new llvm::Module("module1", llvm::getGlobalContext()); if (const TypedefDecl* decl = Result.Nodes.getNodeAs("typename")) { QualType Ty = decl->getUnderlyingType(); llvm::errs() << "<" << Ty.getAsString() << ">" ; CodeGenOptions *CGO = new CodeGenOptions; const llvm::DataLayout& TD = llvm::DataLayout(C->getTargetInfo().getTargetDescription()); CodeGen::CodeGenModule *CGM = new CodeGen::CodeGenModule(*C, *CGO, *M, TD, C->getDiagnostics()); llvm::Type *rawTy = CGM->getTypes().ConvertType(Ty); rawTy->dump(); results.push_back(rawTy); } } std::vector results; }; class PrinterFunction: public MatchFinder::MatchCallback { public : virtual void run(const MatchFinder::MatchResult &Result) { if (const FunctionDecl* decl = Result.Nodes.getNodeAs("function")) { QualType Ty = decl->getType(); llvm::errs() << "<" << Ty.getAsString() << ">" ; ASTContext* C = Result.Context; llvm::Module* M = new llvm::Module("module1", llvm::getGlobalContext()); CodeGenOptions *CGO = new CodeGenOptions; const llvm::DataLayout& TD = llvm::DataLayout(C->getTargetInfo().getTargetDescription()); CodeGen::CodeGenModule *CGM = new CodeGen::CodeGenModule(*C, *CGO, *M, TD, C->getDiagnostics()); llvm::Type *rawTy = CGM->getTypes().ConvertType(Ty); //const clang::FunctionType* Ty = decl->getType()->getAs(); llvm::FunctionType* rawFuncTy = llvm::dyn_cast(rawTy); rawFuncTy->dump(); results.push_back(rawFuncTy); /* llvm::Function* fDeclaration = llvm::Function::Create(rawFuncTy, llvm::GlobalValue::ExternalLinkage, "xxxx", M); fDeclaration->dump(); */ } } std::vector results; }; //DEBT fix dependency on clasp/gcc version vector argv = { "-I/usr/include/libxml2" ,"-I/usr/local/include" ,"-I/usr/lib/llvm-3.6/lib/clang/3.6.0/include" ,"-I/usr/include" }; TEST(ClangAPI, testExternalType) { //,, "-I/usr/include/linux" // "-cc1", "-emit-pch", "-disable-free", "-disable-llvm-verifier", "-mrelocation-model", "static", // "-mthread-model", "posix", "-mdisable-fp-elim", "-fmath-errno", "-masm-verbose", // "-mconstructor-aliases", "-munwind-tables", "-fuse-init-array", "-target-cpu", "x86-64", "-target-linker-version", "2.25", //"-dwarf-column-info", "-resource-dir", "/usr/lib/llvm-3.7/bin/../lib/clang/3.7.0", //"clang", "--", /* int argc= argv.size(); llvm::cl::OptionCategory cat("aaaa"); LLVMInitializeNativeTarget(); CommonOptionsParser op(argc, &*(argv.begin()), cat); ClangTool tool(op.getCompilations(), op.getSourcePathList()); */ auto matcherType = typedefDecl(hasName("xmlNodePtr")).bind("typename"); MatchFinder finder; PrinterType printer; finder.addMatcher(matcherType, &printer); std::string code = (boost::format("#include \"%1%\"") % ("libxml/tree.h")).str(); //runToolOnCodeWithArgs(newFrontendActionFactory(&finder).get()->create(), code, argv); std::unique_ptr ast = buildASTFromCodeWithArgs(code, argv); ASTContext & context = ast->getASTContext(); finder.matchAST(context); - string signatureExpected = "%struct._xmlNode.0*"; + string signatureExpected = "%struct._xmlNode*"; ASSERT_EQ(1, printer.results.size()); llvm::Type* tyActual = printer.results.at(0); string strActual; llvm::raw_string_ostream ss(strActual); tyActual->print(ss); ASSERT_EQ(signatureExpected, ss.str()); //int x = tool.run(newFrontendActionFactory(&finder).get()); } TEST(ClangAPI, testExternalFunction){ auto matcherType = functionDecl(hasName("arc4random")).bind("function"); MatchFinder finder; PrinterFunction printer; finder.addMatcher(matcherType, &printer); std::string code = (boost::format("#include \"%1%\"") % ("bsd/stdlib.h")).str(); std::unique_ptr ast = buildASTFromCodeWithArgs(code, argv); ASTContext & context = ast->getASTContext(); finder.matchAST(context); string signatureExpected = "i32 ()"; ASSERT_EQ(1, printer.results.size()); llvm::Type* tyActual = printer.results.at(0); string strActual; llvm::raw_string_ostream ss(strActual); tyActual->print(ss); ASSERT_EQ(signatureExpected, ss.str()); } diff --git a/cpp/tests/testLibXml2.cpp b/cpp/tests/testLibXml2.cpp index ada2404..a095373 100644 --- a/cpp/tests/testLibXml2.cpp +++ b/cpp/tests/testLibXml2.cpp @@ -1,37 +1,36 @@ // // Created by pgess on 3/28/15. // #include #include #include using namespace std; TEST(libxml2, ReadXML) { - char* docname = "project/documentation.fodt" ; + char* docname = "project/documentation.fodt"; xmlDocPtr doc; xmlNodePtr cur; doc = xmlParseFile(docname); if (doc == NULL ) { fprintf(stderr,"Document not parsed successfully. \n"); return; } cur = xmlDocGetRootElement(doc); if (cur == NULL) { fprintf(stderr,"empty document\n"); xmlFreeDoc(doc); return; } cur = cur->xmlChildrenNode; int count =0; while (cur != NULL) { printf("child: %s\n", cur->name); - cur = cur->next; count ++; } ASSERT_EQ(17, count); } diff --git a/cpp/tests/tests.cpp b/cpp/tests/tests.cpp index d0e8410..66078a2 100644 --- a/cpp/tests/tests.cpp +++ b/cpp/tests/tests.cpp @@ -1,135 +1,136 @@ #include "utils.h" #include using namespace std; using namespace xreate; int main(int argc, char **argv) { testing::GTEST_FLAG(color) = "yes"; string testsTemplate = Config::get("tests.template"); string testsFilter = Config::get(string("tests.templates.") + testsTemplate); testing::GTEST_FLAG(filter) = testsFilter; testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); } +//TODO adopt useful tests //void testParser_1() //{ // shared_ptr scanner(new Scanner(L"scripts/input.xreate")); // shared_ptr parser(new Parser(scanner.get())); // parser->Parse(); // flush(cout); // AST& root = parser->root; // LLVMLayer l(&root); // root.compile(l); // root.run(l); //} //void testClasp2() //{ // shared_ptr scanner(new Scanner(L"scripts/input.xreate")); // shared_ptr parser(new Parser(scanner.get())); // parser->Parse(); // flush(cout); // if (parser->errors->count) // { // cout << "Found " << parser->errors->count << " errors. Stop" << endl; // exit(1); // } // AST& root = parser->root; // ClaspLayer clasp; // /* // FunctionTagsPass(root).run(clasp); // RulesPass(root).run(clasp); // CFGPass(&clasp).run(); // clasp.1 // run(); // */ //} //void testUnsafeCode1() //{ // shared_ptr scanner(new Scanner(L"scripts/cases/bugs-code.xreate")); // shared_ptr parser(new Parser(scanner.get())); // parser->Parse(); // flush(cout); // if (parser->errors->count) // { // cout << "Found " << parser->errors->count << " errors. Stop" << endl; // exit(1); // } // AST& root = parser->root; // ClaspLayer clasp; // /* // FunctionTagsPass(root).run(clasp); // RulesPass(root).run(clasp); // CFGPass(&clasp).run(); // //clasp.addRule(":- call(X, Y), tag(Y, unsafe), not tag(X, unsafe), function(X), function(Y)."); // clasp.run(); // */ //} //void test_DFG_1() //{ // shared_ptr scanner(new Scanner(L"scripts/input.xreate")); // shared_ptr parser(new Parser(scanner.get())); // parser->Parse(); // flush(cout); // if (parser->errors->count) // { // cout << "Found " << parser->errors->count << " errors. Stop" << endl; // exit(1); // } // PassManager m; // m.clasp = new ClaspLayer(); // m.llvm = new LLVMLayer(&parser->root); // m.root = & parser->root; // m.clasp->ast = m.root; // m.registerPass(new DFAPass(&m)); // m.run(); // m.clasp->run(); // m.root->compile(*m.llvm); // m.root->run(*m.llvm); //} //void test_Xml_1() //{ // shared_ptr scanner(new Scanner(L"scripts/input.xreate")); // shared_ptr parser(new Parser(scanner.get())); // parser->Parse(); // flush(cout); // if (parser->errors->count) // { // cout << "Found " << parser->errors->count << " errors. Stop" << endl; // exit(1); // } // PassManager m; // m.root = & parser->root; // m.clasp = new ClaspLayer(); // m.clasp->ast = m.root; // m.llvm = new LLVMLayer(&parser->root); // m.registerPass(new DFAPass(&m)); // m.run(); //} diff --git a/cpp/tests/types.cpp b/cpp/tests/types.cpp index 1f63042..0967945 100644 --- a/cpp/tests/types.cpp +++ b/cpp/tests/types.cpp @@ -1,129 +1,130 @@ /* * types.cpp * * Created on: Jun 4, 2015 * Author: pgess */ #include "gtest/gtest.h" #include "passmanager.h" #include "llvmlayer.h" #include "Parser.h" using namespace std; using namespace xreate; TEST(Types, DependantTypes1) { string&& code = "XmlNode = type alias {\n" " tag:: string,\n" " /* attrs:: [string],*/\n" " content:: string\n" "}.\n"; std::unique_ptr program(PassManager::prepareForCode(move(code))); ExpandedType typeXmlNode = program->root->findType("XmlNode"); ASSERT_EQ(TypeOperator::STRUCT, typeXmlNode->__operator); ASSERT_EQ(2, typeXmlNode->__operands.size()); ASSERT_EQ(TypePrimitive::String, typeXmlNode->__operands.at(0).__value); ASSERT_EQ(TypePrimitive::String, typeXmlNode->__operands.at(1).__value); } TEST(Types, DependantTypes2) { string&& code = "XmlNode = type alias {\n" " tag:: string,\n" " /* attrs:: [string],*/\n" " content:: string\n" "}.\n" "" "Template = type Template(Leaf) [Leaf, [Leaf[content]]]." "Concrete = type alias Template(XmlNode)."; std::unique_ptr program(PassManager::prepareForCode(move(code))); ExpandedType typeConcrete = program->root->findType("Concrete"); ASSERT_EQ(TypeOperator::TUPLE, typeConcrete->__operator); ASSERT_EQ(2, typeConcrete->__operands.size()); ASSERT_EQ(TypeOperator::STRUCT, typeConcrete->__operands.at(0).__operator); ASSERT_EQ(TypeOperator::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 alias {\n" " tag:: string,\n" " /* attrs:: [string],*/\n" " content:: string\n" "}.\n" "" "Tree = type Tree(Leaf) [Leaf, [Tree(Leaf)]]." "Concrete = type alias Tree(XmlNode)."; std::unique_ptr program(PassManager::prepareForCode(move(code))); ExpandedType typeConcrete = program->root->findType("Concrete"); ASSERT_EQ(TypeOperator::TUPLE, typeConcrete->__operator); ASSERT_EQ(2, typeConcrete->__operands.size()); ASSERT_EQ(TypeOperator::STRUCT, typeConcrete->__operands.at(0).__operator); ASSERT_EQ(TypeOperator::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 alias {\n" " tag:: string,\n" " /* attrs:: [string],*/\n" " content:: string\n" "}.\n" "" "Tree = type Tree(Leaf) [Leaf, [Tree(Leaf)]]." "Concrete = type alias Tree(XmlNode)."; std::unique_ptr program(PassManager::prepareForCode(move(code))); ExpandedType typeConcrete = program->root->findType("Concrete"); llvm::Type* raw = program->llvm->toLLVMType(typeConcrete); } TEST(Types, ArrayOfExternal1){ FILE* input = fopen("scripts/testspass/Containers_Implementation_LinkedList1.xreate","r"); assert(input != nullptr); Scanner scanner(input); Parser parser(&scanner); parser.Parse(); AST& ast = parser.root; CodeScope* body = ast.findFunction("test")->getEntryScope(); Symbol symb = body->findSymbol("childrenRaw"); const TypeAnnotation& t = CodeScope::findDefinition(symb); const ExpandedType& t2 = ast.expandType(t); EXPECT_EQ(t2->__operator, TypeOperator::ARRAY); } TEST(Types, ExternType1){ FILE* input = fopen("scripts/testspass/Containers_Implementation_LinkedList1.xreate","r"); assert(input != nullptr); Scanner scanner(input); Parser parser(&scanner); parser.Parse(); AST& ast = parser.root; CodeScope* body = ast.findFunction("test")->getEntryScope(); Symbol symbTree = body->findSymbol("tree"); const TypeAnnotation& t = CodeScope::findDefinition(symbTree); const ExpandedType& t2 = ast.expandType(t); EXPECT_EQ(t2->__operator, TypeOperator::CUSTOM); } +//TEST string type diff --git a/cpp/tests/upcoming.cpp b/cpp/tests/upcoming.cpp new file mode 100644 index 0000000..fc248d1 --- /dev/null +++ b/cpp/tests/upcoming.cpp @@ -0,0 +1,5 @@ +#include "gtest/gtest.h" + +TEST(AST, DISABLED_functionModification){ + //x = find single (...), where single - is a modification sign of a base function 'find' +} diff --git a/cpp/tests/xml.cpp b/cpp/tests/xml.cpp new file mode 100644 index 0000000..cb62100 --- /dev/null +++ b/cpp/tests/xml.cpp @@ -0,0 +1,31 @@ +#include "passmanager.h" +#include "Scanner.h" + +#include "gtest/gtest.h" + +using namespace xreate; + +TEST(Xml, Main){ + FILE* input = fopen("scripts/xml/input.xreate", "r"); + assert(input != nullptr); + + Scanner scanner(input); + PassManager* program = PassManager::prepareForCode(scanner); + + void* mainPtr = program->run(); + int (*main)() = (int (*)())(intptr_t)mainPtr; + + int answer = main(); +} + +TEST(Xml, DISABLED_AliasTuple){ + +} + +TEST(Xml, DISABLED_FoldProtoEnhanced){ + +} + +TEST(Xml, DISABLED_TransfucPropagation){ + +} diff --git a/project/subsystems.graphmlz b/project/subsystems.graphmlz deleted file mode 100644 index 571f723..0000000 Binary files a/project/subsystems.graphmlz and /dev/null differ diff --git a/scripts/environment-tests/current b/scripts/environment-tests/current new file mode 100644 index 0000000..ba337ec --- /dev/null +++ b/scripts/environment-tests/current @@ -0,0 +1,8 @@ +// install cmake +// install llvm +// install gcc +// install gtest + +function():: testEnvironment(exists(gcc)){ + exec("gcc -v") :: expectNoErrors. +} diff --git a/scripts/environment-tests/xreate-environment b/scripts/environment-tests/xreate-environment new file mode 100644 index 0000000..f7428c8 --- /dev/null +++ b/scripts/environment-tests/xreate-environment @@ -0,0 +1,60 @@ +// install cmake +// install llvm +// install gcc +// install gtest + +function():: TestEnvironment(exists(gcc)){ + exec("gcc -v") :: ExpectNoErrors; log("Check gcc"). +} + +function():: provide(gcc) { + exec("sudo apt-get install gcc"):: log("[GCC] Installation"). +} + +function():: TestEnvironment(exists(cmake)){ + exec("cmake /V"):: ExpectNoErrors; log("Check cmake"). +} + +function():: provide(cmake) { + exec("sudo apt-get install cmake"):: log("[CMake] Installation"). +} + +function():: TestEnvironment(exists(subversion)){ + exec("svn --version"):: ExpectNoErrors; log("Check svn"). +} + +function():: provide(subversion) { + exec("sudo apt-get install subversion"):: log("[Subversion] Installation"). +} + +function():: TestEnvironment(exists(scons)){ + exec("scons -v"):: ExpectNoErrors; log("Check scons"). +} + +function():: provide(scons) { + exec("sudo apt-get install scons"):: log("[Scons] Installation"). +} + +function():: TestEnvironment(exists(bison)){ + exec("bison --version"):: ExpectNoErrors; log("Check bison"). +} + +function():: provide(bison) { + exec("sudo apt-get install bison"):: log("[Bison] Installation"). +} + +//FEATURE dependent packages: Subversion +function():: provide(gringo) +{ + exec("cd /opt"). //FEATURE states: dir("/opt") + exec("svn://svn.code.sf.net/p/potassco/code/trunk") + :: log("[Potassco] cloning latest version"); + require(svn); require(rights("/opt", WRITE)). //"sudo chown -R user ./potassco" + + // + exec("scons --build-dir=release"):: require(scons) +} + +function()::{ + +} diff --git a/scripts/function-modifications/control-context.lp b/scripts/function-modifications/control-context.lp new file mode 100644 index 0000000..22d3247 --- /dev/null +++ b/scripts/function-modifications/control-context.lp @@ -0,0 +1 @@ +function_mod(func1, mod1):- %context condition diff --git a/scripts/function-modifications/current b/scripts/function-modifications/current new file mode 100644 index 0000000..1cbf57d --- /dev/null +++ b/scripts/function-modifications/current @@ -0,0 +1,92 @@ +interface(extern-c){ +xml2 = library:: pkgconfig(\"libxml-2.0\") + [\"libxml/tree.h\"]. + +include [xml2]. +} + + +a = function()::int; + enrty; bug(2530) +{ + + +} + +interface(cfg){ + context operator map:: hfgfgfgf + context function a:: optimization: mem +} + +function a :: entry; +} + +a::int. + + +result = fold(vector->el, zero -> acc) { + +} + + +main:: entry; bug(2711); unsafe; permissions(usb_access) = function(a::int, b::int)::string; { +} + +a = function() +context +main = function (a::xxs, b::fefe -> r::fdfd):: fdfdfd case attr x:: AA, BB + { + + context:: { + frdkfkfe + } + + } + + case attr + { + a() + b(). + } + + { + + + } + + context:: optimization: mem; warnings: off + { + + } { + + case { + result = a() + b() :: + } + + case a::odd { + + } + + context + result = a() + b() :: odd. + + result = a()::odd + b(). +} + + +a = function() {}{}{}{} {}{}{}{}{}{}{}{}{}{}{}{}{} + +argument +function +result +function context + +annotation several values, annotation sole value; +function xxs;fdfdfd;fdfd, fdfd;qwqwq;trtrt;iui, aaa;bbb -> qqq; www + :: entry + + case { + + a() + b() + } + + diff --git a/scripts/function-modifications/data-context.lp b/scripts/function-modifications/data-context.lp new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/scripts/function-modifications/data-context.lp @@ -0,0 +1 @@ + diff --git a/scripts/input.xreate b/scripts/input.xreate deleted file mode 100644 index bb95705..0000000 --- a/scripts/input.xreate +++ /dev/null @@ -1,106 +0,0 @@ - - -/* local scope doc ptr */ - - -XmlNode = type alias { - tag:: string, - /* attrs:: [string],*/ - content:: string -}. - -interface(extern-c){ - xml2 = library:: pkgconfig("libxml-2.0"). - - include { - xml2 = ["libxml/tree.h", "string.h"] - }. -} - -Tree = type Tree(Leaf) [Leaf, [Tree(Leaf)]]. -XmlTree = type alias Tree(XmlNode). - -Alias = type alias [String, String]. -AliasList = type alias [Alias]. - - -classesAliasQuery = function(node:: xmlNodePtr):: Alias -{ - classesPara = ["pgess1", "pgess2"] :: [String]. - - - result = - case default {none} - - case node[tag] == "style", class in classesPara, - classAlias = node[attrs, "name"], - class=node[attrs, "parent-style-name"], - { - [classAlias. class] - }. - - result. -} - - -dictAliases = function():: AliasList{ - filename = "project/documentation.fodt" :: string. - docRaw = xmlParseFile(filename) :: xmlDocPtr. - tree= xmlDocGetRootElement(docRaw) :: xmlNodePtr. - - nodeStylesRoot = find(tree, "automatic-styles"):: xmlNodePtr. - nodesStyles= nodeStylesRoot["xmlChildrenNode"]:: [xmlNodePtr]; containers:linkedlist(next, null). - - dictAliases = loop fold(nodesStyles->nodeStyle:: xmlNodePtr, []->aliases::[xmlNodePtr]):: [xmlNodePtr] { - aliases + classAliasesQuery(nodeStyle). - }. - - dictAliases -} - -test1 = function():: int; entry { - dictAliases = dictAliases():: AliasList. - - count = loop fold(dictAliases->alias::Alias, 0->count::int):: int{ - aliasName = alias[0]:: String; logging. - aliasOrigClass = alias[1]::String; logging. - - 0 + strlen(aliasName) + strlen(aliasOrigClass). - } - - count -} - -/* -toXmlNode = function (nodeRaw:: xmlNodePtr):: XmlNode -{ - {tag = nodeRaw["name"], content=null} -} - - -children = function (tree:: xmlNodePtr):: XmlTree -{ - childrenRaw = tree["xmlChildrenNode"]:: [xmlNodePtr]; containers:linkedlist(next, null). - - loop map (childrenRaw->childRaw:: xmlNodePtr):: XmlTree { - [toXmlNode(childRaw), children(childRaw)] - } -} - - -document = function (filename:: string):: XmlTree -{ - docRaw = xmlParseFile(filename) :: xmlDocPtr. - nodeRaw= xmlDocGetRootElement(docRaw) :: xmlNodePtr. - - [toXmlNode(nodeRaw), children(nodeRaw)]:: XmlTree -} - -*/ - - - - - - - diff --git a/scripts/xml/xml-client.xreate b/scripts/xml/[old] xml-client.xreate similarity index 63% rename from scripts/xml/xml-client.xreate rename to scripts/xml/[old] xml-client.xreate index dc1b2cb..5ea610f 100644 --- a/scripts/xml/xml-client.xreate +++ b/scripts/xml/[old] xml-client.xreate @@ -1,71 +1,112 @@ /* Example of c++ code: xmlDocPtr doc; xmlNodePtr cur; doc = xmlParseFile(docname.c_str()); if (doc == NULL ) { fprintf(stderr,"Document not parsed successfully. \n"); return; } cur = xmlDocGetRootElement(doc); if (cur == NULL) { fprintf(stderr,"empty document\n"); xmlFreeDoc(doc); return; } cur = cur->xmlChildrenNode; while (cur != NULL) { printf("child: %s\n", cur->name); cur = cur->next; } */ /* Default strategies: - what to do with unspecified nodes Node content strategy: - send as-is - apply transforms (all / named) - ?? skip Processing order: - dependencies */ + + default_filname = "project/documentation.fodt" : string; + +/* require ptrvalid */ +/* local scope doc ptr */ + +XmlNode = type { + tag: string; + attrs: [string]; + content: string}. + +Tree = type(Leaf) Tree [Leaf; [Tree(Leaf)]]; + +XmlTree = Tree(XmlNode); + + +children = function: (tree: xmlNodePtr)->XmlTree +{ + childrenRaw = tree[xmlChildrenNode]: [xmlNodePtr], linkedlist(next, null); + + map (childrenRaw->childRaw: xmlNodePtr) { + Tree[childRaw[name] children(childRaw)] + } +} + + +document = function: (filename: string)->XmlTree +{ + docRaw = xmlParseFile(docname.c_str()) : xmlDocPtr; + nodeRaw= xmlDocGetRootElement(docRaw) : xmlNodePtr; + + Tree [nodeRaw[name] children(nodeRaw)); +} + query = function(tree: XmlTree): [XmlTree] { children : context(children) = case default [] case (tree[0]: NeedChildren(childrenFilters), ApplyTransform(transFilters)) { loop fold (tree[1]->child: Tree(Leaf) | childrenFilters; []->accum). {accum + traverse(child): cases(transFilters) }; } node = case (node.tag == "style:style"; class = node[attrs, "style:name"]; exists(class, ParaKnownClasses)) { [class, node[attrs, "style:display-name"]]; } case default [] ; Tree[node children] | node + children } +test = function: ()->num +{ + data = query(document(default_filename)): [string, string]; + + exists(data, "pgess1"). +} + /* traverse = function(trees: [XmlTree]) : [XmlTree] loop fold(trees->tree: Tree; []->acc) acc + traverse(tree) */ \ No newline at end of file diff --git a/scripts/xml/all.xreate b/scripts/xml/all.xreate new file mode 100644 index 0000000..3cd606f --- /dev/null +++ b/scripts/xml/all.xreate @@ -0,0 +1,188 @@ +/* C++ SECTION +Example of c++ code: + + xmlDocPtr doc; + xmlNodePtr cur; + doc = xmlParseFile(docname.c_str()); + if (doc == NULL ) { + fprintf(stderr,"Document not parsed successfully. \n"); + return; + } + cur = xmlDocGetRootElement(doc); + if (cur == NULL) { + fprintf(stderr,"empty document\n"); + xmlFreeDoc(doc); + return; + } + + cur = cur->xmlChildrenNode; + while (cur != NULL) { + printf("child: %s\n", cur->name); + + cur = cur->next; + } + +*/ + +/* FEATURES SECTION + + Default strategies: + - what to do with unspecified nodes + + Node content strategy: + - send as-is + - apply transforms (all / named) + - ?? skip + + Processing order: + - dependencies + + Mapping: + * tree -> list + +*/ + +/* TODO SECTION + -- gather types aliases (tree->list mapping) + -- flyweight implementation (doc calculation, for example. based on are there more than one opened document ) +*/ + +// REQUIREMENTS SECTION +/* require ptrvalid */ +/* local scope doc ptr */ +/* singleton element check(::single) */ + +XmlAttr = type alias { + name:: String, + content:: String +}. + +XmlNode = type alias { + name:: String, /* the name of the node, or the entity */ + children:: [xmlNode], /* parent->childs link */ + content:: String, /* the content */ + attributes::[XmlAttr] /* properties list */ + + /* + void *_private; // application data + struct _xmlNode *parent; // child->parent link + struct _xmlNode *next; // next sibling link + struct _xmlNode *prev; // previous sibling link + struct _xmlDoc *doc; // the containing document + unsigned short line; // line number + */ +}. + +interface(extern-c){ + xml2 = library:: pkgconfig("libxml-2.0"). + + include { + xml2 = ["libxml/tree.h", "string.h"] + }. +} + +Tree = type Tree(Leaf) [Leaf, [Tree(Leaf)]]. +XmlTree = type alias Tree(XmlNode). + +find = .. +[xmlNodePtr]; containers:linkedlist(next, null). + + + +test1 = function():: int; entry { + dictAliases = dictAliases():: AliasList. + + count = loop fold(dictAliases->alias::Alias, 0->count::int):: int{ + aliasName = alias[0]:: String; logging. + aliasOrigClass = alias[1]::String; logging. + + count + 1 + } + + count +} + +/* +toXmlNode = function (nodeRaw:: xmlNodePtr):: XmlNode +{ + {tag = nodeRaw["name"], content=null} +} + + +children = function (tree:: xmlNodePtr):: XmlTree +{ + childrenRaw = tree["xmlChildrenNode"]:: [xmlNodePtr]; containers:linkedlist(next, null). + + loop map (childrenRaw->childRaw:: xmlNodePtr):: XmlTree { + [toXmlNode(childRaw), children(childRaw)] + } +} + + +document = function (filename:: string):: XmlTree +{ + docRaw = xmlParseFile(filename) :: xmlDocPtr. + nodeRaw= xmlDocGetRootElement(docRaw) :: xmlNodePtr. + + [toXmlNode(nodeRaw), children(nodeRaw)]:: XmlTree +} + +*/ + +Alias = type alias { + alias: String, + original: String +}. + +AliasList = type alias [Alias]. + +classesPar = ["pgess1", "pgess2"] :: [String]. +classesAliasQuery = function(node:: xmlNodePtr):: Alias +{ + result = + case default {none} + + case node[tag] == "style", class in classesPara, + classAlias = node[attrs, "name"], + class=node[attrs, "parent-style-name"], + { + [classAlias. class] + }. + + result. +} + + + +dictAliases = function():: AliasList{ + filename = "project/documentation.fodt" :: string. + docRaw = xmlParseFile(filename) :: xmlDocPtr. + tree= xmlDocGetRootElement(docRaw) :: xmlNodePtr. + + nodeStylesRoot = findNodes(tree, "office:automatic-styles"):: xmlNodePtr; single. + nodesStyles= findNodes(nodeStylesRoot, "style:style"):: [xmlNodePtr]. + + nodesChildAliases = filter(nodeStyles){ + "style:parent-style-name" in classesPar + } + + dictChildAliases = loop fold(nodesChilds->node:: xmlNodePtr, []->aliases::[Alias]) { + aliases + {alias = attr(node, "style:name"), original = attr(node, "style:parent-style-name")} + }. + + nodesDisplayAliases = filter(nodesStyles){ + "style:parent-style-name" in classesPar + } + + dictDisplayAliases = loop fold(nodesDisplayAliases->node:: xmlNodePtr, []->aliases::[Alias]) { + aliases + {alias = attr(node, "style:display-name"), original = attr(node, "style:name")} + }. + + nodesDisplayAliases + dictDisplayAliases +} + + + + + + diff --git a/scripts/xml/input.xreate b/scripts/xml/input.xreate new file mode 100644 index 0000000..e763d7f --- /dev/null +++ b/scripts/xml/input.xreate @@ -0,0 +1,142 @@ +/* C++ SECTION +Example of c++ code: + + xmlDocPtr doc; + xmlNodePtr cur; + doc = xmlParseFile(docname.c_str()); + if (doc == NULL ) { + fprintf(stderr,"Document not parsed successfully. \n"); + return; + } + cur = xmlDocGetRootElement(doc); + if (cur == NULL) { + fprintf(stderr,"empty document\n"); + xmlFreeDoc(doc); + return; + } + + cur = cur->xmlChildrenNode; + while (cur != NULL) { + printf("child: %s\n", cur->name); + + cur = cur->next; + } + +*/ + +/* FEATURES SECTION + + Default strategies: + - what to do with unspecified nodes + + Node content strategy: + - send as-is + - apply transforms (all / named) + - ?? skip + + Processing order: + - dependencies + + Mapping: + * tree -> list + +*/ + +/* TODO SECTION + -- gather types aliases (tree->list mapping) + -- flyweight implementation ('doc' field calculation, for example. based on are there more than one opened document ) +*/ + +// REQUIREMENTS SECTION +/* require ptrvalid */ +/* local scope doc ptr */ +/* singleton element check(::single) */ + +XmlAttr = type alias { + name:: string, + content:: string +}. + +XmlNode = type alias { + name:: string, /* the name of the node, or the entity */ + + content:: string, /* the content */ + attributes::[XmlAttr] /* properties list */ + + /* + children:: [xmlNode], // parent->childs link + + void *_private; // application data + struct _xmlNode *parent; // child->parent link + struct _xmlNode *next; // next sibling link + struct _xmlNode *prev; // previous sibling link + struct _xmlDoc *doc; // the containing document + unsigned short line; // line number + */ +}. + +interface(extern-c){ + xml2 = library:: pkgconfig("libxml-2.0"). + + include { + xml2 = ["libxml/tree.h", "string.h"] + }. +} + +Tree = type Tree(Leaf) [Leaf, [Tree(Leaf)]]. +XmlTree = type alias Tree(XmlNode). + +toXmlNode = function (nodeRaw:: xmlNodePtr):: XmlNode +{ + propertiesRaw = nodeRaw["properties"]:: [xmlAttrPtr]; containers:linkedlist(next, null). + properties = loop map(propertiesRaw -> property::xmlAttrPtr)::[XmlAttr]{ + {name=property["name"], content=property["children", "content"]} + }. + + {name = nodeRaw["name"], + content=nodeRaw["content"], + attributes=properties} +} + +children = function(nodeRaw::xmlDocPtr)::[XmlTree] { + childrenRaw = nodeRaw["children"]:: [xmlDocPtr]; containers:linkedlist(next, null). + + children = loop map(childrenRaw->child:: xmlDocPtr) :: [XmlTree]{ + [toXmlNode(child), children(child)] + }. + + children +} + +document = function (filename:: string):: XmlTree +{ + docRaw = xmlParseFile(filename) :: xmlDocPtr. + nodeRaw= xmlDocGetRootElement(docRaw) :: xmlNodePtr. + + [toXmlNode(nodeRaw), children(nodeRaw)]:: XmlTree +} + +traverse = function(tree:: XmlTree) :: [XmlNode] { + listOfNodes = loop fold(tree -> node:: XmlTree, []->acc:: [XmlNode]):: [XmlNode]{ + acc + node[0] + traverse(node[1]):: [XmlNode] + }. + + listOfNodes +} + +test1 = function():: int; entry { + filename = "project/documentation.fodt" :: string. + + root = document(filename):: XmlTree. + nodesAll = traverse(root):: [XmlNode]. + + result = loop fold(nodesAll->node:: XmlNode, 0->count::int):: int{ + count + if (0==strcmp(node["name"], "section")) :: int { + 1 + } else { + 0 + } + }. + + result +} diff --git a/scripts/xml/xml-backup.xreate b/scripts/xml/xml-backup.xreate deleted file mode 100644 index 7fe9246..0000000 --- a/scripts/xml/xml-backup.xreate +++ /dev/null @@ -1,65 +0,0 @@ -default_filname = "project/documentation.fodt" : string; - -/* require ptrvalid */ -/* local scope doc ptr */ - -XmlNode = type { - tag: string; - attrs: [string]; - content: string}. - -Tree = type(Leaf) Tree [Leaf; [Tree(Leaf)]]; - -XmlTree = Tree(XmlNode); - - -children = function: (tree: xmlNodePtr)->XmlTree -{ - childrenRaw = tree[xmlChildrenNode]: [xmlNodePtr], linkedlist(next, null); - - map (childrenRaw->childRaw: xmlNodePtr) { - Tree[childRaw[name] children(childRaw)] - } -} - - -document = function: (filename: string)->XmlTree -{ - docRaw = xmlParseFile(docname.c_str()) : xmlDocPtr; - nodeRaw= xmlDocGetRootElement(docRaw) : xmlNodePtr; - - Tree [nodeRaw[name] children(nodeRaw)); -} - - -query = function: (tree: XmlTree) [string, string] -{ - children : context(children) = - case default - [] - - case (tree[0]: NeedChildren(childrenFilters), ApplyTransform(transFilters)) - { - loop fold (tree[1]->child: Tree(Leaf) | childrenFilters; []->accum). - {accum + traverse(child): cases(transFilters) }; - } - - node = - case (node.tag == "style:style"; class = node[attrs, "style:name"]; exists(class, ParaKnownClasses)) - { - [class, node[attrs, "style:display-name"]]; - } - - case default - [] ; - - node + children; -} - - -test = function: ()->num -{ - data = query(document(default_filename)): [string, string]; - - exists(data, "pgess1"). -} diff --git a/scripts/xml/xml-query.xreate b/scripts/xml/xml-query.xreate deleted file mode 100644 index 60a330e..0000000 --- a/scripts/xml/xml-query.xreate +++ /dev/null @@ -1,38 +0,0 @@ -XmlNode = type { - tag: string; - attrs: [string]; - content: string}. - -Tree = type(Leaf) Tree [Leaf; [Tree(Leaf)]]. - -XmlTree = Tree(XmlNode). - -query = function(tree: XmlTree): [XmlTree] -{ - children : context(children) = - case default - [] - - case (tree[0]: NeedChildren(childrenFilters), ApplyTransform(transFilters)) - { - loop fold (tree[1]->child: Tree(Leaf) | childrenFilters; []->accum). - {accum + traverse(child): cases(transFilters) }; - } - - node = - case (node.tag == "style:style"; class = node[attrs, "style:name"]; exists(class, ParaKnownClasses)) - { - [class, node[attrs, "style:display-name"]]; - } - - case default - [] ; - - Tree[node children] | node + children -} - - /* -traverse = function(trees: [XmlTree]) : [XmlTree] - loop fold(trees->tree: Tree; []->acc) - acc + traverse(tree) - */ \ No newline at end of file diff --git a/tools/testrender/CMakeLists.txt b/tools/testrender/CMakeLists.txt index 690ae5f..b87e502 100644 --- a/tools/testrender/CMakeLists.txt +++ b/tools/testrender/CMakeLists.txt @@ -1,5 +1,10 @@ project(testrender) cmake_minimum_required(VERSION 2.8) +INCLUDE_DIRECTORIES("/usr/include/libxml2") +set(CMAKE_BUILD_TYPE Debug) +set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -g -Wall -std=c++11") + aux_source_directory(. SRC_LIST) add_executable(${PROJECT_NAME} ${SRC_LIST}) +target_link_libraries(${PROJECT_NAME} -lxml2) diff --git a/tools/testrender/main.cpp b/tools/testrender/main.cpp index 5f5419b..d86ce29 100644 --- a/tools/testrender/main.cpp +++ b/tools/testrender/main.cpp @@ -1,10 +1,134 @@ #include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include using namespace std; +char* pathTestsOutput = "/tmp/xreate-tests-output-XXXXXX"; +const string& pathComponentsGraph = "/private/prg/code/xreate/project/subsystems.graphml"; + +map tests; +set testsUnused; + +void runTests(){ + //mkstemp(pathTestsOutput); + const string &cmm_export = string("export GTEST_OUTPUT=\"xml:")+ pathTestsOutput +"\""; + const string &cmm_chdir = "cd /private/prg/code/xreate/"; + const string &cmm_runtest = "exec build/xreate"; + + const string& comm = boost::str(boost::format("(%1% && %2% && %3%)") % cmm_export % cmm_chdir % cmm_runtest); + system(comm.c_str()); +} + +void parseTestsOutput(){ + const string& queryTestCases = "//testcase[@status='run']"; + + xmlDocPtr doc = xmlParseFile(pathTestsOutput); + xmlXPathContextPtr context = xmlXPathNewContext(doc); + xmlXPathObjectPtr testcases = xmlXPathEvalExpression((xmlChar*) queryTestCases.c_str(), context); + + for (int caseId = 0; caseId < testcases->nodesetval->nodeNr; ++caseId) { + xmlNodePtr testcase = testcases->nodesetval->nodeTab[caseId]; + + string nameTestSuite((const char *) xmlGetProp(testcase->parent, (const xmlChar*)"name")); + string nameTestCase((const char *) xmlGetProp(testcase, (const xmlChar*)"name")); + bool flagSuccess = (testcase->children)? false: true; + + string testName = nameTestSuite+":"+nameTestCase; + tests.emplace(testName, flagSuccess); + testsUnused.insert(testName); + } +} + +string getTestsResultForComponent(const string& signature){ + list componentParts; + boost::split(componentParts, signature, [](const char& a){return a==',';}); + + int resNeg = 0; int resPos = 0; bool flagTestsFound = false; + for(auto test: tests){ + for(const string& signature: componentParts){ + if (boost::icontains(test.first, signature)){ + if (test.second){ + resPos ++; + } else { + resNeg--; + } + + flagTestsFound = true; + testsUnused.erase(test.first); + break; + } + } + } + + if (!flagTestsFound){ + cout << "Warning: No tests for "<nodesetval->nodeNr; ++nodeId){ + xmlNodePtr nodeComponent = setComponents->nodesetval->nodeTab[nodeId]; + //xmlXPathSetContextNode(node, context); + context->node = nodeComponent; + xmlXPathObjectPtr setNodeTestSignature = xmlXPathEvalExpression((xmlChar*) queryTestSignature.c_str(), context); + assert(setNodeTestSignature->nodesetval->nodeNr==1); + char* componentTestsSignature = (char*) xmlNodeGetContent(setNodeTestSignature->nodesetval->nodeTab[0]); + + string componentTestsResult = getTestsResultForComponent(componentTestsSignature); + + xmlXPathObjectPtr setNodeTestResult = xmlXPathEvalExpression((xmlChar*) queryTestResults.c_str(), context); + + if (0 == setNodeTestResult->nodesetval->nodeNr){ + xmlNodePtr dataTestsResult = xmlNewChild(nodeComponent, NULL, BAD_CAST "data", + BAD_CAST componentTestsResult.c_str()); + + xmlNewProp(dataTestsResult, BAD_CAST "key", BAD_CAST "d5"); + continue; + } + assert(setNodeTestResult->nodesetval->nodeNr == 1); + xmlNodePtr dataTestsResult = setNodeTestResult->nodesetval->nodeTab[0]; + xmlNodeSetContent(dataTestsResult, BAD_CAST componentTestsResult.c_str()); + } + + xmlSaveFile(pathComponentsGraph.c_str(), doc); +} + +void checkUnusedTests(){ + for (string test: testsUnused){ + cout << "Warning: no components use test "<