diff --git a/coco/gen-xreate b/coco/gen-xreate deleted file mode 100755 index 132dff9..0000000 --- a/coco/gen-xreate +++ /dev/null @@ -1 +0,0 @@ -cococpp -frames /usr/share/coco-cpp/ ./xreate.ATG diff --git a/coco/xreate.ATG b/coco/xreate.ATG index 44ec3ed..fbe17ca 100644 --- a/coco/xreate.ATG +++ b/coco/xreate.ATG @@ -1,422 +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; .) +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; .) +BDecl = (. Expression body; TypeAnnotation typ; pushContextScope(scope); .) '{' { ( IF(checkAssignment()) VDecl '.' - | ExprTyped (. scope->setBody(body); .) + | ExprTyped (. scope->setBody(body); popContextScope(); .) )} '}'. -IfDecl = (. Expression cond; ManagedScpPtr blockTrue = root.add(new xreate::CodeScope(outer)); ManagedScpPtr blockFalse = root.add(new xreate::CodeScope(outer)); - TypeAnnotation typIf; .) +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 = +LoopDecl = (. Expression eIn, eAcc, eFilters; std::wstring varEl, varAcc; TypeAnnotation typEl, typAcc; - ManagedScpPtr block = root.add(new xreate::CodeScope(f)); .) + 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; Expression tag; .) - ["switch" [tagcolon Type {';' MetaSimpExpr}]] - CaseDecl {CaseDecl} +SwitchDecl = (. TypeAnnotation typ; eSwitch = Expression(Operator::SWITCH, {}); .) + // ["switch" [tagcolon Type {';' MetaSimpExpr}]] + CaseDecl {CaseDecl} . -CaseDecl<> = (. Expression e; .) +CaseDecl = (. Expression inner(Operator::CASE, {}); + ManagedScpPtr scopeCond = root.add(new xreate::CodeScope(context.scope)); + ManagedScpPtr scopeBody = root.add(new xreate::CodeScope(&*scopeCond)); .) "case" ( "default" - | CalleeParamsNamed + | CaseParams<&*scopeCond> ) - BDecl + 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; .) +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 + | 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)); .) }. -CalleeParamsNamed<> = - CalleeParamNamed - {',' CalleeParamNamed - }. - -CalleeParamNamed<> = (. Expression arg; TypeAnnotation argtyp; .) - ( - IF(checkAssignment()) VDecl - | ExprTyped - ). - 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 1cb116b..a0de9f7 100644 --- a/config/default.json +++ b/config/default.json @@ -1,42 +1,50 @@ { "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" - } + "function": "bind_func", + "scope": "bind_scope" + }, + + "nonevalue": "nonevalue", + "ret": { + "symbol": "retv", + "tag": "ret" + } }, "tests": { "template": "default", "templates": { "default": "*-", "types": "Types*-", "containers": "Containers*-", "ast": "AST*", "non-containers": "*-Containers*", "libxml2": "libxml2*", - "log": "Logging*" + "log": "Logging*", + "cfg": "CFG.testLoopContextExists" } } } diff --git a/core/null.lp b/core/null.lp new file mode 100644 index 0000000..8006219 --- /dev/null +++ b/core/null.lp @@ -0,0 +1,2 @@ +functionRetNull(f):- bind_func(f, retsymbol(X)), bind(X, null), v(X). +functionRetNull(f):- bind_func(f, retsymbol(X)), dfa_connection(X, Y, alias), bind(Y, null), v(X), v(Y). \ No newline at end of file diff --git a/cpp/CMakeLists.txt b/cpp/CMakeLists.txt index 30040d4..d3e4c7b 100644 --- a/cpp/CMakeLists.txt +++ b/cpp/CMakeLists.txt @@ -1,141 +1,150 @@ cmake_minimum_required(VERSION 2.8.11) project(xreate) find_package(LLVM REQUIRED CONFIG) -find_package(Qt5Core) + +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 - ./tests/tests.cpp ./tests/testClangAPI.cpp ./tests/testJson.cpp ./tests/testBasic.cpp - ./src/utils.cpp ./src/passmanager.cpp - ./src/pass/abstractpass.cpp ./src/pass/dfgpass.cpp ./src/pass/compilepass.cpp ./src/pass/functiontagspass.cpp - #./src/pass/cfgpass.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/attachments.cpp + ./src/instructions/instr-containers.cpp + ./src/query/containers.cpp + ./src/query/ptrvalid.cpp + ./src/attachments.cpp - /opt/potassco/gringo-4.4.0-source/app/shared/src/clingocontrol.cc - /opt/potassco/gringo-4.4.0-source/app/pyclingo/src/clingo_lib.cc + #${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 ) -set(POTASSCO_PATH "/opt/potassco/gringo-4.4.0-source") -INCLUDE_DIRECTORIES("/usr/lib/llvm-3.7/include") -INCLUDE_DIRECTORIES("/usr/include/libxml2") + +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}/app/shared/include -${POTASSCO_PATH}/app/pyclingo/src +${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.h tests/testLibXml2.cpp src/ExternLayer.cpp src/ExternLayer.h) +add_executable(xreate ${SOURCE_FILES} ${COCO_SOURCE_FILES} tests/testLibXml2.cpp src/ExternLayer.cpp src/ExternLayer.h) -set(COCO_TARGET cocoTarget) +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-xreate + 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_PATH ${POTASSCO_PATH}/build/debug) - -#find_library(LIBCLASP_LIBRARY_GRINGO NAMES gringo -# HINTS ${LIBCLASP_PATH}) -#find_library(LIBCLASP_LIBRARY_CLASP NAMES clasp -# HINTS ${LIBCLASP_PATH}) - set(LIBCLASP_LIBS - ${LIBCLASP_PATH}/libclasp.a - ${LIBCLASP_PATH}/libgringo.a - ${LIBCLASP_PATH}/libprogram_opts.a + clingo + clasp + gringo + program_opts + reify ) -#set(LIBCLANG_PATH "/usr/lib/llvm-3.7/lib/") -#set(LIBCLANG_LIBS -##/usr/lib/llvm-3.7/lib/libclangToolingCore.a -#/usr/lib/llvm-3.7/lib/libclangTooling.a -#) - -file(GLOB_RECURSE LIBCLANG_LIBS2 /usr/lib/llvm-3.7/lib/*.a) - -set(LIBCLANG_LIBS -/usr/lib/llvm-3.7/lib/libclangParse.a -/usr/lib/llvm-3.7/lib/libclangFormat.a -${LIBCLANG_LIBS2} -${LIBCLANG_LIBS2} -/usr/lib/llvm-3.7/lib/libclangParse.a -/usr/lib/llvm-3.7/lib/libclangFormat.a -) - -message(STATUS "ALL LIBS: " ${LIBCLANG_LIBS}) - - -message(STATUS ${LIBCLASP_LIBS}) +message(STATUS "CLANG LIBS: " ${CLANG_LIBS}) +message(STATUS "CLASP LIBS: " ${LIBCLASP_LIBS}) add_definitions(-DWITH_THREADS=0) 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}) -set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -g -Wall -fprofile-arcs -ftest-coverage -O0") -target_link_libraries(xreate ${GTEST_LIBRARIES} ${llvm_libs} ${LIBCLANG_LIBS} pthread xml2 Qt5::Core ${LIBCLASP_LIBS} gcov) +# -fprofile-arcs -ftest-coverage -O0 +set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -g -Wall") + +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 1b95b7e..6d8c5c1 100644 --- a/cpp/src/ExternLayer.cpp +++ b/cpp/src/ExternLayer.cpp @@ -1,274 +1,276 @@ // // Created by pgess on 4/21/15. // #include "ExternLayer.h" -#include "QStringList" #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; 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) {} 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 (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; 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); - QStringList code; + list code; std::vector args{ - "-I/usr/local/include" - ,"-I/usr/lib/llvm-3.7/bin/../lib/clang/3.7.0/include" - ,"-I/usr/bin/../lib/gcc/x86_64-linux-gnu/4.9/include" - ,"-I/usr/include/x86_64-linux-gnu" - ,"-I/usr/include" + "-I/usr/include" + ,"-I/usr/local/include" + ,"-I/usr/lib/llvm-3.6/lib/clang/3.6.0/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()), - [](const string header ) { - QString line = QString("#include \"%1\"").arg(header.c_str()); - llvm::outs()<< "<" << line.toStdString() << "> "; + [&formatInclude](const string header ) { + string line = boost::str(formatInclude % header); + llvm::outs()<< "<" << line << "> "; return line; }); llvm::outs() << '\n'; } - - loadLibraries(move(libs)); - ast = buildASTFromCodeWithArgs(code.join('\n').toStdString(), args); + //TODO uncomment loadLibraries + //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/ExternLayer.h b/cpp/src/ExternLayer.h index cc2a18f..ab41749 100644 --- a/cpp/src/ExternLayer.h +++ b/cpp/src/ExternLayer.h @@ -1,55 +1,55 @@ // // Created by pgess on 4/21/15. // #ifndef XREATE_EXTERNLAYER_H #define XREATE_EXTERNLAYER_H #include "llvmlayer.h" #include #include #include #include "ast.h" #include "clang/AST/ASTContext.h" -#include "/private/prg/vendors/clang/lib/CodeGen/CodeGenModule.h" +#include "/opt/llvm-toolchain-3.6-3.6/clang/lib/CodeGen/CodeGenModule.h" #include "clang/Frontend/ASTUnit.h" #include "clang/Frontend/CodeGenOptions.h" namespace xreate { struct ExternData { void addLibrary(Atom&& name, Atom&& package); void addIncludeDecl(Expression&& e); std::vector entries; std::map __dictLibraries; }; class ExternLayer { public: ExternLayer(LLVMLayer* llvm); llvm::Function* lookupFunction(const std::string& name); clang::QualType lookupType(const std::string& id); std::vector getStructFields(const clang::QualType& ty); llvm::Type* toLLVMType(const clang::QualType& t); bool isPointer(const clang::QualType& t); void init(const AST* root); static std::vector fetchPackageFlags(const ExternEntry& entry); static std::vector fetchPackageLibs(const ExternEntry& entry); private: std::unique_ptr ast; std::unique_ptr __cgm; std::unique_ptr __cgo; llvm::DataLayout __datalayout; LLVMLayer* __llvm; std::vector entries; std::map __functions; void addExternalData(const std::vector& data); void loadLibraries(std::vector&& libs); }; } #endif //XREATE_EXTERNLAYER_H diff --git a/cpp/src/ast.cpp b/cpp/src/ast.cpp index 6f7b723..6db5f2f 100644 --- a/cpp/src/ast.cpp +++ b/cpp/src/ast.cpp @@ -1,637 +1,642 @@ #include "ast.h" #include "ExternLayer.h" #include #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) {} 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)); __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); } 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()) {} 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 {}; 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 +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; 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; 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 34a7708..751e072 100644 --- a/cpp/src/clasplayer.cpp +++ b/cpp/src/clasplayer.cpp @@ -1,482 +1,611 @@ #include "clasplayer.h" #include // for defining logic programs #include // unfounded set checkers #include // for enumerating answer sets #include -#include - #include -#include +#include #include "utils.h" +#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; } - QStringList multiplyLists(std::list &&lists) { - QStringList result = lists.front(); + list + multiplyLists(list> &&lists) { + typedef list StringList; + assert(lists.size()); + StringList result(*lists.begin()); lists.pop_front(); - for (QStringList &list: lists) { - QStringList::const_iterator end = result.end(); - for (QStringList::iterator expr1I = result.begin(); expr1I < end; ++expr1I) { + 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; - QStringList::const_iterator expr2I = list.begin(); + StringList::const_iterator expr2I = list.begin(); for (int expr2No = 0, size = list.size() - 1; expr2No < size; ++expr2No, ++expr1I) - result.append(QString("%1, %2").arg(*expr1I).arg(*expr2I)); + result.push_back(str(concat %(*expr1I) %(*expr2I))); - *expr1I = QString("%1, %2").arg(*expr1I).arg(*expr2I); + *expr1I = str(concat %(*expr1I) %(*expr2I)); } } return result; } void - ClaspLayer::addCFAData(CFGraph &&graph) { - ostream &cout = __partGeneral; - - cout << endl << "%\t\tStatic analysis: CFA" << endl; - - for (const std::pair &relation: graph.__relations) { - const string &tagFrom = graph.__nodes.at(relation.first); - const string &tagTo = graph.__nodes.at(relation.second); - - cout << (QString("call(%1, %2) .").arg(tagFrom.c_str()).arg(tagTo.c_str())).toStdString() << endl; - } + 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 format2Args("(%1%, %2%)"); for (i1= dfaData.__edges.begin(), i2 = dfaData.__data.begin(); i1!= dfaData.__edges.end(); ++i1, ++i2 ) { - QString edgeData; + string edgeName; switch (*i2) { - case DFGConnection::OPT: edgeData = "opt"; break; - case DFGConnection::ALIAS: edgeData = "alias"; break; - case DFGConnection::PROTO: edgeData = "proto"; break; + case DFGConnection::OPT: edgeName = "opt"; break; + case DFGConnection::ALIAS: edgeName = "alias"; break; + case DFGConnection::PROTO: edgeName = "proto"; break; } - cout << QString("dfa_connection(%1, %2, %3).") - .arg(QString("(%1, %2)").arg(i1->first.identifier).arg(i1->first.scope)) - .arg(QString("(%1, %2)").arg(i1->second.identifier).arg(i1->second.scope)) - .arg(edgeData).toStdString() << endl; + cout << "dfa_connection"<< (format3Args + %(format2Args %(i1->first.identifier) %(i1->first.scope)) + %(format2Args %(i1->second.identifier) %(i1->second.scope)) + %edgeName) + << "." <first); symbols.insert(i1->second); } + boost::format formatBind("bind(%1%, %2%)."); for (const pair& tag: dfaData.__tags) { - for (QString variant: compile(tag.second)) { - cout << QString("bind(%1, %2).") - .arg(QString("(%1, %2)").arg(tag.first.identifier).arg(tag.first.scope)) - .arg(variant).toStdString()< &tags) { + ClaspLayer::involveCFAData() { ostream &cout = __partTags; + const std::string& atomBinding = Config::get("clasp.bindings.function"); + const std::string& atomBindingScope = Config::get("clasp.bindings.scope"); + + //show function tags + int counterTags = 0; + + boost::format formatFunction("function(%1%)."); + boost::format formatBind("%1%(%2%, %3%)."); + for (auto function: cfagraph.__nodesFunction.left) { + cout << formatFunction % (function.second) << std::endl; + - cout << (QString("function(%1) .").arg(function.c_str())).toStdString() << std::endl; + for (const auto& tag_: boost::make_iterator_range(cfagraph.__functionTags.equal_range(function.first))){ + const Tag& tag = tag_.second; - int tagsCount = 0; - for (const Tag &tag: tags) { - QStringList tagRaw = compile(tag.first); - assert(tagRaw.size() == 1); + list tagRaw = compile(tag.first); + assert(tagRaw.size() == 1); - std::string atom_binding = Config::get("clasp.bindings.function"); - cout << QString("%1(%2, %3).").arg(atom_binding.c_str()).arg(function.c_str()).arg(tagRaw.at(0)).toStdString() << endl; - ++tagsCount; + cout << formatBind + % (atomBinding) + % (function.second) + % (tagRaw.front()) + << endl; + ++counterTags; + } } - if (tagsCount == 0) { + 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%)."); + 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; - QStringList domains; + list domains; + boost::format formatDef("%1%(%2%)"); std::transform(rule.__args.begin(), rule.__args.end(), std::inserter(domains, domains.begin()), - [](const std::pair &argument) { + [&formatDef](const std::pair &argument) { string domain; switch (argument.second) { case DomainAnnotation::FUNCTION: domain = "function"; break; case DomainAnnotation::VARIABLE: domain = "variable"; break; } - return QString("%1(%2)").arg(domain.c_str()).arg(argument.first.c_str()); + return boost::str(formatDef % domain % argument.first); }); - QStringList vars; + list vars; std::transform(rule.__args.begin(), rule.__args.end(), std::inserter(vars, vars.begin()), [](const std::pair &argument) { return argument.first.c_str(); }); - std::list guardsRaw; + list> guardsRaw; std::transform(rule.__guards.begin(), rule.__guards.end(), std::inserter(guardsRaw, guardsRaw.begin()), [this](const Expression &guard) { return compile(guard); }); - QStringList guards = multiplyLists(std::move(guardsRaw)); - QStringList &&branches = compileNeg(rule.__condition); + const list& guards = multiplyLists(std::move(guardsRaw)); + list &&branches = compileNeg(rule.__condition); - for (const QString &guardsJoined: guards) - for (const QString &branch: branches) { + 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)); - QString result = QString("warning(%1, (%2)):- %3, %4, %5.") - .arg(hook) - .arg(vars.join(", ")) - .arg(branch) - .arg(guardsJoined) - .arg(domains.join(", ")); - - __partGeneral << result.toStdString() << endl; + __partGeneral << formatWarning + %(hook) + %(boost::algorithm::join(vars, ", ")) + %(branch) + %(guardsJoined) + %(boost::algorithm::join(domains, ", ")) + < ClaspLayer::compile(const Expression &e) const { - QStringList result; + list result; switch (e.op) { case Operator::CALL: { assert(e.__state == Expression::COMPOUND); - std::list operands; + std::list> operands; std::transform(e.operands.begin(), e.operands.end(), std::inserter(operands, operands.begin()), [this](const Expression &e) { return compile(e); }); - QStringList &&operands_ = multiplyLists(std::move(operands)); - result.append(QString("%1(%2)").arg(e.__valueS.c_str()).arg(operands_.join(", "))); + 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); - QStringList &&rawOp = compile(op); + list &&rawOp = compile(op); assert(rawOp.size() == 1); - result.append(QString("not %1").arg(rawOp.at(0))); + result.push_back((boost::format("not %1%")%(rawOp.front())).str()); break; }; case Operator::NONE: { switch (e.__state) { case Expression::IDENT: - result.append(QString(e.__valueS.c_str())); + result.push_back(e.__valueS); break; case Expression::NUMBER: - result.append(QString::number(e.__valueD)); + result.push_back(to_string(e.__valueD)); break; default: assert(true); } break; } } + if (e.isNone()){ + result.push_back(e.__valueS); + } + + assert(result.size()); return result; } - QStringList + std::list ClaspLayer::compileNeg(const Expression &e) const { - QStringList result; + list result; switch (e.op) { case Operator::IMPL: { assert(e.__state == Expression::COMPOUND); assert(e.operands.size() == 2); - QStringList operands1 = compile(e.operands.at(0)); - QStringList operands2 = compile(e.operands.at(1)); + 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.append(QString("%1, not %2").arg(op1).arg(op2)); + result.push_back(boost::str(formatNeg %(op1) % (op2))); } break; } case Operator::NEG: { assert(e.operands.size() == 1); const Expression &op = e.operands.at(0); - QStringList &&rawOp = compile(op); + list &&rawOp = compile(op); assert(rawOp.size() == 1); - result.append(rawOp.at(0)); + 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::addImports() { + 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() { - addImports(); + involveImports(); + involveCFAData(); ostringstream program; program << __partTags.str() << __partGeneral.str(); cout << FYEL(program.str()) << endl; const char *argv[] = {nullptr, nullptr}; - ClingoLib ctl(2, argv); + DefaultGringoModule moduleDefault; + ClingoLib ctl(moduleDefault, 2, argv); //prg.add("p", ["t"], "q(t).") Gringo::FWStringVec vars{}; ctl.add("base", vars, program.str()); //prg.ground([("p", [2])]) Gringo::Control::GroundVec vals{std::make_pair("base", Gringo::FWValVec {})}; ctl.ground(vals, Gringo::Any()); //solve Gringo::Control::Assumptions as; Gringo::SolveResult result = ctl.solve(Gringo::Control::ModelHandler([&](Gringo::Model const &model) { return this->onModel(model); }), std::move(as)); if (result == Gringo::SolveResult::SAT) { cout << FGRN("SUCCESSFULLY") << endl; } else { cout << FRED("UNSUCCESSFULLY") << endl; } // invoke all query plugins to process clasp data for (IQuery* q: __queries) { q->init(this); } } ClaspLayer::ClaspLayer() { } ClaspLayer::ModelRange ClaspLayer::query(const std::string& atom) { if (! __model.count(atom)){ return boost::none; } return ModelRange(__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) { - auto pos = __indexScopes.emplace(symbol.scope, __indexScopes.size()); - if (pos.second) - __registryScopes.push_back(symbol.scope); - SymbolPacked result; - result.scope = pos.first->second; + + result.scope = pack(symbol.scope); result.identifier = symbol.identifier; return result; } Symbol ClaspLayer::unpack(const SymbolPacked& symbol) { return Symbol{symbol.identifier, __registryScopes[symbol.scope]}; }; /* 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; } */ /***************************************** - * CFGraph + * CFAGraph ***************************************** */ - void - CFGraph::addNode(unsigned int function, std::string &&tag) { - __nodes.emplace(function, tag); + CFAGraph::addFunctionNodeTags(const std::string& function, const std::vector&tags) { + unsigned int fid = registerNodeFunction(function); + + for (Tag tag: tags){ + __functionTags.emplace(fid, tag); + } } - bool - CFGraph::existsNode(unsigned int function) const { - return __nodes.count(function); + void + CFAGraph::addScopeNodeTags(const ScopePacked& scope, const std::vector& tags){ + for (Expression tag: tags){ + __scopeTags.emplace(scope, tag); + } } void - CFGraph::addLink(unsigned int nodeFrom, unsigned int nodeTo) { - __relations.insert(std::make_pair(nodeFrom, nodeTo)); + 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 SymbolInvalid& symbol){ + 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 SymbolPacked& nodeFrom, DFGConnection link) { - if (!linkExists(nodeTo, nodeFrom)) - { - __edges.emplace_back(nodeTo, nodeFrom); - __data.push_back(link); - - EdgeId eid = __edges.size()-1; - __outEdges.emplace(nodeFrom, eid); - } + DFAGraph::addLink(const SymbolPacked& nodeTo, const SymbolNode& nodeFrom, DFGConnection link) { + VisitorAddLink visitor(this, nodeTo, link); + boost::apply_visitor(visitor, nodeFrom); } void - DFAGraph::addTag(const SymbolPacked &node, Expression &&tag) { - __tags.emplace(node, tag); + 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 9fb1f8f..85acd90 100644 --- a/cpp/src/clasplayer.h +++ b/cpp/src/clasplayer.h @@ -1,172 +1,200 @@ #ifndef CLASPLAYER_H #define CLASPLAYER_H -#include -#include + #include -#include + +#include +#include #include +#include #include +#include namespace xreate { - class CFGraph { + typedef unsigned int ScopePacked; + + class CFAGraph { friend class ClaspLayer; public: - void addNode(unsigned int function, std::string &&tag); - void addLink(unsigned int nodeFrom, unsigned int nodeTo); - bool existsNode(unsigned int function) const; - void print(std::ostream &cout) const; + 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; - std::map __nodes; + std::map __relations; + boost::bimap __nodesFunction; + std::multimap __functionTags; + std::multimap __scopeTags; + + unsigned int registerNodeFunction(const std::string& fname); }; + + struct SymbolPacked { VID identifier; - unsigned int scope; + 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(const SymbolPacked& node, Expression&& tag); - void addLink(const SymbolPacked& nodeTo, const SymbolPacked& nodeFrom, DFGConnection link); + 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 addCFAData(CFGraph &&graph); + 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); + ScopePacked pack(CodeScope* scope); SymbolPacked pack(const Symbol& symbol, std::string hintSymbolName=""); Symbol unpack(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::unordered_map __indexScopes; std::vector __registryScopes; void printWarnings(std::ostream& out); bool onModel(Gringo::Model const &model); - QStringList compile(const Expression &e) const; - QStringList compileNeg(const Expression &e) const; + std::list compile(const Expression &e) const; + std::list compileNeg(const Expression &e) const; unsigned int registerWarning(std::string &&message); - void addImports(); + 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 1cc1e05..5f7bfbc 100644 --- a/cpp/src/instructions/instr-containers.cpp +++ b/cpp/src/instructions/instr-containers.cpp @@ -1,469 +1,470 @@ #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 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 //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 - PointerType* tyInt8P = PointerType::getInt8PtrTy(llvm::getGlobalContext()); - Value* nullInt8P = llvm::ConstantPointerNull::get(tyInt8P); + 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); - llvm::BasicBlock *blockException = llvm::BasicBlock::Create(llvm::getGlobalContext(), "exception", 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(blockException); - - llvm->initExceptionsSupport(); - llvm::Function* fAllocate = llvm->module->getFunction("__cxa_allocate_exception"); - llvm::Function* fThrow = llvm->module->getFunction("__cxa_throw"); - auto exception = llvm->builder.CreateCall(fAllocate, ConstantInt::get(IntegerType::getInt64Ty(getGlobalContext()), 4)); - vector throwParams{exception, nullInt8P, nullInt8P}; - llvm->builder.CreateCall(fThrow, ArrayRef(throwParams)); - llvm->builder.CreateUnreachable(); - - 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; 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); // 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; } +llvm::Value* +Instructions::compileSwitch(const Expression& exprSwitch, const std::string& hintRetVar){ + EXPAND_CONTEXT + llvm::IRBuilder<>& builder = llvm->builder; + + + //builder.CreateSwitch() + +} + llvm::Value* Instructions::compileConstantArray(const Expression &expr, const std::string& hintRetVar) { EXPAND_CONTEXT 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 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; 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::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; }; } 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)); }; } //return null pointer if (linkedlist){ return ConstantPointerNull::getNullValue(sourceRawType); } } 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 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); }; } if (linkedlist){ return index; } } 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); } 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); } } }; 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); } } diff --git a/cpp/src/instructions/instr-containers.h b/cpp/src/instructions/instr-containers.h index be660d1..9465d35 100644 --- a/cpp/src/instructions/instr-containers.h +++ b/cpp/src/instructions/instr-containers.h @@ -1,85 +1,86 @@ #ifndef CODEINSTRUCTIONS_H #define CODEINSTRUCTIONS_H #include "llvmlayer.h" #include "ast.h" #include #include #include "pass/compilepass.h" namespace xreate { namespace containers { class Iterator{ public : virtual llvm::Value* begin() =0; virtual llvm::Value* end() = 0; virtual llvm::Value* get(llvm::Value* index,const std::string& hintRetVar="") = 0; virtual llvm::Value* move(llvm::Value* index, const std::string& hintRetVar="")=0; virtual ~Iterator(){}; static Iterator* create(CompilePass::Context context, const Symbol& var); }; class Instructions { public: Instructions(CompilePass::Context ctx); llvm::Value* compileArrayIndex(const Symbol &dataSymbol, std::vector indexes, std::string ident = ""); llvm::Value* compileStructIndex(llvm::Value* aggregate, const ExpandedType& t, const std::string& idx); /* * - map Computation -> Llvm_Array: Prohibited, we do not know a result size * - map Llvm_Array -> Computation: considered in `compileGetElement` * - map Llvm_Array -> Llvm_Array considered by this method */ llvm::Value*compileMapSolid(const Expression &expr, const std::string hintRetVar = ""); llvm::Value* compileFold(const Expression& fold, const std::string& ident=""); llvm::Value* compileIf(const Expression& exprIf, const std::string& ident); + llvm::Value* compileSwitch(const Expression& exprSwitch, const std::string& hintRetVar); llvm::Value* compileConstantStringAsPChar(const string &data, const std::string& hintRetVar); llvm::Value* compileConstantArray(const Expression &expr, const std::string& hintRetVar=""); private: CompilePass::Context context; llvm::IntegerType* const tyNum; }; }} #endif //CODEINSTRUCTIONS_H /* template struct InstructionClasses {}; template<> struct InstructionClasses { typedef InstructionList Impl; }; template<> struct InstructionClasses { typedef InstructionMap Impl; }; template class CodeInstruction: public InstructionClasses::Impl { typedef typename InstructionClasses::Impl InstructionImpl; public: CodeInstruction(CodeScope* parent) : InstructionImpl(parent) {} llvm::Value * compileExpression(const Expression &expr, LLVMLayer &l, const std::string * const hintRetVar) { if (expr.op == Instruction) return InstructionImpl::compileDefault(expr, l, hintRetVar); return CodeScope::compileExpression(expr, l, hintRetVar); } }; } */ diff --git a/cpp/src/llvmlayer.cpp b/cpp/src/llvmlayer.cpp index 47121d3..2afa47c 100644 --- a/cpp/src/llvmlayer.cpp +++ b/cpp/src/llvmlayer.cpp @@ -1,229 +1,249 @@ #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) { 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/llvmlayer.h b/cpp/src/llvmlayer.h index 3079d28..fbbc823 100644 --- a/cpp/src/llvmlayer.h +++ b/cpp/src/llvmlayer.h @@ -1,56 +1,58 @@ #ifndef LLVMLAYER_H #define LLVMLAYER_H #include "llvm/IR/Module.h" #include "llvm/IR/Function.h" #include "llvm/IR/PassManager.h" #include "llvm/IR/CallingConv.h" #include "llvm/IR/Verifier.h" #include "llvm/IR/IRPrintingPasses.h" #include "llvm/IR/IRBuilder.h" #include "llvm/Support/raw_ostream.h" #include "llvm/IR/LLVMContext.h" #include "llvm/ExecutionEngine/ExecutionEngine.h" #include "utils.h" namespace xreate { class AST; class ExternLayer; class TypeAnnotation; class LLVMLayer { public: LLVMLayer(AST* rootAST); AST *ast = 0; ExternLayer *layerExtern =0; llvm::Module *module = 0; llvm::ExecutionEngine* jit= 0; llvm::IRBuilder<> builder; void moveToGarbage(void *o); llvm::Type* toLLVMType(const Expanded& ty) const; void print(); void* getFunctionPointer(llvm::Function* function); void initJit(); - void initExceptionsSupport(); + + llvm::BasicBlock* initExceptionBlock(llvm::BasicBlock* block); private: + void initExceptionsSupport(); llvm::Type* toLLVMType(const Expanded& ty, std::map& conjunctions) const; std::vector __garbage; }; struct TypeUtils { bool isStruct(const Expanded& ty); bool isPointer(const Expanded& ty); std::vector getStructFields(const Expanded& t); TypeUtils(LLVMLayer*llvmlayer) : llvm(llvmlayer){} private: LLVMLayer* llvm; }; } #endif // LLVMLAYER_H diff --git a/cpp/src/pass/abstractpass.h b/cpp/src/pass/abstractpass.h index 89e74ec..da48e1c 100644 --- a/cpp/src/pass/abstractpass.h +++ b/cpp/src/pass/abstractpass.h @@ -1,121 +1,123 @@ #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 class AbstractPass: public AbstractPassBase { private: std::set __visitedSymbols; + Output __defaultValue; public: - AbstractPass(PassManager* manager): AbstractPassBase(manager) {} + AbstractPass(PassManager* manager, Output defaultValue=Output()) + : AbstractPassBase(manager), __defaultValue(defaultValue) {} //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()); + for (const Expression &op: expression.getOperands()) { process(op, context); } - assert(expression.op != Operator::MAP || expression.op == Operator::MAP && expression.blocks.size()); for (CodeScope* scope: expression.blocks) { process(scope, context); } - /* if (expression.op == Operator::CALL) { const std::string &calleeName = expression.getValueString(); - ManagedFnPtr callee = root->findFunction(calleeName); + ManagedFnPtr callee = man->root->findFunction(calleeName); + if (callee) processFnCall(callee, context); } - */ break; case Expression::IDENT: assert(context.scope); std::string ident = expression.getValueString(); const Symbol& symbol = context.scope->findSymbol(ident); - if (__visitedSymbols.count(symbol)) {break;} + if (__visitedSymbols.count(symbol)) {assert(false && "Invalid state");} __visitedSymbols.insert(symbol); PassContext context2 = context; context2.scope = symbol.scope; if (CodeScope::hasDeclaration(symbol)) { - process(CodeScope::findDeclaration(symbol), context2, ident); + return process(CodeScope::findDeclaration(symbol), context2, ident); } break; } } void run() { ManagedRulePtr rule = man->root->begin(); while (rule.isValid()) { process(rule); ++rule; } ManagedFnPtr f = man->root->begin(); while (f.isValid()) { process(f); ++f; } } }; } #endif diff --git a/cpp/src/pass/cfgpass.cpp b/cpp/src/pass/cfgpass.cpp index c3195e7..6c84981 100644 --- a/cpp/src/pass/cfgpass.cpp +++ b/cpp/src/pass/cfgpass.cpp @@ -1,41 +1,73 @@ #include "cfgpass.h" -#include - +#include using namespace std; using namespace xreate; + void -CFGPass::start() -{ - __context.graph = CFGraph(); +CFGPass::initSignatures(){ + auto range = man->root->__interfacesData.equal_range(CFA); + for (auto i = range.first; i!= range.second; ++i){ + __signatures.emplace(i->second.op, i->second); + } +} + +void CFGPass::run(){ + initSignatures(); + + return AbstractPass::run(); } void CFGPass::finish() { - man->clasp->addCFGData(move(__context.graph)); + man->clasp->setCFAData(move(__context.graph)); + + return AbstractPass::finish(); } -CFGPass::CFGPass(PassManager* manager) - : ASTPass(manager) +void +CFGPass::processFnCall(ManagedFnPtr function, PassContext context) { - man->registerFilter(this, PassFilter:: FUNCTION); - man->registerFilter(this, PassFilter:: FUNCTIONCALL); + ClaspLayer* clasp = man->clasp; + __context.graph.addLink(clasp->pack(context.scope), function->getName()); + + return AbstractPass::processFnCall(function, context); +} + +void +CFGPass::process(CodeScope* scope, PassContext context, const std::string& hintBlockDecl){ + return AbstractPass::process(scope, context, hintBlockDecl); +} + +void +CFGPass::process(const Expression& expression, PassContext context, const std::string& varDecl){ + ClaspLayer* clasp = man->clasp; + + if (expression.__state == Expression::COMPOUND){ + Operator op= expression.op; + + if (__signatures.count(op)) { + assert(expression.blocks.size()); + + for (const auto& scheme: boost::make_iterator_range(__signatures.equal_range(expression.op))) { + __context.graph.addScopeNodeTags(clasp->pack(expression.blocks.front()), scheme.second.getOperands()); + } + } + } + + return AbstractPass::process(expression, context, varDecl); } void -CFGPass::process(ManagedFnPtr function, PassContext context) +CFGPass::process(ManagedFnPtr function) { - //FUNCTION decl - if (context.function == function) - { - const string& name = function->getName(); - - __context.graph.addNode(function.id(), string(name)); - return; - } - - //FUNCTIONCALL decl - __context.graph.addLink(context.function.id(), function.id()); -} \ No newline at end of file + __context.graph.addFunctionNodeTags(function->getName(), function->getAnnotations()); + + return AbstractPass::process(function); +} + +CFGPass::CFGPass(PassManager* manager) + : AbstractPass(manager) +{} diff --git a/cpp/src/pass/cfgpass.h b/cpp/src/pass/cfgpass.h index 0eb3ebf..c68ba2f 100644 --- a/cpp/src/pass/cfgpass.h +++ b/cpp/src/pass/cfgpass.h @@ -1,26 +1,33 @@ // Control Flow Graph determination pass #ifndef CFGPASS_H #define CFGPASS_H #include "passmanager.h" #include "clasplayer.h" +#include "abstractpass.h" namespace xreate { -class CFGPass : public ASTPass +class CFGPass : public AbstractPass { public: - void init(); + void process(ManagedFnPtr function) override; + void processFnCall(ManagedFnPtr function, PassContext context) override; + void process(CodeScope* scope, PassContext context, const std::string& hintBlockDecl="") override; + void process(const Expression& expression, PassContext context, const std::string& varDecl="") override; + CFGPass(PassManager* manager); - void process(ManagedFnPtr function, PassContext context); - virtual void start(); - virtual void finish(); + void finish() override; + void run() override; private: struct { - CFGraph graph; + CFAGraph graph; } __context; + std::multimap __signatures; //CFA data for particular operators + + void initSignatures(); }; } #endif // CFGPASS_H diff --git a/cpp/src/pass/compilepass.cpp b/cpp/src/pass/compilepass.cpp index e374bc8..ed0d8b2 100644 --- a/cpp/src/pass/compilepass.cpp +++ b/cpp/src/pass/compilepass.cpp @@ -1,449 +1,454 @@ #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); }; }; 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")); 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 9026b78..197541f 100644 --- a/cpp/src/pass/dfgpass.cpp +++ b/cpp/src/pass/dfgpass.cpp @@ -1,152 +1,184 @@ #include "dfgpass.h" -#include "../passmanager.h" - +#include "passmanager.h" +#include "clasplayer.h" +#include using namespace xreate; using namespace std; 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); -SymbolPackedOptional + } 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); + } +} + +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) { - SymbolPacked nodeThis = clasp->pack(context.scope->findSymbol(decl), decl); + SymbolNode nodeThis = clasp->pack(context.scope->findSymbol(decl), decl); __context.graph.addTag(nodeThis, Expression(tag.second)); } } switch(expression.__state) { case Expression::IDENT: - AbstractPass::process(expression, context, decl); - - string ident = expression.getValueString(); - const Symbol& identSymbol = context.scope->findSymbol(ident); + const string& ident = expression.getValueString(); + SymbolNode nodeFrom = AbstractPass::process(expression, context, decl); + SymbolPacked nodeTo = clasp->pack(context.scope->findSymbol(ident)); - SymbolPacked nodeFrom = clasp->pack(identSymbol); - if (!decl.empty()) { - SymbolPacked nodeTo = clasp->pack(context.scope->findSymbol(decl)); - __context.graph.addLink(move(nodeTo), move(nodeFrom), DFGConnection::ALIAS); - } + __context.graph.addLink(nodeTo, nodeFrom, DFGConnection::ALIAS); + return nodeTo; + } - return nodeFrom; + //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; + 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 boost::none; + if (!function) return SymbolInvalid(); // set calling relations: CodeScope *scopeRemote = function->getEntryScope(); - std::vector::iterator op = operands.begin(); + std::vector::iterator op = operands.begin(); for (const std::string &arg: scopeRemote->__args) { - if (*op) { const Symbol &nodeRemote = scopeRemote->findSymbol(arg); - __context.graph.addLink(clasp->pack(nodeRemote), **op, DFGConnection::OPT); - } + SymbolPacked* operandPacked = boost::get(&*op); + assert(operandPacked); + __context.graph.addLink(clasp->pack(nodeRemote), *operandPacked, DFGConnection::OPT); ++op; } - SymbolPacked ret = clasp->pack(Symbol{0, scopeRemote}); - if (!decl.empty()) { - __context.graph.addLink( - clasp->pack( - context.scope->findSymbol(decl)), - ret, DFGConnection::OPT); - } - - return ret; + //TODO need SymbolTransient::connection mark in order to represent OPT connection + return clasp->pack(Symbol{0, scopeRemote}); } } - std::vector operands; + std::vector operands; + + if (expression.__state != Expression::COMPOUND){ + AbstractPass::process(expression, context, decl); + return SymbolInvalid(); + } 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::const_iterator arg = operands.begin(); + std::vector::iterator arg = operands.begin(); std::vector::const_iterator tag = ++scheme.getOperands().begin(); while (tag != scheme.getOperands().end()) { - if (*arg && tag->__state != Expression::INVALID) { - __context.graph.addTag(**arg, Expression(*tag)); + if (tag->__state != Expression::INVALID) { + __context.graph.addTag(*arg, Expression(*tag)); } ++arg; ++tag; } Expression retTag = *scheme.getOperands().begin(); if (retTag.__state != Expression::INVALID) { - assert(!decl.empty()); - SymbolPacked pdecl = clasp->pack(context.scope->findSymbol(decl)); - __context.graph.addTag(pdecl, move(retTag)); + return SymbolTransient{{retTag}}; } } // adhoc for MAP case, TODO reorganize code in more clear manner if (expression.op == Operator::MAP) { - SymbolPackedOptional nodeFrom; + SymbolNode nodeFrom; 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)); - __context.graph.addLink(move(nodeTo), move(*nodeFrom), DFGConnection::PROTO); + 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 boost::none; + return SymbolInvalid(); } - AbstractPass::process(expression, context, decl); - return boost::none; + return SymbolInvalid(); } 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)); } diff --git a/cpp/src/pass/dfgpass.h b/cpp/src/pass/dfgpass.h index 8622130..fcf9cf1 100644 --- a/cpp/src/pass/dfgpass.h +++ b/cpp/src/pass/dfgpass.h @@ -1,34 +1,34 @@ // Data Flow Graph determination pass #ifndef DFGPASS_H #define DFGPASS_H #include "abstractpass.h" #include "clasplayer.h" -#include namespace xreate { -typedef boost::optional SymbolPackedOptional; -class DFGPass : public AbstractPass { +class ClaspLayer; + +class DFGPass : public AbstractPass { public: - SymbolPackedOptional process(const Expression& expression, PassContext context, const std::string& varDecl="") override; + SymbolNode process(ManagedFnPtr function); + SymbolNode process(const Expression& expression, PassContext context, const std::string& varDecl="") override; DFGPass(PassManager* manager); - unsigned int hash(const CodeScope* scope); void init(); void run(); void finish(); private: struct { DFAGraph graph; } __context; std::map __signatures; //DFA data for particular operators ClaspLayer* clasp; }; }; #endif diff --git a/cpp/src/pass/functiontagspass.cpp b/cpp/src/pass/functiontagspass.cpp deleted file mode 100644 index 6c30b77..0000000 --- a/cpp/src/pass/functiontagspass.cpp +++ /dev/null @@ -1,10 +0,0 @@ - -#include "functiontagspass.h" -using namespace std; -using namespace xreate; - -void -FunctionTagsPass::process(ManagedFnPtr function) -{ - man->clasp->addFunctionTags(function->getName(), function->getAnnotations()); -} diff --git a/cpp/src/pass/functiontagspass.h b/cpp/src/pass/functiontagspass.h deleted file mode 100644 index 5d92786..0000000 --- a/cpp/src/pass/functiontagspass.h +++ /dev/null @@ -1,14 +0,0 @@ -#ifndef FUNCTIONTAGSPASS_H -#define FUNCTIONTAGSPASS_H - -#include "abstractpass.h" - -namespace xreate { -class FunctionTagsPass: public AbstractPass -{ -public: - FunctionTagsPass(PassManager *manager): AbstractPass(manager) {} - void process(ManagedFnPtr function) override; -};} - -#endif // FUNCTIONTAGSPASS_H diff --git a/cpp/src/passmanager.cpp b/cpp/src/passmanager.cpp index 37c3f28..3bcfded 100644 --- a/cpp/src/passmanager.cpp +++ b/cpp/src/passmanager.cpp @@ -1,84 +1,93 @@ #include #include "query/containers.h" #include "passmanager.h" #include "pass/compilepass.h" #include "Parser.h" +#include "pass/cfgpass.h" #include "pass/dfgpass.h" -#include "pass/functiontagspass.h" #include "pass/logging.h" +#include using namespace xreate; using namespace std; PassManager* PassManager::prepareForCode(std::string&& code){ Scanner scanner(reinterpret_cast(code.c_str()), code.size()); return prepareForCode(scanner); } PassManager* PassManager::prepareForCode(Scanner& scanner){ Parser parser(&scanner); parser.Parse(); assert(!parser.errors->count && "Parser errors"); PassManager* man = new PassManager; AST* ast = new AST(parser.root); man->root = ast; man->clasp = new ClaspLayer(); man->clasp->ast = man->root; man->llvm = new LLVMLayer(man->root); - man->registerPass(new DFGPass(man)); - man->registerPass(new FunctionTagsPass(man)); + + CFGPass* passCFG = new CFGPass(man); + + man->registerPass(new DFGPass(man), passCFG); + man->registerPass(passCFG); return man; } void -PassManager::registerPass(AbstractPassBase* pass) +PassManager::registerPass(AbstractPassBase* pass, AbstractPassBase* parent) { - __passes.push_back(pass); + __passes.emplace(parent, pass); } void* PassManager::run() { - for (AbstractPassBase* pass: __passes) - { - pass->run(); - pass->finish(); - } - - clasp->registerdQuery(new containers::Query()); - clasp->run(); + runWithoutCompilation(); CompilePass* compiler = new CompilePass(this); compiler->run(); //Compiler Dependents: Logging* logger = new Logging(this); logger->initDependencies(compiler); logger->run(); llvm->print(); llvm->initJit(); return llvm->getFunctionPointer(compiler->getEntryFunction()); } void PassManager::runWithoutCompilation(){ - for (AbstractPassBase* pass: __passes) - { - pass->run(); - pass->finish(); - } + std::list passes{nullptr}; + while (passes.size()){ + AbstractPassBase* parent = passes.front(); + + auto range = __passes.equal_range(parent); + + for (auto i=range.first; i!=range.second; ++i){ + AbstractPassBase* pass = i->second; + + pass->run(); + pass->finish(); + + passes.push_back(pass); + } + + passes.pop_front(); + } clasp->registerdQuery(new containers::Query()); clasp->run(); } PassManager::~PassManager(){} diff --git a/cpp/src/passmanager.h b/cpp/src/passmanager.h index e9d581c..4c9e0de 100644 --- a/cpp/src/passmanager.h +++ b/cpp/src/passmanager.h @@ -1,31 +1,33 @@ #ifndef PASSMANAGER_H #define PASSMANAGER_H -#include "clasplayer.h" -#include "ast.h" -#include #include "Scanner.h" +#include +#include namespace xreate { class AbstractPassBase; +class ClaspLayer; +class LLVMLayer; +class AST; class PassManager { public: ~PassManager(); void* run(); void runWithoutCompilation(); - void registerPass(AbstractPassBase* pass); + void registerPass(AbstractPassBase* pass, AbstractPassBase* prerequisite=nullptr); static PassManager* prepareForCode(std::string&& code); static PassManager* prepareForCode(Scanner& scanner); ClaspLayer* clasp; LLVMLayer* llvm; AST* root; private: //typedef std::multimap FILTERS_STORAGE; //FILTERS_STORAGE __filters; - std::list __passes; + std::multimap __passes; }; } #endif diff --git a/cpp/src/query/containers.h b/cpp/src/query/containers.h index 6da2c5e..663b08c 100644 --- a/cpp/src/query/containers.h +++ b/cpp/src/query/containers.h @@ -1,80 +1,83 @@ // // Created by pgess on 3/14/15. // #ifndef _XREATE_CONTAINERSQUERY_H_ #define _XREATE_CONTAINERSQUERY_H_ + #include "passmanager.h" +#include "clasplayer.h" + #include namespace xreate { namespace containers { enum ImplementationType {SOLID, ON_THE_FLY, LINKED_LIST}; template struct ImplementationRec; template<> struct ImplementationRec { size_t size; }; template<> struct ImplementationRec{ Symbol source; }; struct Implementation; struct ImplementationLinkedList { bool flagIsValid; std::string fieldPointer; Expression terminator; ImplementationLinkedList(const Symbol& source); operator bool() const; Implementation getImplementationData() const; private: Symbol s; }; struct Implementation { typedef boost::variant, ImplementationRec> Variant; const ImplementationType impl; Variant data; static Implementation create(const Symbol &var); static Implementation create(const Symbol& var, const std::string &implSerialized); static Implementation create(const Symbol& var, const Implementation& proto); template const ImplementationRec& extract() const{ const ImplementationRec& rec = boost::get>(data); return rec; } }; class Query : public xreate::IQuery { public: static Implementation queryImplementation(xreate::Symbol const &s); void init(ClaspLayer* clasp); ~Query(){} private: bool flagIsDataLoaded = false; PassManager *man; }; } template<> struct AttachmentsDict { typedef containers::Implementation Data; static const unsigned int key = 1; }; } #endif //_XREATE_CONTAINERSQUERY_H_ diff --git a/cpp/src/utils.h b/cpp/src/utils.h index 532b46d..925023c 100644 --- a/cpp/src/utils.h +++ b/cpp/src/utils.h @@ -1,128 +1,130 @@ #ifndef UTILS_H #define UTILS_H #include "jeayeson/jeayeson.hpp" //TODO mark dirty members /* template struct DdesctructableClass { } */ /* template struct TagUpdatable{ TagUpdatable(const OriginalType& source) : __source(source) {} TagUpdatable() = delete; const OriginalType& __source; }; struct Updatable; template struct TagsDictionary {}; template struct TagsDictionary { typedef TagUpdatable TagName; }; template struct awareOf { awareOf(OT& dest) : __dest(dest) {} awareOf& operator= (const typename TagsDictionary::TagName& source) { __dest = source.__source; } private: OT& __dest; }; template> const OT& awareOf(const Tag& holder) { return std::forward(holder.__source); } */ namespace xreate { template struct AddTag { explicit AddTag(const Source &&src) : __src(src) { } operator const Source&() const{ return __src; } const Source& get() const{ return __src; } const Source* operator->() const { return &__src; } private: Source __src; }; struct Expand_t{}; template using Expanded = AddTag; - + + + //DEBT move to resources compiler. https://github.com/markusfisch/cpprc class Config { private: json_map __storage; static Config __self; Config(); public: static std::string get(std::string key) { return __self.__storage.get_for_path(key).get(); } }; } #define RST "\x1B[0m" #define KRED "\x1B[31m" #define KGRN "\x1B[32m" #define KYEL "\x1B[33m" #define KBLU "\x1B[34m" #define KMAG "\x1B[35m" #define KCYN "\x1B[36m" #define KWHT "\x1B[37m" #define FRED(x) KRED << x << RST #define FGRN(x) KGRN <runWithoutCompilation(); + + ClaspLayer::ModelRange 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); +} + +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 new file mode 100644 index 0000000..fd82f58 --- /dev/null +++ b/cpp/tests/DFGtests.cpp @@ -0,0 +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")); + + 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 3addb1b..2929080 100644 --- a/cpp/tests/ast.cpp +++ b/cpp/tests/ast.cpp @@ -1,27 +1,41 @@ /* * ast.cpp * * Created on: Jun 11, 2015 * Author: pgess */ #include "gtest/gtest.h" #include "passmanager.h" -#include "pass/functiontagspass.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) { + 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()); +} + diff --git a/cpp/tests/containers.cpp b/cpp/tests/containers.cpp index 15b4e11..4c149bc 100644 --- a/cpp/tests/containers.cpp +++ b/cpp/tests/containers.cpp @@ -1,58 +1,57 @@ /* * containers.cpp * * Created on: Jun 9, 2015 * Author: pgess */ #include "gtest/gtest.h" #include "passmanager.h" -#include "pass/functiontagspass.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)); + 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/externc.cpp b/cpp/tests/externc.cpp index fe5587e..ae6287a 100644 --- a/cpp/tests/externc.cpp +++ b/cpp/tests/externc.cpp @@ -1,105 +1,104 @@ #include "gtest/gtest.h" #include "passmanager.h" -#include "pass/functiontagspass.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)); } 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{return arc4random() }"; + "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/skipdetection.cpp b/cpp/tests/skipdetection.cpp new file mode 100644 index 0000000..5ccb14b --- /dev/null +++ b/cpp/tests/skipdetection.cpp @@ -0,0 +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")); + 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 8826b37..9cb9a5c 100644 --- a/cpp/tests/testBasic.cpp +++ b/cpp/tests/testBasic.cpp @@ -1,27 +1,26 @@ #include "gtest/gtest.h" #include "passmanager.h" -#include "pass/functiontagspass.h" #include "Scanner.h" #include "Parser.h" #include #include using namespace std; using namespace xreate; TEST(EntryFunction, test1){ 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 d426cf1..15bcd61 100644 --- a/cpp/tests/testClangAPI.cpp +++ b/cpp/tests/testClangAPI.cpp @@ -1,191 +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 "/private/prg/vendors/clang/lib/CodeGen/CodeGenTypes.h" -#include "/private/prg/vendors/clang/lib/CodeGen/CodeGenModule.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 +#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.7/bin/../lib/clang/3.7.0/include" - ,"-I/usr/bin/../lib/gcc/x86_64-linux-gnu/4.9/include" - ,"-I/usr/include/x86_64-linux-gnu" + ,"-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 = QString("#include \"%1\"").arg("libxml/tree.h").toStdString(); + 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*"; 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 = QString("#include \"%1\"").arg("bsd/stdlib.h").toStdString(); + 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/testLogging.cpp b/cpp/tests/testLogging.cpp index 1d6de19..a84026a 100644 --- a/cpp/tests/testLogging.cpp +++ b/cpp/tests/testLogging.cpp @@ -1,87 +1,87 @@ /* * testLogging.cpp * * Created on: Jun 23, 2015 * Author: pgess */ #include "gtest/gtest.h" #include "passmanager.h" #include "llvmlayer.h" #include "Parser.h" #include "pass/compilepass.h" #include "pass/logging.h" using namespace std; using namespace xreate; TEST(Logging, simpleInjection){ PassManager* man = PassManager::prepareForCode("test= function():: int; entry{x = 2+8::int. return x}"); man->runWithoutCompilation(); CompilePass* compilator = new CompilePass(man); compilator->run(); CompilePass::FunctionUnit* fTest = compilator->getFunctionUnit(CompilePass::FunctionQuery("test")); ASSERT_NE(fTest, nullptr); CompilePass::CodeScopeUnit* scopeUnitTest = fTest->getEntry(); CodeScope* scopeTest = scopeUnitTest->scope; Symbol symbX = scopeTest->findSymbol("x"); TypeAnnotation typX = scopeTest->findDefinition(symbX); llvm::Value* retRaw = scopeUnitTest->compile(); llvm::BasicBlock& blockTestRaw = fTest->raw->getEntryBlock(); LLVMLayer* llvm = man->llvm; //llvm->builder.SetInsertPoint(&blockTestRaw); CompilePass::Context params{fTest, scopeUnitTest, compilator}; Logging l(man); l.inject(symbX, params); llvm->initJit(); int (*f)() = (int(*)()) llvm->getFunctionPointer(fTest->raw); testing::internal::CaptureStdout(); f(); std::string&& output = testing::internal::GetCapturedStdout(); EXPECT_STREQ("10\n", output.c_str()); } TEST(Logging, simpleInjection2){ - PassManager* man = PassManager::prepareForCode("test= function():: int; entry{x = 2+8::int; logging. return x}"); + PassManager* man = PassManager::prepareForCode("test= function():: int; entry{x = 2+8::int; logging. x}"); man->runWithoutCompilation(); CompilePass* compiler= new CompilePass(man); compiler->run(); Logging* logger = new Logging(man); logger->initDependencies(compiler); logger->run(); man->llvm->initJit(); man->llvm->print(); int (*f)() = (int(*)()) man->llvm->getFunctionPointer(compiler->getEntryFunction()); testing::internal::CaptureStdout(); f(); std::string&& output = testing::internal::GetCapturedStdout(); EXPECT_STREQ("10\n", output.c_str()); } TEST(Logging, simpleInjection3){ FILE* input = fopen("scripts/cases/log.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(); fclose(input); } diff --git a/scripts/cases/log.xreate b/scripts/cases/log.xreate index 1bb0ac9..997edf1 100644 --- a/scripts/cases/log.xreate +++ b/scripts/cases/log.xreate @@ -1,64 +1,64 @@ /* Log level: Log entry(flat, hierarchical) */ // EXTERN INCLUDES interface(extern-c){ xml2 = library:: pkgconfig("libxml-2.0"). include { xml2 = ["libxml/tree.h", "string.h"] }. } // CONTAINERS interface(dfa) { operator map:: (op(seqaccess)) -> impl(solid). operator list_range:: ()->impl(on_the_fly). operator list:: ()->impl(solid). operator fold:: (op(seqaccess)). operator index:: (op(randaccess)). /* operator map: (op(seqaccess)) -> impl(llvm_array | on_the_fly); */ } import raw("core/containers.lp"). // PROGRAM XmlNode = type alias { tag:: string, /* attrs:: [string],*/ content:: string }. Tree = type Tree(Leaf) [Leaf, [Tree(Leaf)]]. XmlTree = type alias Tree(XmlNode). test= function():: num; entry { filename = "project/documentation.fodt" :: string. docRaw = xmlParseFile(filename) :: xmlDocPtr. tree= xmlDocGetRootElement(docRaw) :: xmlNodePtr. childrenRaw = tree["children"]:: [xmlNodePtr]; containers:linkedlist(next, null). size = loop fold(childrenRaw->child:: xmlNodePtr, 0->count::int):: int { // $log{ // count +1:: warning, subsystem=xml // } - + //log{warning, subsystem=xml, ..} childName = child["name"]::string; logging. count + strlen(childName):: int }. size } diff --git a/scripts/input.xreate b/scripts/input.xreate index ccb0330..bb95705 100644 --- a/scripts/input.xreate +++ b/scripts/input.xreate @@ -1,92 +1,106 @@ /* 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"] + 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]. -test= function():: num; entry { + +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. - childrenRaw = tree["xmlChildrenNode"]:: [xmlNodePtr]; containers:linkedlist(next, null). - size = loop fold(childrenRaw->child:: xmlNodePtr, 0->count::int) : int { - count +1 + + 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). }. - size + 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 } */ -/* -query = function (tree:: XmlTree):: [string, string] -{ - children = switch :: context(children) - case default - { [] } - - case tree[0]:: NeedChildren(childrenFilters); ApplyTransform(transFilters) - { - loop fold (tree[1]->child:: Tree(Leaf) | childrenFilters, null->accum:: [Tree(Leaf)]) - :: [Tree(Leaf)] - {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 - {null}. - - node + children -} -*/ + +