diff --git a/coco/xreate.ATG b/coco/xreate.ATG index c24f5bc..3bfb0e9 100644 --- a/coco/xreate.ATG +++ b/coco/xreate.ATG @@ -1,515 +1,518 @@ //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 || y->kind == _pre); } 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". pre = "pre". lparen = '('. rparen = ')'. lbrack = '['. rbrack = ']'. lcurbrack = '{'. rcurbrack = '}'. equal = "==". assign = '='. implic = '-' '>'. colon = ':'. context = "context". tagcolon = "::". COMMENTS FROM "/*" TO "*/" NESTED COMMENTS FROM "//" TO lf IGNORE cr + lf + tab PRODUCTIONS Xreate = (. Function* function; .) { ( RuleDecl | InterfaceData | Imprt | ContextSection | IF(checkFuncDecl()) FDecl (. root.add(function); .) | TDecl ) }. Ident = ident {':' ident} (. name = t->val; .). FDecl = (. std::wstring fname; std::wstring varname; TypeAnnotation typIn; TypeAnnotation typOut; bool flagIsPrefunct = false; .) Ident assign [pre (. flagIsPrefunct = true; .)] function (. f = new Function(fname); f->isPrefunction = flagIsPrefunct; CodeScope* entry = f->getEntryScope(); .) ['(' Ident tagcolon Type (. f->addArg(std::move(varname), move(typIn)); .) {',' Ident tagcolon Type (. f->addArg(std::move(varname), move(typIn));.) } ')'] [ tagcolon ( IF(flagIsPrefunct) FnTag | Type (. f->setReturnType(typOut); .) ) {';' FnTag }] BDecl (. entry->__body.bindType(move(typOut));.) . -ContextSection<>= (. std::wstring context; Function* f; .) -"case" "context" tagcolon Ident -lcurbrack { FDecl (. root.add(f, context); .) +ContextSection<>= (. Expression context; Function* f; .) +"case" "context" tagcolon MetaSimpExpr +lcurbrack { FDecl (. f->guardContext = context; root.add(f); .) } rcurbrack. /** * TYPES * */ TypeTerm = (. std::wstring tid; .) ("string" | "int" | "num" | "float" | "bool") (. typ = Atom(t->val); .) . Type = (. TypeAnnotation typ2; TypeAtom typ3; std::wstring tid, field; .) ( TList | TStruct | TypeTerm (. typ = TypeAnnotation(typ3); .) |IF (checkIndex()) Ident lbrack Ident (. typ = TypeAnnotation(TypeOperator::ACCESS, {}); typ.__valueCustom = Atom(tid).get(); typ.fields.push_back(Atom(field).get()); .) {',' Ident (. typ.fields.push_back(Atom(field).get()); .) } rbrack | Ident (. typ = TypeAnnotation(TypeOperator::CUSTOM, {}); typ.__valueCustom = Atom(tid).get(); .) ['(' Type (. typ.__operator = TypeOperator::CALL; typ.__operands.push_back(typ2); .) {',' Type (. typ.__operands.push_back(typ2); .) } ')'] ) . TList = (. TypeAnnotation ty; .) '[' Type (. typ = TypeAnnotation(TypeOperator::ARRAY, {ty}); .) {',' Type (. typ.__operator = TypeOperator::TUPLE; typ.__operands.push_back(ty); .) }']' . TStruct = (. TypeAnnotation t; std::wstring field; .) '{' Ident tagcolon Type (. typ = TypeAnnotation(TypeOperator::STRUCT, {t}); typ.fields.push_back(Atom(field).get()); .) {',' Ident tagcolon Type} (. typ.__operands.push_back(t); typ.fields.push_back(Atom(field).get()); .) '}'. TDecl = (. std::wstring ttag; TypeAnnotation t, t1; std::wstring tname, arg; std::vector> args; .) Ident assign "type" ( "alias" Type (. root.add(move(t), Atom(tname)); .) | "variant" lparen Ident (. t = TypeAnnotation(TypeOperator::VARIANT, {}); args.push_back(Atom(arg)); .) {',' Ident (. args.push_back(Atom(arg)); .) } rparen (. t.addFields(move(args)); 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)); .) . ContextDecl = (. Expression tag; .) context tagcolon MetaSimpExpr (. scope->tags.push_back(move(tag)); .) {';' MetaSimpExpr (. scope->tags.push_back(move(tag)); .) }. //TODO forbid multiple body declaration (ExprTyped) BDecl = (. Expression body; TypeAnnotation typ; pushContextScope(scope); .) '{' { (RuleContextDecl | ContextDecl '.' | IF(checkAssignment()) VDecl '.' | ExprTyped (. scope->setBody(body); popContextScope();.) )} '}'. IfDecl = (. Expression cond; ManagedScpPtr blockTrue = root.add(new xreate::CodeScope(context.scope)); ManagedScpPtr blockFalse = root.add(new xreate::CodeScope(context.scope)); TypeAnnotation typIf; .) "if" '(' Expr ')' tagcolon Type BDecl<&*blockTrue> "else" BDecl<&*blockFalse> -(. e = Expression(Operator::IF, {cond}); e.addBlock(blockTrue); e.addBlock(blockFalse); .) +(. e = Expression(Operator::IF, {cond}); e.addBlock(blockTrue); e.addBlock(blockFalse); e.bindType(move(typIf)); .) . LoopDecl = (. Expression eIn, eAcc, eFilters; std::wstring varEl, varAcc, contextClass; TypeAnnotation typEl, typAcc; ManagedScpPtr block = root.add(new xreate::CodeScope(context.scope)); .) "loop" ("map" '(' Expr implic Ident tagcolon Type ')' tagcolon Type BDecl<&*block> (. e = Expression(Operator::MAP, {eIn}); e.addBindings({Atom(varEl)}); block->addArg(Atom(varEl), move(typEl)); e.addBlock(block); .) |"fold" '(' Expr implic Ident tagcolon Type ['|' Expr ] ',' Expr implic Ident tagcolon Type ')' tagcolon Type BDecl<&*block> (. e = Expression(Operator::FOLD, {eIn, eAcc}); e.addBindings({Atom(varEl), Atom(varAcc)}); block->addArg(Atom(varEl), move(typEl)); block->addArg(Atom(varAcc), move(typAcc)); e.addBlock(block); .) | "context" '(' string (. contextClass = t->val; .) ')' BDecl<&*block> (. e = Expression(Operator::LOOP_CONTEXT, {Expression(Atom(std::move(contextClass)))}); e.addBlock(block); .) ). SwitchDecl = (. TypeAnnotation typ; eSwitch = Expression(Operator::SWITCH, {}); Expression eCondition; Expression tag;.) ["switch" ("ad" "hoc" lparen Expr tagcolon MetaSimpExpr rparen (. eSwitch.op = Operator::SWITCH_ADHOC; eSwitch.operands.push_back(eCondition); eSwitch.tags.emplace(tag.getValueString(), move(tag)); .) | lparen Expr rparen tagcolon Type (. eSwitch.operands.push_back(eCondition); eSwitch.type = typ; .) ) ] CaseDecl {CaseDecl} . CaseDecl = (. ManagedScpPtr scope = root.add(new xreate::CodeScope(context.scope)); .) "case" ( "default" BDecl<&*scope> (. Expression exprCase(Operator::CASE_DEFAULT, {}); exprCase.addBlock(scope); outer.operands.insert(++outer.operands.begin(), exprCase); .) | CaseParams<&*scope> (. ManagedScpPtr scopeBody = root.add(new xreate::CodeScope(&*scope)); .) BDecl<&*scopeBody> (. Expression exprCase(Operator::CASE, {}); exprCase.addBlock(scope); exprCase.addBlock(scopeBody); outer.addArg(move(exprCase)); .) ). 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)); .) ). +SequenceDecl = +"sequence" ListLiteral (. sequence.setOp(Operator::SEQUENCE); .). + + /*============================ INTERFACES ===============================*/ Imprt<> = "import" "raw" lparen string (. root.__rawImports.push_back(Atom(t->val).get()); .) rparen . InterfaceData<> = "interface" '(' ( "dfa" ')' InterfaceDFA | "extern-c" ')' InterfaceExternC | "cfa" ')' InterfaceCFA | "adhoc" ')' InterfaceAdhoc ). InterfaceAdhoc<> = '{' [ PrefunctionSchemeDecl ] '}'. PrefunctionSchemeDecl<> = (. TypeAnnotation typReturn; std::wstring prefName; Expression exprCases; .) pre function Ident tagcolon Type '{' SwitchDecl '}' (. Expression prefData(Operator::CALL, {Atom(prefName), exprCases}); prefData.type = typReturn; root.addInterfaceData(Adhoc, move(prefData)); .). InterfaceExternC<> = (.xreate::ExternData data; .) '{' {IncludeExternDecl | LibExternDecl } '}' (. root.addExternData(move(data)); .) . LibExternDecl = (. std::wstring pkgname, libname; .) Ident assign "library" tagcolon "pkgconfig" '(' string (. pkgname = t->val; .) ')' '.' (. data.addLibrary(Atom(libname), Atom(pkgname)); .) . IncludeExternDecl = (. Expression inc; .) "include" StructLiteral '.' (. data.addIncludeDecl(move(inc)); .) . - InterfaceDFA<> = '{' { InstructDecl } '}' . - InstructDecl = (.Operator op; Expression tag; Expression scheme; std::vector& tags = scheme.operands; tags.push_back(Expression()); /* return value */ .) "operator" InstructAlias tagcolon '(' (.scheme.setOp(op); .) [ MetaSimpExpr (. tags.push_back(tag); .) { ',' MetaSimpExpr (. tags.push_back(tag); .) } ] ')' [ implic MetaSimpExpr (. tags[0] = tag; .) ] (. root.addDFAData(move(scheme)); .) '.'. InstructAlias = ( "map" (. op = Operator::MAP; .) | "list_range" (. op = Operator::LIST_RANGE; .) | "list" (. op = Operator::LIST; .) | "fold" (. op = Operator::FOLD; .) | "index" (. op = Operator::INDEX; .) ). InterfaceCFA<> = '{' { InstructCFADecl } '}' . InstructCFADecl<> = (.Operator op; Expression tag; Expression scheme; std::vector& tags = scheme.operands; .) "operator" InstructAlias tagcolon (. scheme.setOp(op); .) [ MetaSimpExpr (. tags.push_back(tag); .) { ',' MetaSimpExpr (. tags.push_back(tag); .) } ] '.' (. root.addInterfaceData(CFA, move(scheme)); .). /*============================ METAPROGRAMMING ===============================*/ // TagsDecl = (. Expression tag; TagModifier mod = TagModifier::NONE; .) // ':' { MetaSimpExpr (. /*f.addTag(std::move(tag), mod); */ .) // }. FnTag = (. Expression tag; TagModifier mod = TagModifier::NONE; .) MetaSimpExpr ['-' TagMod] (. f->addTag(std::move(tag), mod); .). TagMod = ( "assert" (. mod = TagModifier::ASSERT; .) | "require" (. mod = TagModifier::REQUIRE; .) ). RuleDecl<> = "rule" tagcolon (. RuleArguments args; RuleGuards guards; DomainAnnotation typ; std::wstring arg; .) '(' Ident tagcolon Domain (. args.add(arg, typ); .) {',' Ident tagcolon Domain (. args.add(arg, typ); .) } ')' ["case" RGuard {',' RGuard}] '{' RBody '}' . /* - TODO use RGuard for guards-*/ RuleContextDecl = (.Expression eHead, eGuards, eBody; .) "rule" "context" tagcolon MetaSimpExpr "case" MetaSimpExpr '{' MetaSimpExpr '}' (.scope->contextRules.push_back(Expression(Operator::CONTEXT_RULE, {eHead, eGuards, eBody})); .). Domain = ( "function" (. dom = DomainAnnotation::FUNCTION; .) | "variable" (. dom = DomainAnnotation::VARIABLE; .) ). RGuard= (. Expression e; .) MetaExpr (. guards.add(std::move(e)); .). MetaExpr= (.Operator op; Expression e2; .) MetaExpr2 [MetaOp MetaExpr2 (. e = Expression(op, {e, e2}); .) ]. MetaExpr2= ( '(' 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)); root.recognizeVariantIdentifier(e); .) | ListLiteral (. /* tuple */.) - | StructLiteral (. /* struct */.) + | StructLiteral (. /* struct */.) + | SequenceDecl | LoopDecl | IfDecl | SwitchDecl | AdhocDecl | 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); .) ) ] ']'. AdhocDecl = (. Expression command; .) "ad" "hoc" Expr (. e.setOp(Operator::ADHOC); e.addArg(std::move(command)); .). CalleeParams = (. Expression e2; TypeAnnotation typ; .) ExprTyped (. e.addArg(std::move(e2)); .) {',' ExprTyped (. e.addArg(std::move(e2)); .) }. AddOp< Operator& op> = (. op = Operator::ADD; .) ( '+' | '-' (. op = Operator::SUB; .) ). MulOp< Operator& op> = (. op = Operator::MUL; .) ( '*' | '/' (. op = Operator::DIV; .) ). RelOp< Operator& op> = (. op = Operator::EQU; .) ( equal | '<' (. op = Operator::LSS; .) | '>' (. op = Operator::GTR; .) ). END Xreate. diff --git a/config/default.json b/config/default.json index ef2aff4..80e5eb5 100644 --- a/config/default.json +++ b/config/default.json @@ -1,56 +1,58 @@ { "containers": { "id": { "implementations": "impl_fulfill_cluster", "clusters": "var_cluster", "prototypes": "proto_cluster", "linkedlist": "linkedlist" }, "impl": { "solid": "solid", "onthefly": "on_the_fly" } }, "logging": { "id": "logging" }, "function-entry": "entry", "clasp": { "bindings" : { "variable": "bind", "function": "bind_func", "scope": "bind_scope", - "scope_weak" : "bind_scope_weak" + "function_demand" : "bind_function_demand", + "scope_decision": "bind_scope_decision" }, "nonevalue": "nonevalue", "ret": { "symbol": "retv", "tag": "ret" } }, "tests": { - "template": "adhocs", + "template": "installation", "templates": { "basic": "EntryFunction*", "default": "*-", "types": "Types*-", "containers": "Containers*-", "ast": "AST*", "non-containers": "*-Containers*", "log": "Logging*", "clang": "ClangAPI*", "cfg": "CFG.*", "skip": "SkipDetection*", "raw-xml": "libxml2*", "xml": "Xml.*", - "adhocs": "ExpressionSerializer.*:Adhoc.*:Context.*" + "adhocs": "ExpressionSerializer.*:Adhoc.*:Context.*", + "installation": "Compilation.*:Sprint1.*" } } } diff --git a/core/control-context.lp b/core/control-context.lp index 1c27c0f..f815057 100644 --- a/core/control-context.lp +++ b/core/control-context.lp @@ -1,27 +1,23 @@ -%TODO context-dependent function specialization implemenetation(inline/...) - % context propagation -bind_scope_demand(Scope, Context):- bind_scope_demand(ScopeChild, Context), cfa_parent(ScopeChild, scope(Scope)). -bind_scope_demand(Scope, Context):- bind_function_demand(FnChild, Context), cfa_call(Scope, FnChild). -bind_function_demand(Fn, Context):- bind_scope_demand(ScopeChild, Context), cfa_parent(ScopeChild, function(Fn)). +bind_scope_decision(Scope, Fn, Resolution):- cfa_call(Scope, Fn), cfa_function_specializations(Fn, Resolution), bind_scope(Scope, Resolution). +bind_scope_decision(Scope, Fn, Resolution):- cfa_call(Scope, FnChild), bind_function_demand(FnChild, Fn), cfa_function_specializations(Fn, Resolution), bind_scope(Scope, Resolution). + +bind_scope_demand(Scope, FnCallee):- cfa_call(Scope, FnCallee), cfa_function_specializations(FnCallee, _), not bind_scope_decision(Scope, FnCallee, _). +bind_scope_demand(Scope, FnCallee):- bind_scope_demand(ScopeChild, FnCallee), cfa_parent(ScopeChild, scope(Scope)). +bind_scope_demand(Scope, FnCallee):- cfa_call(Scope, FnChild), bind_function_demand(FnChild, FnCallee), not bind_scope_decision(Scope, FnCallee, _). + +bind_function_demand(Fn, Demand):- bind_scope_demand(Scope, Demand), cfa_parent(Scope, function(Fn)). bind_scope(Scope, Context) :- bind_scope(ScopeParent, Context), cfa_parent(Scope, scope(ScopeParent)). bind_scope(Scope, Context) :- bind_scope(ScopeParent, Context): cfa_call(ScopeParent, FnCurrent); cfa_call(_, FnCurrent) , cfa_parent(Scope, function(FnCurrent)), bind_scope(_, Context), scope(Scope). -bind_scope_weak(Scope, Context) :- bind_scope(Scope, Context), bind_scope_demand(Scope, Context). -bind_scope_weak(Scope, Context) :- cfa_parent(Scope, scope(ScopeParent)), bind_scope_weak(ScopeParent, Context), scope(Scope), scope(ScopeParent). -bind_scope_weak(Scope, Context) :- bind_scope_weak(ScopeParent, Context), - cfa_call(ScopeParent, FnCurrent), cfa_parent(Scope, function(FnCurrent)). - % adhoc classes(unfinished): -%bind_func(Fn, adhoc_class(Context)) := bind_func(Fn, adhoc(Context)), bind_scope(Scope, Context), cfa_parent(Scope, function(Fn)). +%bind_func(Fn, adhoc_class(Context)) :- bind_func(Fn, adhoc(Context)), bind_scope(Scope, Context), cfa_parent(Scope, function(Fn)). %scope_parent(Scope, ScopeParent) :- cfa_parent(Scope, scope(ScopeParent)). %scope_parent(Scope, ScopeParent2) :- cfa_parent(Scope, scope(ScopeParent)), scope_parent(ScopeParent, ScopeParent2). %scope_function(Scope, Fn) :- cfa_parent(Scope, function(Fn)). -%scope_function(Scope, Fn) :- cfa_parent(Scope, scope(ScopeParent)), scope_function(ScopeParent, Fn). - - +%scope_function(Scope, Fn) :- cfa_parent(Scope, scope(ScopeParent)), scope_function(ScopeParent, Fn). \ No newline at end of file diff --git a/cpp/CMakeLists.txt b/cpp/CMakeLists.txt index 9630011..909759a 100644 --- a/cpp/CMakeLists.txt +++ b/cpp/CMakeLists.txt @@ -1,174 +1,183 @@ cmake_minimum_required(VERSION 2.8.11) project(xreate) find_package(LLVM REQUIRED CONFIG) # MACRO (ADD_PCH_RULE _header_filename _src_list) # SET(_gch_filename "${_header_filename}.gch") # LIST(APPEND ${_src_list} ${_gch_filename}) # SET (_args ${CMAKE_CXX_FLAGS}) # LIST(APPEND _args -c ${_header_filename} -o ${_gch_filename}) # GET_DIRECTORY_PROPERTY(DIRINC INCLUDE_DIRECTORIES) # foreach (_inc ${DIRINC}) # LIST(APPEND _args "-I" ${_inc}) # endforeach(_inc ${DIRINC}) # SEPARATE_ARGUMENTS(_args) # add_custom_command(OUTPUT ${_gch_filename} # COMMAND rm -f ${_gch_filename} # COMMAND ${CMAKE_CXX_COMPILER} ${CMAKE_CXX_COMPILER_ARG1} ${_args} # DEPENDS ${_header_filename}) # ENDMACRO(ADD_PCH_RULE _header_filename _src_list) set (CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake-tools") include(PCH_GCC4_v2) 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(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 + ./src/pass/compilepass.cpp + ./src/compilation/latecontextcompiler2.cpp + ${TEST_FILES} - - ./src/ast.cpp + + #./src/compilation/latecontextcompiler.cpp + + ./src/serialization/expressionserializer.cpp + ./src/serialization/expressionserializer2.cpp + ./src/query/context.cpp + + ./src/ast.cpp ./src/llvmlayer.cpp ./src/clasplayer.cpp - #./src/main.cpp - ./src/utils.cpp + ./src/utils.cpp ./src/passmanager.cpp - ./src/pass/abstractpass.cpp ./src/pass/dfgpass.cpp ./src/pass/compilepass.cpp + ./src/pass/abstractpass.cpp ./src/pass/dfgpass.cpp ./src/pass/cfgpass.cpp ./src/pass/loggerpass.cpp ./src/pass/adhocpass.cpp - #./src/pass/rulespass.cpp + #./src/pass/rulespass.cpp # ./src/compilation/instr-containers.cpp - ./src/compilation/latecontext.cpp + ./src/query/containers.cpp ./src/query/ptrvalid.cpp - ./src/query/context.cpp + ./src/attachments.cpp ./src/contextrule.cpp - ./src/expressionserializer.cpp - #${POTASSCO_PATH}/app/shared/src/clingocontrol.cc #${POTASSCO_PATH}/app/pyclingo/src/clingo_lib.cc ) set(COCO_PATH ${CMAKE_HOME_DIRECTORY}/../coco/) set(COCO_SOURCE_FILES ${COCO_PATH}/Parser.h ${COCO_PATH}/Scanner.h ${COCO_PATH}/Parser.cpp ${COCO_PATH}/Scanner.cpp ) INCLUDE_DIRECTORIES(${LLVM_INCLUDE_DIRS}) INCLUDE_DIRECTORIES("/usr/include/libxml2") INCLUDE_DIRECTORIES(${COCO_PATH} ./src) INCLUDE_DIRECTORIES(${POTASSCO_PATH}/libgringo ${POTASSCO_PATH}/libclasp ${POTASSCO_PATH}/libclingo ${POTASSCO_PATH}/libprogram_opts ) include_directories(${CMAKE_HOME_DIRECTORY}/../vendors/jeayeson/include/) #execute_process(COMMAND ${COCO_PATH}/gen-xreate WORKING_DIRECTORY OUTPUT_VARIABLE COCO_OUTPUT) message(STATUS "COCO GRAMMAR BUILD STATUS:" ${COCO_OUTPUT}) include_directories(${LLVM_INCLUDE_DIRS}) add_definitions(${LLVM_DEFINITIONS}) #add_definitions() set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Winvalid-pch -std=c++14 -D_GNU_SOURCE -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS") set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -g -Wall -fprofile-arcs -ftest-coverage -O0 -DWITH_THREADS=1") +set(RESOURCES_DBUS_INTERFACES + resources/hamster.xml +) # ADD_PCH_RULE (${CMAKE_HOME_DIRECTORY}/src/ast.h SOURCE_FILES) # ADD_PCH_RULE (${CMAKE_HOME_DIRECTORY}/src/llvmlayer.h SOURCE_FILES) # ADD_PCH_RULE (${CMAKE_HOME_DIRECTORY}/src/clasplayer.h SOURCE_FILES) # ADD_PCH_RULE (${CMAKE_HOME_DIRECTORY}/src/pass/abstractpass.h SOURCE_FILES) add_custom_command(OUTPUT ${COCO_PATH}/Parser.cpp COMMAND ${COCO_PATH}/gen-grammar WORKING_DIRECTORY ${COCO_PATH} DEPENDS ${COCO_PATH}/xreate.ATG ) add_executable(xreate ${SOURCE_FILES} ${COCO_SOURCE_FILES} src/ExternLayer.cpp src/ExternLayer.h) add_custom_target (coverage COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/src/code-coverage.sh WORKING_DIRECTORY ${CMAKE_BINARY_DIR}) message(STATUS "BINARY DIR" ${CMAKE_BINARY_DIR}) #add_dependencies(${PROJECT_NAME} coverageTarget) llvm_map_components_to_libnames(llvm_libs support core irreader all native nativecodegen) message(STATUS "LLVM LIBS: " ${llvm_libs}) set(LIBCLASP_LIBS clingo clasp gringo program_opts reify ) message(STATUS "CLANG LIBS: " ${CLANG_LIBS}) message(STATUS "CLASP LIBS: " ${LIBCLASP_LIBS}) 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(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) #set(COTIRE_UNITY_SOURCE_MAXIMUM_NUMBER_OF_INCLUDES "-j4") -#cotire(xreate) \ No newline at end of file +#cotire(xreate) diff --git a/cpp/src/ExternLayer.cpp b/cpp/src/ExternLayer.cpp index 3a866ab..ed57492 100644 --- a/cpp/src/ExternLayer.cpp +++ b/cpp/src/ExternLayer.cpp @@ -1,282 +1,285 @@ // // Created by pgess on 4/21/15. // #include "ExternLayer.h" #include #include #include "clang/Tooling/Tooling.h" #include "clang/Frontend/ASTUnit.h" #include "clang/Frontend/CodeGenOptions.h" #include "clang/ASTMatchers/ASTMatchers.h" #include "clang/ASTMatchers/ASTMatchFinder.h" #include "clang/Basic/TargetInfo.h" #include #include #include using namespace xreate; using namespace std; using namespace clang; using namespace clang::driver; using namespace clang::tooling; using namespace clang::ast_matchers; using namespace llvm; class FinderCallbackTypeDecl : public MatchFinder::MatchCallback { public : QualType typeResult; virtual void run(const MatchFinder::MatchResult &Result) { if (const TypedefDecl* decl = Result.Nodes.getNodeAs("typename")) { typeResult = decl->getUnderlyingType(); } } }; class FinderCallbackFunction : public MatchFinder::MatchCallback { public : QualType typeResult; virtual void run(const MatchFinder::MatchResult &Result) { if (const FunctionDecl* decl = Result.Nodes.getNodeAs("function")) { typeResult = decl->getType(); } } }; void ExternData::addLibrary(Atom&& name, Atom&& package) { __dictLibraries.emplace(name.get(), package.get()); } void ExternData::addIncludeDecl(Expression&& e) { assert(e.op == Operator::LIST_NAMED); //TODO ?? implement Expression parsing(Array of Expr as vector); 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) : __datalayout(llvm->module), __llvm(llvm) {} std::vector ExternLayer::fetchPackageFlags(const ExternEntry& entry){ std::vector args; FILE* flags = popen((string("pkg-config --cflags ") + entry.package).c_str(), "r"); size_t linesize=0; char* linebuf=0; ssize_t linelen=0; while ((linelen=getdelim(&linebuf, &linesize, ' ', flags))>0) { if (linebuf[0]=='\n') continue; if (linelen==1 && linebuf[0]==' ') continue; if (linebuf[linelen-1 ] == ' ') linebuf[linelen-1] = 0; llvm::outs() << '<' << linebuf << "> "; args.push_back(linebuf); free(linebuf); linebuf = 0; } pclose(flags); return (args); } std::vector ExternLayer::fetchPackageLibs(const ExternEntry& entry){ std::vector libs; FILE* flags = popen((string("pkg-config --libs ") + entry.package).c_str(), "r"); size_t linesize=0; char* linebuf=0; ssize_t linelen=0; while ((linelen=getdelim(&linebuf, &linesize, ' ', flags))>0) { if (linebuf[0]=='\n') continue; if (linelen==1 && linebuf[0]==' ') continue; if (linebuf[linelen-1 ] == ' ') linebuf[linelen-1] = 0; if (linelen>=2 && linebuf[0] == '-' && linebuf[1] == 'l'){ libs.push_back(linebuf + 2); } else { libs.push_back(linebuf); } llvm::outs() << '<' << linebuf << "> "; free(linebuf); linebuf = 0; } pclose(flags); return (libs); } void ExternLayer::loadLibraries(vector&& libs){ string msgErr; for (const string& lib: libs) { const string& libName = string("lib")+lib+".so"; if (!llvm::sys::DynamicLibrary::LoadLibraryPermanently(libName.c_str(), &msgErr)){ llvm::errs()<<"\n"<<"Loading library "<__externdata); // TODO use default include path from 'clang -xc++ -E' list code; std::vector args{ "-I/usr/include" ,"-I/usr/local/include" ,"-I/usr/lib/llvm-3.6/lib/clang/3.6.2/include" // ,"-I/usr/lib/gcc/x86_64-linux-gnu/4.9/include" // ,"-I/usr/include/x86_64-linux-gnu" }; std::vector libs; boost::format formatInclude("#include \"%1%\""); for(const ExternEntry& entry: entries) { llvm::outs()<<"[ExternC] Processing package: "<< entry.package << "\n"; llvm::outs()<<"[ExternC] args: "; vector&& args2 = fetchPackageFlags(entry); args.insert(args.end(), args2.begin(), args2.end()); for(const string arg: args2) { llvm::outs()<< "<" << arg << "> "; } llvm::outs()<<"\n[ExternC] libs: "; args2 = fetchPackageLibs(entry); for(const string arg: args2) { llvm::outs()<< "<" << arg << "> "; } libs.insert(libs.end(), args2.begin(), args2.end()); llvm::outs()<<"\n[ExternC] headers: "; std::transform(entry.headers.begin(), entry.headers.end(), std::inserter(code, code.begin()), [&formatInclude](const string header ) { string line = boost::str(formatInclude % header); llvm::outs()<< "<" << line << "> "; return line; }); llvm::outs() << '\n'; } 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()); + if (callback.typeResult.isNull()){ + cout <<"[External Layer] " << "Unknown function: "<getTypes().ConvertType(tyFuncQual); llvm::FunctionType* tyRawFunc = llvm::dyn_cast(tyRaw); llvm::Function* function = llvm::Function::Create(tyRawFunc, llvm::GlobalValue::ExternalLinkage, name, __llvm->module); __functions.emplace(name, function); return function; } diff --git a/cpp/src/ast.cpp b/cpp/src/ast.cpp index 2bebce2..6d5f2ad 100644 --- a/cpp/src/ast.cpp +++ b/cpp/src/ast.cpp @@ -1,726 +1,701 @@ #include "ast.h" #include "ExternLayer.h" #include #include #include using namespace std; namespace xreate{ class TypesResolver { private: const AST* ast; std::map scope; std::map signatures; ExpandedType expandType(const TypeAnnotation &t, const std::vector &args = std::vector()){ return TypesResolver(ast, scope, signatures)(t, args); } std::vector expandOperands(const std::vector& operands) { std::vector pack; pack.reserve(operands.size()); std::transform(operands.begin(), operands.end(), std::inserter(pack, pack.end()), [this](const TypeAnnotation& t){ return expandType(t); }); return pack; } public: TypesResolver(const AST* root, const std::map& scopeOuter = std::map(), std::map signaturesOuter = std::map()) : ast(root), scope(scopeOuter), signatures(signaturesOuter) { } ExpandedType operator()(const TypeAnnotation &t, const std::vector &args = std::vector()) { //assert(args.size() == t.bindings.size()); // invalid number of arguments for (size_t 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::VARIANT: { return ExpandedType(TypeAnnotation(t)); } 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(bindings.size() + params.size()); std::transform(params.begin(), params.end(), std::inserter(bindings, bindings.end()), [](const Atom& ident){return ident.get(); }); } void TypeAnnotation::addFields(std::vector>&& listFields) { fields.reserve(fields.size() + listFields.size()); std::transform(listFields.begin(), listFields.end(), std::inserter(fields, fields.end()), [](const Atom& ident){return ident.get(); }); } 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()) { } 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(); } void Expression::setValueDouble(double value){ __valueD = value; } bool Expression::isValid() const{ return (__state != INVALID); } Expression::Expression() : __state(INVALID), op(Operator::NONE) {} AST::AST() { } void AST::addInterfaceData(const ASTInterface& interface, Expression&& data ) { __interfacesData.emplace(interface, move(data)); } void AST::addDFAData(Expression &&data) { __dfadata.push_back(data); } void AST::addExternData(ExternData &&data) { __externdata.insert(__externdata.end(), data.entries.begin(), data.entries.end()); } void AST::add(Function* f) { __functions.push_back(f); - __indexFunctions.emplace(f->getName(), FunctionSpecialization{"", __functions.size()-1}); -} - -void -AST::add(Function* f, Atom && context){ - __functions.push_back(f); - __indexFunctions.emplace(f->getName(), FunctionSpecialization{context.get(), __functions.size()-1}); + __indexFunctions.emplace(f->getName(), __functions.size()-1); } void AST::add(MetaRuleAbstract *r) { __rules.push_back(r); } void AST::add(TypeAnnotation&& t, Atom&& alias){ if (t.__operator == TypeOperator::VARIANT){ for (int i=0, size=t.fields.size(); i< size; ++i){ __dictVariants.emplace(t.fields[i], make_pair(t, i)); } } __indexTypeAliases.emplace(alias.get(), t); } ManagedScpPtr AST::add(CodeScope* scope) { this->__scopes.push_back(scope); return ManagedScpPtr(this->__scopes.size()-1, &this->__scopes); } std::string AST::getModuleName() { const std::string name = "moduleTest"; return name; } ManagedPtr AST::findFunction(const std::string& name) { int count = __indexFunctions.count(name); if (!count) { return ManagedFnPtr::Invalid(); } assert(count ==1); auto range = __indexFunctions.equal_range(name); - return ManagedPtr(range.first->second.id, &this->__functions); + return ManagedPtr(range.first->second, &this->__functions); } std::list -AST::getFunctionVariants(const std::string& name){ - auto functions = __indexFunctions.equal_range(name); +AST::getAllFunctions() const{ + const size_t size = __functions.size(); std::list result; - std::transform(functions.first, functions.second, inserter(result, result.end()), - [this](auto f){return ManagedFnPtr(f.second.id, &this->__functions);}); + for (size_t i=0; i__functions)); + } return result; } -ManagedFnPtr -AST::findFunctionVariant(const std::string& name, const FunctionSpecializationQuery& query) { - boost::optional variant; - boost::optional variantDefault; - +//TASK select default specializations +std::list +AST::getFunctionVariants(const std::string& name) const{ auto functions = __indexFunctions.equal_range(name); - for (AST::FUNCTIONS_REGISTRY::const_iterator function = functions.first; function != functions.second; ++function){ - const string& guard = function->second.guard; - if (guard.empty()){ - assert(!variantDefault); - variantDefault = function->second; - } - - if (query.context.count(guard)){ - assert(!variant); - variant = function->second; - } - } - - //Pickup default specialization if necessary - if (!variant){ - variant = variantDefault; - } - - if (variant) return ManagedPtr(variant->id, &__functions); - - //case of no appropriate variant found - assert(0 == std::distance(functions.first, functions.second)); + std::list result; + std::transform(functions.first, functions.second, inserter(result, result.end()), + [this](auto f){return ManagedFnPtr(f.second, &this->__functions);}); - //case of external functions - return ManagedFnPtr::Invalid(); + return result; } template<> ManagedPtr AST::begin() {return ManagedPtr(0, &this->__functions);} template<> ManagedPtr AST::begin() {return ManagedPtr(0, &this->__scopes);} template<> ManagedPtr AST::begin() {return ManagedPtr(0, &this->__rules);} 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)); } void AST::recognizeVariantIdentifier(Expression& identifier){ assert(identifier.__state == Expression::IDENT); std::string name = identifier.getValueString(); if (__dictVariants.count(name)){ auto record = __dictVariants.at(name); const TypeAnnotation& typ = record.first; identifier.__state = Expression::VARIANT; identifier.setValueDouble(record.second); identifier.type = typ; } } 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) { 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]; } //TODO get rid of findSymbol. Determine symbol while AST parsing. Refind symbols not found while first pass. 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 + std::cout << "Unknown symbol: "<< name << std::endl; assert(false && "Symbol not found"); } bool CodeScope:: hasDeclaration(const Symbol& symbol) { CodeScope* self = symbol.scope; return (self->__declarations.count(symbol.identifier)); } const Expression& CodeScope::findDeclaration(const Symbol& symbol) { CodeScope* self = symbol.scope; if (! self->__declarations.count(symbol.identifier)) { // no declaration exists assert(false); } return self->__declarations[symbol.identifier]; } void RuleArguments::add(const Atom &arg, DomainAnnotation typ) { emplace_back(arg.get(), typ); } void RuleGuards::add(Expression&& e) { push_back(e); } MetaRuleAbstract:: MetaRuleAbstract(RuleArguments&& args, RuleGuards&& guards) : __args(std::move(args)), __guards(std::move(guards)) {} MetaRuleAbstract::~MetaRuleAbstract(){} RuleWarning:: RuleWarning(RuleArguments&& args, RuleGuards&& guards, Expression&& condition, Atom&& message) : MetaRuleAbstract(std::move(args), std::move(guards)), __message(message.get()), __condition(condition) {} RuleWarning::~RuleWarning(){} void RuleWarning::compile(ClaspLayer& layer) { - layer.addRuleWarning(*this); + //TODO restore addRuleWarning + //layer.addRuleWarning(*this); } bool operator< (const Symbol& s1, const Symbol& s2) { return (s1.scope < s2.scope) || (s1.scope==s2.scope && s1.identifier #include #include #include #include #include #include #include "attachments.h" #include "utils.h" #include namespace llvm{ class Value; } namespace xreate { struct String_t{}; struct Identifier_t {}; struct Number_t {}; struct Type_t {}; template class Atom {}; //DEBT hold for all atoms/identifiers Parser::Token data, like line:col position template<> class Atom { public: Atom(const std::wstring& value) { char buffer[32]; wcstombs(buffer, value.c_str(), 32); __value = buffer; } Atom(std::string && name): __value(name) {} const std::string& get() const{return __value; } private: std::string __value; }; template<> class Atom { public: Atom(wchar_t* value) { __value = wcstol(value, 0, 10); } Atom(int value) : __value(value) {} double get()const {return __value; } private: double __value; }; template<> class Atom { public: Atom(const std::wstring& value){ assert(value.size()); __value = std::string(++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, VARIANT, 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); void addFields(std::vector>&& listFields); 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, LOOP_CONTEXT, INDEX, IF, SWITCH, SWITCH_ADHOC, CASE, CASE_DEFAULT, LOGIC_AND, ADHOC, CONTEXT_RULE +ADD, SUB, MUL, DIV, EQU, LSS, GTR, NEG, LIST, LIST_RANGE, LIST_NAMED, CALL, NONE, IMPL/* implication */, MAP, FOLD, LOOP_CONTEXT, INDEX, IF, SWITCH, SWITCH_ADHOC, CASE, CASE_DEFAULT, LOGIC_AND, ADHOC, CONTEXT_RULE, SEQUENCE }; 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() const { 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; void setValueDouble(double value); const std::string& getValueString() const; void setValue(const Atom&& v); bool isValid() const; enum {INVALID, COMPOUND, IDENT, NUMBER, STRING, VARIANT} __state = INVALID; Operator op; std::vector bindings; std::map __indexBindings; std::vector operands; TypeAnnotation type; std::map tags; std::list blocks; private: std::string __valueS; double __valueD; }; template void Expression::addBindings(InputIt paramsBegin, InputIt paramsEnd) { size_t index = bindings.size(); std::transform(paramsBegin, paramsEnd, std::inserter(bindings, bindings.end()), [&index, this] (const Atom atom){ std::string key = atom.get(); this->__indexBindings[key] = index++; return key; }); } typedef std::list ExpressionList; enum class TagModifier {NONE, ASSERT, REQUIRE}; enum class DomainAnnotation {FUNCTION, VARIABLE}; class RuleArguments: public std::vector> { public: void add(const Atom& name, DomainAnnotation typ); }; class RuleGuards: public std::vector { public: void add(Expression&& e); }; class ClaspLayer; class LLVMLayer; class MetaRuleAbstract { public: MetaRuleAbstract(RuleArguments&& args, RuleGuards&& guards); virtual ~MetaRuleAbstract(); virtual void compile(ClaspLayer& layer) =0; protected: RuleArguments __args; RuleGuards __guards; }; class RuleWarning: public MetaRuleAbstract { friend class ClaspLayer; public: RuleWarning(RuleArguments&& args, RuleGuards&& guards, Expression&& condition, Atom&& message); virtual void compile(ClaspLayer& layer); ~RuleWarning(); private: std::string __message; Expression __condition; }; typedef unsigned int VID; /* class Expression: ExpressionAbstract { friend class CFGPass; public: llvm::Value* compile(LLVMLayer& l, Function* f, std::string* hintRetVar=0) const; }; */ typedef std::pair VariableDefinition; typedef std::pair VariableDeclaration; typedef std::pair Tag; struct Symbol { VID identifier; CodeScope * scope; }; struct SymbolTags_t{}; template<> struct AttachmentsDict { typedef std::map Data; static const unsigned int key = 2; }; bool operator< (const Symbol& s1, const Symbol& s2); bool operator== (const Symbol& s1, const Symbol& s2); class CodeScope { friend class Function; friend class PassManager; public: CodeScope(CodeScope* parent=0); void setBody(const Expression& body); void addDeclaration(const Atom &&name, TypeAnnotation &&typ, Expression&& body); void addArg(Atom && name, TypeAnnotation&& typ); //TODO exclude forceCompile partz Symbol findSymbol(const std::string &name); static const Expression& findDeclaration(const Symbol& symbol); static TypeAnnotation& findDefinition(const Symbol& symbol); static bool hasDeclaration(const Symbol& symbol); ~CodeScope(); std::vector __args; Expression __body; //TODO move __body to __declarations[0] SymbolAttachments attachments; std::map __vartable; /** * definition of return type has variable index Zero(0) */ //TODO move __definitions to SymbolsAttachments data std::unordered_map __definitions; std::unordered_map __declarations; std::vector tags; std::vector contextRules; 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; bool isPrefunction = false; //SECTIONTAG adhoc Function::isPrefunction flag Expression guardContext; private: std::vector __tags; }; class ExternData; struct ExternEntry { std::string package; std::vector headers; }; typedef Expanded ExpandedType; enum ASTInterface { CFA, DFA, Extern, Adhoc }; struct FunctionSpecialization { std::string guard; size_t id; }; struct FunctionSpecializationQuery { std::unordered_set context; }; class AST { public: AST(); - //TASK extern and DFA interfaces move into addINterfaceData + //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(Function* f, Atom && context); void add(MetaRuleAbstract* r); ManagedScpPtr add(CodeScope* scope); std::string getModuleName(); ManagedPtr findFunction(const std::string& name); typedef std::multimap FUNCTIONS_REGISTRY; - std::list> getAllFunctions(); + std::list getAllFunctions() const; + std::list getFunctionVariants(const std::string& name) const; 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; //TODO CFA data here. private: std::vector __rules; std::vector __functions; std::vector __scopes; FUNCTIONS_REGISTRY __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); void recognizeVariantIdentifier(Expression& identifier); private: std::map> __dictVariants; 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 adc4701..21237f6 100644 --- a/cpp/src/clasplayer.cpp +++ b/cpp/src/clasplayer.cpp @@ -1,670 +1,689 @@ #include "clasplayer.h" #include #include "utils.h" #include #include #include using namespace std; +//TODO escape identifiers started from upper case symbol 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"); const string& atomBindScope = Config::get("clasp.bindings.scope"); for (Gringo::Value atom : model.atoms(Gringo::Model::ATOMS)) { atom.print(cout); cout <<" | "<< endl; if (*atom.name() == atomBindVar || *atom.name() == atomBindFunc || *atom.name() == atomBindScope){ string name = *std::get<1>(parse(atom)).name(); __model.emplace(move(name), move(atom)); } __model.emplace(*atom.name(), move(atom)); } return true; } list multiplyLists(list> &&lists) { typedef list StringList; assert(lists.size()); StringList result(*lists.begin()); lists.pop_front(); boost::format concat("%s, %s"); for (StringList &list: lists) { StringList::const_iterator end = result.end(); for (StringList::iterator expr1I = result.begin(); expr1I != end; ++expr1I) { if (list.size() == 0) continue; StringList::const_iterator expr2I = list.begin(); for (int expr2No = 0, size = list.size() - 1; expr2No < size; ++expr2No, ++expr1I) result.push_back(str(concat %(*expr1I) %(*expr2I))); *expr1I = str(concat %(*expr1I) %(*expr2I)); } } return result; } void ClaspLayer::setCFAData(CFAGraph &&graph) { cfagraph = graph; } void ClaspLayer::addDFAData(DFAGraph &&graph) { dfaData = graph; std::set symbols; ostream &cout = __partGeneral; cout << endl << "%\t\tStatic analysis: DFA" << endl; std::vector>::iterator i1; std::vector::iterator i2; boost::format formatDfaConnection("dfa_connection(%1%, %2%, %3%)."); boost::format format2Args("(%1%, %2%)"); for (i1= dfaData.__edges.begin(), i2 = dfaData.__data.begin(); i1!= dfaData.__edges.end(); ++i1, ++i2 ) { string edgeName; switch (*i2) { case DFGConnection::OPT: edgeName = "opt"; break; case DFGConnection::ALIAS: edgeName = "alias"; break; case DFGConnection::PROTO: edgeName = "proto"; break; } cout << formatDfaConnection %(format2Args %(i1->first.identifier) %(i1->first.scope)).str() %(format2Args %(i1->second.identifier) %(i1->second.scope)).str() %edgeName << " %" <first) << " - " << getHintForPackedSymbol(i1->second) <first); symbols.insert(i1->second); } boost::format formatBind("bind(%1%, %2%)."); for (const pair& tag: dfaData.__tags) { for (string variant: compile(tag.second)) { cout << (formatBind % (format2Args %(tag.first.identifier) %(tag.first.scope)) % (variant)) << "%" << getHintForPackedSymbol(tag.first) << endl; } symbols.insert(tag.first); } for (const SymbolPacked& s: symbols) { cout << "v(" << format2Args % (s.identifier) % (s.scope) << ")." << " %" << getHintForPackedSymbol(s) < tagRaw = compile(tag.first); assert(tagRaw.size() == 1); cout << formatBind % (function.second) % (tagRaw.front()) << endl; ++counterTags; } } + if (bufFunctionNames.tellp()){ + cout << formatFunction % (bufFunctionNames.str().substr(2)) << std::endl; + } + if (counterTags == 0) { - cout << "%no tags at all" << endl; + cout << "%no functtion tags at all" << endl; } //declare scopes - boost::format formatScope("scope(%1%)."); - for (auto scope: __indexScopes) { - //std::string function = scope.first. - cout << formatScope % scope.second << std::endl; - } + boost::format formatScope("scope(0..%1%)."); + cout << formatScope % (__registryScopes.size() - 1) << std::endl; //show context rules: for (auto rule: cfagraph.__contextRules) { cout << ContextRule(rule.second).compile(rule.first) << std::endl; }; //show scope tags: counterTags = 0; boost::format formatScopeBind(atomBindingScope + "(%1%, %2%)."); for (auto entry: cfagraph.__scopeTags) { ScopePacked scopeId = entry.first; const Expression& tag = entry.second; list tagRaw = compile(tag); assert(tagRaw.size() == 1); cout << formatScopeBind % scopeId %(tagRaw.front()) << endl; ++counterTags; } if (counterTags == 0) { cout << "%scope tags: no tags at all" << endl; } cout << endl << "%\t\tStatic analysis: CFA" << endl; //parent connections //TEST CFG parent function boost::format formatFunctionParent("cfa_parent(%1%, function(%2%))."); for (const auto &relation: cfagraph.__parentFunctionRelations) { const string& function = cfagraph.__nodesFunction.left.at(relation.second); cout << formatFunctionParent % relation.first % function << endl; } //TEST CFG parent scope boost::format formatScopeParent("cfa_parent(%1%, scope(%2%))."); for (const auto &relation: cfagraph.__parentScopeRelations) { cout << formatScopeParent % relation.first % relation.second << endl; } //call connections boost::format formatCall("cfa_call(%1%, %2%)."); for (const auto &relation: cfagraph.__callRelations) { const ScopePacked scopeFrom = relation.first; const string& functionTo = cfagraph.__nodesFunction.left.at(relation.second); cout << formatCall % (scopeFrom) % (functionTo) << endl; } + + //function specializations descrtiption + //SECTIONTAG late-context cfa_function_specializations + boost::format formatSpecializations("cfa_function_specializations(%1%, %2%)."); + const list& functions = ast->getAllFunctions(); + for (auto f: functions){ + if (f->guardContext.isValid()){ + list guardRaw = compile(f->guardContext); + assert(guardRaw.size() == 1); + cout << formatSpecializations % (f->getName()) % (guardRaw.front()) << endl; + } + } } void ClaspLayer::addRuleWarning(const RuleWarning &rule) { //__partGeneral << rule << endl; list domains; boost::format formatDef("%1%(%2%)"); std::transform(rule.__args.begin(), rule.__args.end(), std::inserter(domains, domains.begin()), [&formatDef](const std::pair &argument) { string domain; switch (argument.second) { case DomainAnnotation::FUNCTION: domain = "function"; break; case DomainAnnotation::VARIABLE: domain = "variable"; break; } return boost::str(formatDef % domain % argument.first); }); list vars; std::transform(rule.__args.begin(), rule.__args.end(), std::inserter(vars, vars.begin()), [](const std::pair &argument) { return argument.first.c_str(); }); list> guardsRaw; std::transform(rule.__guards.begin(), rule.__guards.end(), std::inserter(guardsRaw, guardsRaw.begin()), [this](const Expression &guard) { return compile(guard); }); const list& guards = multiplyLists(std::move(guardsRaw)); list &&branches = compileNeg(rule.__condition); boost::format formatWarning("warning(%1%, (%2%)):- %3%, %4%, %5%."); for (const string &guardsJoined: guards) for (const string &branch: branches) { unsigned int hook = registerWarning(string(rule.__message)); __partGeneral << formatWarning %(hook) %(boost::algorithm::join(vars, ", ")) %(branch) %(guardsJoined) %(boost::algorithm::join(domains, ", ")) < ClaspLayer::compile(const Expression &e){ list result; switch (e.op) { case Operator::CALL: { assert(e.__state == Expression::COMPOUND); std::list> operands; std::transform(e.operands.begin(), e.operands.end(), std::inserter(operands, operands.begin()), [](const Expression &e) { return ClaspLayer::compile(e); }); list &&operands_ = multiplyLists(std::move(operands)); result.push_back(boost::str(boost::format("%1%(%2%)") % (e.__valueS) % (boost::algorithm::join(operands_, ", ")))); break; } case Operator::NEG: { assert(e.operands.size() == 1); const Expression &op = e.operands.at(0); list &&rawOp = compile(op); assert(rawOp.size() == 1); result.push_back((boost::format("not %1%")%(rawOp.front())).str()); break; }; case Operator::NONE: { switch (e.__state) { case Expression::IDENT: result.push_back(e.__valueS); break; case Expression::NUMBER: result.push_back(to_string(e.__valueD)); break; default: assert(true); } break; } default: break; } //TODO Null ad hoc ClaspLayer implementation // if (e.isNone()){ // result.push_back(e.__valueS); // } assert(result.size()); return result; } std::list ClaspLayer::compileNeg(const Expression &e){ list result; switch (e.op) { case Operator::IMPL: { assert(e.__state == Expression::COMPOUND); assert(e.operands.size() == 2); list operands1 = compile(e.operands.at(0)); list operands2 = compile(e.operands.at(1)); boost::format formatNeg("%1%, not %2%"); for (const auto &op1: operands1) for (const auto &op2: operands2) { result.push_back(boost::str(formatNeg %(op1) % (op2))); } break; } case Operator::NEG: { assert(e.operands.size() == 1); const Expression &op = e.operands.at(0); list &&rawOp = compile(op); assert(rawOp.size() == 1); result.push_back(rawOp.front()); break; }; default: assert(true); } return result; } unsigned int ClaspLayer::registerWarning(std::string &&message) { static int warningId = 0; __warnings.emplace(warningId, message); return warningId++;; } void ClaspLayer::involveImports() { ostream &out = __partGeneral; for (string fn: ast->__rawImports) { std::ifstream file(fn); if (!file) continue; while(!file.eof()){ string line; std::getline(file, line); out << line << endl; } } } void ClaspLayer::addRawScript(std::string&& script){ __partGeneral << script; } void ClaspLayer::run() { involveImports(); involveCFAData(); ostringstream program; program << __partTags.str() << __partGeneral.str(); cout << FYEL(program.str()) << endl; std::vector args{"clingo", nullptr}; DefaultGringoModule moduleDefault; Gringo::Scripts scriptsDefault(moduleDefault); ClingoLib ctl(scriptsDefault, 0, args.data()); ctl.add("base", {}, program.str()); ctl.ground({{"base", {}}}, nullptr); // solve Gringo::SolveResult result = ctl.solve([this](Gringo::Model const &model) { this->onModel(model); return true; }, {}); if (result == Gringo::SolveResult::SAT) { cout << FGRN("SUCCESSFULLY") << endl; } else { cout << FRED("UNSUCCESSFULLY") << endl; } // invoke all query plugins to process clasp data for (auto q: __queries) { q.second->init(this); } } ClaspLayer::ClaspLayer() { } ClaspLayer::ModelFragment ClaspLayer::query(const std::string& atom) { if (! __model.count(atom)){ return boost::none; } return ModelFragment(__model.equal_range(atom)); } ScopePacked - ClaspLayer::pack(CodeScope* scope) { + ClaspLayer::pack(CodeScope* const scope) { auto pos = __indexScopes.emplace(scope, __indexScopes.size()); if (pos.second) __registryScopes.push_back(scope); return pos.first->second; } SymbolPacked ClaspLayer::pack(const Symbol& symbol, std::string hintSymbolName) { SymbolPacked result; result.scope = pack(symbol.scope); result.identifier = symbol.identifier; __indexSymbolNameHints.emplace(result, hintSymbolName); return result; } Symbol ClaspLayer::unpack(const SymbolPacked& symbol) { return Symbol{symbol.identifier, __registryScopes[symbol.scope]}; }; std::string ClaspLayer::getHintForPackedSymbol(const SymbolPacked& symbol){ auto result = __indexSymbolNameHints.find(symbol); return (result == __indexSymbolNameHints.end())? "" : result->second; } /* void AspOutPrinter::reportSolution(const Clasp::Solver&, const Clasp::Enumerator&, bool complete) { if (complete) std::cout << "No more models!" << std::endl; else std::cout << "More models possible!" << std::endl; } void AspOutPrinter::reportModel(const Clasp::Solver& s, const Clasp::Enumerator&) { std::cout << "Model " << s.stats.solve.models << ": \n"; // get the symbol table from the solver const Clasp::AtomIndex& symTab = *s.strategies().symTab; for (Clasp::AtomIndex::const_iterator it = symTab.begin(); it != symTab.end(); ++it) { // print each named atom that is true w.r.t the current assignment } std::cout << std::endl; } */ /***************************************** * CFAGraph ***************************************** */ void CFAGraph::addFunctionAnnotations(const std::string& function, const std::vector&tags) { unsigned int fid = registerNodeFunction(function); for (Tag tag: tags){ __functionTags.emplace(fid, tag); } } void CFAGraph::addScopeAnnotations(const ScopePacked& scope, const std::vector& tags){ for (Expression tag: tags){ __scopeTags.emplace(scope, tag); } } void CFAGraph::addContextRules(const ScopePacked& scope, const std::vector& rules){ for (Expression rule: rules){ __contextRules.emplace(scope, rule); } } void CFAGraph::addCallConnection(const ScopePacked& scopeFrom, const std::string& functionTo) { unsigned int idFuncTo = registerNodeFunction(functionTo); __callRelations.emplace(scopeFrom, idFuncTo); } void CFAGraph::addParentConnection(const ScopePacked& scope, const std::string& functionParent){ __parentFunctionRelations.emplace(scope, registerNodeFunction(functionParent)); } void CFAGraph::addParentConnection(const ScopePacked& scope, const ScopePacked& scopeParent){ __parentScopeRelations.emplace(scope, scopeParent); } unsigned int CFAGraph::registerNodeFunction(const std::string& fname){ auto pos = __nodesFunction.left.insert(make_pair(__nodesFunction.size(), fname)); return pos.first->first; } /***************************************** * 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->isConnected(__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& symbolFrom){ if (__link != DFGConnection::ALIAS){ assert(false && "Undefined behaviour"); } for (const Expression& tag: symbolFrom.tags){ __graph->__tags.emplace(__nodeTo, tag); } } void operator()(const SymbolInvalid&){ if (__link == DFGConnection::ALIAS) return; if (__link == DFGConnection::OPT) return; assert(false && "Undefined behaviour"); } VisitorAddLink(DFAGraph* const dfagraph, const SymbolPacked& nodeTo, DFGConnection link): __graph(dfagraph), __nodeTo(nodeTo), __link(link) {} private: DFAGraph* const __graph; SymbolPacked __nodeTo; DFGConnection __link; }; bool DFAGraph::isConnected(const SymbolPacked& identifierTo, const SymbolPacked& identifierFrom) { auto range = __outEdges.equal_range(identifierFrom); for(std::multimap::iterator edge = range.first; edge != range.second; ++edge) { if (__edges[edge->second].second == identifierTo) return true; } return false; } void DFAGraph::addConnection(const SymbolPacked& nodeTo, const SymbolNode& nodeFrom, DFGConnection link) { VisitorAddLink visitor(this, nodeTo, link); boost::apply_visitor(visitor, nodeFrom); } void DFAGraph::addAnnotation(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); } IQuery* ClaspLayer::registerQuery(IQuery *query, const QueryId& id) { return __queries.emplace(id, query).first->second; } IQuery* ClaspLayer::getQuery(const QueryId& id){ assert(__queries.count(id) && "Undefined query"); return __queries.at(id); } } diff --git a/cpp/src/clasplayer.h b/cpp/src/clasplayer.h index 2e208d3..f920106 100644 --- a/cpp/src/clasplayer.h +++ b/cpp/src/clasplayer.h @@ -1,239 +1,239 @@ #ifndef CLASPLAYER_H #define CLASPLAYER_H #include "ast.h" #include "contextrule.h" #include #include #include #include #include #include namespace xreate { typedef unsigned int ScopePacked; class CFAGraph { friend class ClaspLayer; public: void addFunctionAnnotations(const std::string& function, const std::vector&tags); void addScopeAnnotations(const ScopePacked& scope, const std::vector&tags); void addContextRules(const ScopePacked& scope, const std::vector&rules); void addCallConnection(const ScopePacked& scopeFrom, const std::string& functionTo); void addParentConnection(const ScopePacked& scope, const std::string& functionParent); void addParentConnection(const ScopePacked& scope, const ScopePacked& scopeParent); // void addScopeRetIdentifier(const ScopePacked& scope, const SymbolPacked& identifier); private: std::map __parentFunctionRelations; std::map __parentScopeRelations; - std::multimap __callRelations; + std::set> __callRelations; boost::bimap __nodesFunction; std::multimap __functionTags; std::multimap __scopeTags; std::multimap __contextRules; unsigned int registerNodeFunction(const std::string& fname); }; struct SymbolPacked { VID identifier; ScopePacked scope; }; struct SymbolTransient{ std::list tags; }; struct SymbolInvalid{}; typedef boost::variant SymbolNode; bool operator==(const SymbolPacked& s1, const SymbolPacked& s2); bool operator<(const SymbolPacked& s1, const SymbolPacked& s2); enum class DFGConnection{ ALIAS, OPT, PROTO}; class VisitorAddTag; class VisitorAddLink; class DFAGraph { friend class ClaspLayer; friend class VisitorAddTag; friend class VisitorAddLink; public: void addAnnotation(SymbolNode& identifier, Expression&& tag); void addConnection(const SymbolPacked& identifierTo, const SymbolNode& identifierFrom, DFGConnection link); bool isConnected(const SymbolPacked& identifierTo, const SymbolPacked& identifierFrom); 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() {} }; enum class QueryId{ ContainersQuery, ContextQuery, PtrvalidQuery }; class ClaspLayer { friend class ContextRule; public: AST *ast; DFAGraph dfaData; CFAGraph cfagraph; ClaspLayer(); IQuery* registerQuery(IQuery* query, const QueryId& id); IQuery* getQuery(const QueryId& id); void addFunctionTags(const std::string &function, const std::vector &tags); void setCFAData(CFAGraph &&graph); void addDFAData(DFAGraph &&graph); void addRuleWarning(const RuleWarning &rule); void run(); template static std::tuple parse(const Gringo::Value& atom); typedef std::multimap::const_iterator ModelIterator; typedef boost::optional> ModelFragment; ModelFragment query(const std::string& atom); - ScopePacked pack(CodeScope* scope); + ScopePacked pack(CodeScope* const scope); SymbolPacked pack(const Symbol& symbol, std::string hintSymbolName=""); Symbol unpack(const SymbolPacked& symbol); std::string getHintForPackedSymbol(const SymbolPacked& symbol); void addRawScript(std::string&& script); private: // all query plugins to process clasp data std::map __queries; std::multimap __model; std::map __warnings; std::ostringstream __partTags; std::ostringstream __partGeneral; std::map __indexSymbolNameHints; std::unordered_map __indexScopes; std::vector __registryScopes; void printWarnings(std::ostream& out); bool onModel(Gringo::Model const &model); static std::list compile(const Expression &e); static std::list compileNeg(const Expression &e); unsigned int registerWarning(std::string &&message); void involveImports(); void involveCFAData(); }; template struct ParseImplAtom { static typ get(const Gringo::Value& atom) { return atom.num(); } }; template<> struct ParseImplAtom { static std::string get(const Gringo::Value& atom) { return *atom.string(); }}; template<> struct ParseImplAtom { static SymbolPacked get(const Gringo::Value& atom) { auto result = ClaspLayer::parse(atom); return SymbolPacked{std::get<0>(result), std::get<1>(result)}; }}; template<> struct ParseImplAtom { static Gringo::Value get(const Gringo::Value& atom) { return atom; }}; template<> struct ParseImplAtom { static Expression get(const Gringo::Value& atom) { switch (atom.type()){ case Gringo::Value::NUM: return Expression(atom.num()); case Gringo::Value::ID: return Expression((std::string(atom.string()))); case Gringo::Value::FUNC: { Expression result(Operator::CALL, {Expression(std::string(atom.name()))}); for(const Gringo::Value& arg: atom.args()){ result.addArg(ParseImplAtom::get(arg)); } return result; } default: { assert(false); } } }}; 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/compilation/instr-containers.cpp b/cpp/src/compilation/instr-containers.cpp index 38192a0..2cbf0a0 100644 --- a/cpp/src/compilation/instr-containers.cpp +++ b/cpp/src/compilation/instr-containers.cpp @@ -1,575 +1,575 @@ #include "instr-containers.h" #include "llvmlayer.h" #include "ast.h" #include "query/context.h" #include "query/containers.h" #include "query/ptrvalid.h" using namespace std; using namespace llvm; using namespace xreate; using namespace xreate::containers; #define NAME(x) (hintRetVar.empty()? x : hintRetVar) #define UNUSED(x) (void)(x) #define EXPAND_CONTEXT \ LLVMLayer* llvm = context.pass->man->llvm; \ - CompilePass::CodeScopeUnit* scope = context.scope; \ - CompilePass::FunctionUnit* function = context.function; + compilation::CodeScopeUnit* scope = context.scope; \ + compilation::FunctionUnit* function = context.function; -Instructions::Instructions(CompilePass::Context ctx) +Instructions::Instructions(compilation::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); + compilation::CodeScopeUnit* scopeLoopUnit = function->getScopeUnit(scopeLoop); scopeLoopUnit->bindArg(elIn, move(varEl)); Value* elOut = scopeLoopUnit->compile(); Value *pElOut = builder.CreateGEP(dataOut, ArrayRef(std::vector{ConstantInt::get(tyNum, 0), stateLoop})); builder.CreateStore(elOut, pElOut); //next iteration preparing Value *stateLoopNext = builder.CreateAdd(stateLoop,llvm::ConstantInt::get(tyNum, 1)); stateLoop->addIncoming(stateLoopNext, blockLoop); //next iteration checks: Value* condAfter = builder.CreateICmpSLE(stateLoopNext, rangeTo); builder.CreateCondBr(condAfter, blockLoop, blockAfterLoop); //finalization: builder.SetInsertPoint(blockAfterLoop); return dataOut; } Value* Instructions::compileArrayIndex(const Symbol &dataSymbol, std::vector indexes, std::string hintRetVar) { EXPAND_CONTEXT UNUSED(function); //TODO find out symbol identifier in order to name it in raw llvm; llvm::Value* data = scope->compileSymbol(dataSymbol); const Expression& decl = CodeScope::findDeclaration(dataSymbol); if (decl.op == Operator::LIST) { assert(indexes.size() == 1); return llvm->builder.CreateExtractElement(data, indexes[0], NAME("el")); } indexes.insert(indexes.begin(), llvm::ConstantInt::get(tyNum, 0)); Value *pEl = llvm->builder.CreateGEP(data, llvm::ArrayRef(indexes)); return llvm->builder.CreateLoad(pEl, NAME("el")); } Value* Instructions::compileStructIndex(llvm::Value* aggregate, const ExpandedType& t, const std::string& idx){ EXPAND_CONTEXT UNUSED(scope); TypeUtils types(llvm); std::vector&& fields = types.getStructFields(t); for (unsigned i=0, size = fields.size(); i refs; llvm::IntegerType* tyInt = llvm::Type::getInt32Ty(llvm::getGlobalContext()); llvm::ConstantInt* zero = llvm::ConstantInt::get(tyInt, 0, false); llvm::BasicBlock *blockSafe = llvm::BasicBlock::Create(llvm::getGlobalContext(), "safe", function->raw); // safety check: not null ptr Symbol s; if (! QueryPtrValid::assertValidPtr(s)){ PointerType* tyAggr = dyn_cast(aggregate->getType()); llvm::Value* null = llvm::ConstantPointerNull::get(tyAggr); Value* condNull = llvm->builder.CreateICmpNE(aggregate, null); llvm::BasicBlock *blockException = llvm::BasicBlock::Create(llvm::getGlobalContext(), "exception", function->raw); llvm->builder.CreateCondBr(condNull, blockSafe, blockException); llvm->initExceptionBlock(blockException); } llvm->builder.SetInsertPoint(blockSafe); std::vector indexes; //dereference pointer if (types.isPointer(t)){ indexes.push_back(zero); } indexes.push_back(ConstantInt::get(tyInt, i)); Value* addr = llvm->builder.CreateGEP(aggregate, indexes); return llvm->builder.CreateLoad(addr); } } assert(false && "not found required struct field"); } llvm::Value* Instructions::compileFold(const Expression& fold, const std::string& hintRetVar) { EXPAND_CONTEXT assert(fold.op == Operator::FOLD); //initialization: Symbol varInSymbol = scope->scope->findSymbol(fold.getOperands()[0].getValueString()); Implementation info = Query::queryImplementation(varInSymbol); Iterator* it = Iterator::create(context, varInSymbol); llvm::Value* rangeFrom = it->begin(); llvm::Value* rangeTo = it->end(); llvm::Value* accumInit = scope->process(fold.getOperands()[1]); std::string varIn = fold.getOperands()[0].getValueString(); std::string varAccum = fold.bindings[1]; std::string varEl = fold.bindings[0]; llvm::Value* valSat = nullptr; bool flagHasSaturation = false; //false; // TODO add `saturation` ann. llvm::BasicBlock *blockBeforeLoop = llvm->builder.GetInsertBlock(); llvm::BasicBlock *blockLoop = llvm::BasicBlock::Create(llvm::getGlobalContext(), "fold", function->raw); llvm::BasicBlock *blockAfterLoop = llvm::BasicBlock::Create(llvm::getGlobalContext(), "postfold", function->raw); llvm::BasicBlock *blockEarly = llvm::BasicBlock::Create(llvm::getGlobalContext(), "earlyret", function->raw); // * initial check Value* condBefore = llvm->builder.CreateICmpNE(rangeFrom, rangeTo); llvm->builder.CreateCondBr(condBefore, blockLoop, blockEarly); llvm->builder.SetInsertPoint(blockEarly); llvm->builder.CreateRet(accumInit); //TODO implement saturation; add unittests; // Saturation check if (flagHasSaturation) { Value* condSat = llvm->builder.CreateICmpNE(accumInit, valSat); llvm->builder.CreateCondBr(condSat, blockLoop, blockAfterLoop); } // * create phi llvm->builder.SetInsertPoint(blockLoop); llvm::PHINode *accum = llvm->builder.CreatePHI(tyNum, 2, NAME("accum")); accum->addIncoming(accumInit, blockBeforeLoop); llvm::PHINode *stateLoop = llvm->builder.CreatePHI(rangeFrom->getType(), 2, "foldIt"); stateLoop->addIncoming(rangeFrom, blockBeforeLoop); // * loop body CodeScope* scopeLoop = fold.blocks.front(); - CompilePass::CodeScopeUnit* loopUnit = function->getScopeUnit(scopeLoop); + compilation::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::compileLoopContext(const Expression& expression, const std::string& hintRetVar){ EXPAND_CONTEXT llvm::IRBuilder<>& builder = llvm->builder; ContextQuery* queryContext = reinterpret_cast (context.pass->man->clasp->getQuery(QueryId::ContextQuery)); ScopePacked scopeOuterId = context.pass->man->clasp->pack(scope->scope); - std::list contextScopeOuter = queryContext->getContext(scopeOuterId); + const ContextDomain& contextScopeOuter = queryContext->getContext(scopeOuterId); std::string classSelected = expression.operands[0].getValueString(); std::list elementsSelected; for (const Expression& c: contextScopeOuter){ if (c.op == Operator::CALL && c.getValueString() == classSelected){ assert(c.operands.size()); elementsSelected.push_back(c.operands[0]); } } assert(expression.blocks.size()); CodeScope* scopeInner = expression.blocks.front(); - CompilePass::CodeScopeUnit* scopeInnerUnit = function->getScopeUnit(scopeInner); + compilation::CodeScopeUnit* scopeInnerUnit = function->getScopeUnit(scopeInner); ScopePacked scopeInnerId = context.pass->man->clasp->pack(scopeInner); llvm::Value* result = nullptr; for (const Expression& element: elementsSelected){ std::string blockName = "context" + element.getValueString(); llvm::BasicBlock *blockInner = llvm::BasicBlock::Create(llvm::getGlobalContext(), blockName, function->raw); builder.CreateBr(blockInner); builder.SetInsertPoint(blockInner); queryContext->forceContext(scopeInnerId, {element}); scopeInnerUnit->reset(); result = scopeInnerUnit->compile(); } return result; } 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::Type* tyResultType = llvm->toLLVMType(llvm->ast->expandType(exprIf.type)); 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")); + llvm::PHINode *ret = builder.CreatePHI(tyResultType, 2, NAME("if")); ret->addIncoming(resultTrue, blockTrue); ret->addIncoming(resultFalse, blockFalse); return ret; } -//TODO implement switch llvm::Value* Instructions::compileSwitch(const Expression& exprSwitch, const std::string& hintRetVar){ EXPAND_CONTEXT UNUSED(scope); UNUSED(function); assert(exprSwitch.operands.size() >= 2); assert(exprSwitch.operands[1].op == Operator::CASE_DEFAULT); int countCases = exprSwitch.operands.size()-1; llvm::IRBuilder<>& builder = llvm->builder; llvm::BasicBlock* blockProlog = builder.GetInsertBlock(); llvm::BasicBlock *blockEpilog = llvm::BasicBlock::Create(llvm::getGlobalContext(), "switchAfter", function->raw); builder.SetInsertPoint(blockEpilog); llvm::Type* exprSwitchType = llvm->toLLVMType(ExpandedType(exprSwitch.type)); llvm::PHINode *ret = builder.CreatePHI(exprSwitchType, countCases, NAME("switch")); builder.SetInsertPoint(blockProlog); llvm::Value * conditionSwitch = scope->process(exprSwitch.operands[0]); llvm::BasicBlock *blockDefault = llvm::BasicBlock::Create(llvm::getGlobalContext(), "caseDefault", function->raw); llvm::SwitchInst * instructionSwitch = builder.CreateSwitch(conditionSwitch, blockDefault, countCases); for (int size = exprSwitch.operands.size(), i=2; iraw); llvm::Value* condCase = function->getScopeUnit(exprSwitch.operands[i].blocks.front())->compile(); builder.SetInsertPoint(blockCase); llvm::Value* resultCase = function->getScopeUnit(exprSwitch.operands[i].blocks.back())->compile(); builder.CreateBr(blockEpilog); ret->addIncoming(resultCase, builder.GetInsertBlock()); builder.SetInsertPoint(blockProlog); instructionSwitch->addCase(dyn_cast(condCase), blockCase); } //compile default block: builder.SetInsertPoint(blockDefault); CodeScope* scopeDefault = exprSwitch.operands[1].blocks.front(); llvm::Value* resultDefault = function->getScopeUnit(scopeDefault)->compile(); builder.CreateBr(blockEpilog); ret->addIncoming(resultDefault, builder.GetInsertBlock()); builder.SetInsertPoint(blockEpilog); return ret; } llvm::Value* Instructions::compileConstantArray(const Expression &expr, const std::string& hintRetVar) { EXPAND_CONTEXT UNUSED(scope); UNUSED(function); const size_t& __size = expr.getOperands().size(); const Expression& __data = expr; ArrayType* typList = (ArrayType*) (llvm->toLLVMType(ExpandedType(TypeAnnotation(tag_array, TypePrimitive::I32, __size)))); Type*typI32 = llvm->toLLVMType(ExpandedType(TypeAnnotation(TypePrimitive::I32))); std::vector list; list.reserve(__size); const std::vector operands = __data.getOperands(); std::transform(operands.begin(), operands.end(), std::inserter(list, list.begin()), [typI32](const Expression& e){return ConstantInt::get(typI32, e.getValueDouble());}); Value* listSource = ConstantArray::get(typList, ArrayRef(list)); /* Value* listDest = l.builder.CreateAlloca(typList, ConstantInt::get(typI32, __size), *hintRetVar); l.buil1der.CreateMemCpy(listDest, listSource, __size, 16); */ return listSource; } llvm::Value* Instructions::compileConstantStringAsPChar(const string& data, const std::string& hintRetVar) { EXPAND_CONTEXT UNUSED(function); UNUSED(scope); 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; //TODO is used somewhere? + compilation::CodeScopeUnit* sourceUnit; + compilation::FunctionUnit* function; //TODO is used somewhere? const Expression& sourceDecl; - CompilePass::Context context; + compilation::Context context; llvm::Type* sourceRawType =nullptr; public: - IteratorForward(CompilePass::Context ctx, const xreate::Symbol& s, const ImplementationRec& implementation) - : llvm(ctx.pass->man->llvm), current(s), source(implementation.source), linkedlist(source), sourceScope(source.scope), sourceUnit(new CompilePass::CodeScopeUnit(source.scope, ctx.function, ctx.pass)), + IteratorForward(compilation::Context ctx, const xreate::Symbol& s, const ImplementationRec& implementation) + : llvm(ctx.pass->man->llvm), current(s), source(implementation.source), linkedlist(source), sourceScope(source.scope), sourceUnit(new compilation::CodeScopeUnit(source.scope, ctx.function, ctx.pass)), sourceDecl(CodeScope::findDeclaration(source)), context(ctx) { } llvm::Value* begin() { switch(sourceDecl.op) { case xreate::Operator::LIST: { sourceRawType = Type::getInt32Ty(llvm::getGlobalContext()); return ConstantInt::get(Type::getInt32Ty(llvm::getGlobalContext()), 0); }; case xreate::Operator::LIST_RANGE:{ assert(sourceDecl.operands.size()==2); llvm::Value* result = sourceUnit->process(sourceDecl.operands.at(0)); sourceRawType = result->getType(); return result; }; default: break; } if (linkedlist){ llvm::Value* result = sourceUnit->process(sourceDecl); sourceRawType = result->getType(); return result; } assert(false); } llvm::Value* end(){ switch(sourceDecl.op) { case xreate::Operator::LIST: { size_t idLast = sourceDecl.operands.size() - 1; return ConstantInt::get(sourceRawType, idLast); } case xreate::Operator::LIST_RANGE: { assert(sourceDecl.operands.size() == 2); return sourceUnit->process(sourceDecl.operands.at(1)); }; default: break; } //return null pointer if (linkedlist){ return ConstantPointerNull::getNullValue(sourceRawType); } assert(false && "Unknown declaration"); return nullptr; } llvm::Value* get(Value* index,const std::string& hintRetVar="") override{ const Expression& currentDecl = CodeScope::findDeclaration(current); switch (currentDecl.op) { case xreate::Operator::LIST: { //TODO re check is it right scope(source) to compilation currentDecl. Write unittests for this. //llvm::Value* currentValue = sourceUnit->process(currentDecl); return Instructions(context).compileArrayIndex(current, vector{index}); }; case xreate::Operator::LIST_RANGE: { return index; }; case xreate::Operator::MAP: { assert(currentDecl.getOperands().size()==1); assert(currentDecl.bindings.size()); assert(currentDecl.blocks.size()); CodeScope* scopeLoop = currentDecl.blocks.front(); const std::string& varIn = currentDecl.getOperands()[0].getValueString(); std::string varEl = currentDecl.bindings[0]; const Symbol& symbIn = current.scope->findSymbol(varIn); auto it = std::unique_ptr(Iterator::create(context, symbIn)); Value* elIn = it->get(index, varEl); - CompilePass::CodeScopeUnit* unitLoop = function->getScopeUnit(scopeLoop); + compilation::CodeScopeUnit* unitLoop = function->getScopeUnit(scopeLoop); unitLoop->bindArg(elIn, std::move(varEl)); return unitLoop->compile(); } case xreate::Operator::NONE: { assert(currentDecl.__state==Expression::IDENT); const Symbol& symbIn = current.scope->findSymbol(currentDecl.getValueString()); auto it = std::unique_ptr(Iterator::create(context, symbIn)); return it->get(index); }; default: break; } if (linkedlist){ return index; } assert(false && "Unknown declaration"); return nullptr; } llvm::Value* move(Value* index, const std::string& hintRetVar) override{ switch(sourceDecl.op) { case xreate::Operator::LIST: case xreate::Operator::LIST_RANGE: return llvm->builder.CreateAdd(index, llvm::ConstantInt::get(llvm::Type::getInt32Ty(llvm::getGlobalContext()), 1), hintRetVar); default: break; } if (linkedlist){ ExpandedType tySource = llvm->ast->expandType(sourceScope->findDefinition(source)); assert(tySource->__operator == TypeOperator::ARRAY && "Linked list implementation has to have ARRAY type"); assert(tySource->__operands.size()); return Instructions(context).compileStructIndex(index, ExpandedType(TypeAnnotation(tySource->__operands.at(0))), linkedlist.fieldPointer); } assert(false && "Unknown declaration"); return nullptr; } }; Iterator* -Iterator::create(CompilePass::Context context, const Symbol& var){ +Iterator::create(compilation::Context context, const Symbol& var){ const Implementation& data = Query::queryImplementation(var); switch(data.impl){ case ON_THE_FLY: return new IteratorForward(context, var, data.extract()); default: assert(true); } assert(false && "Unknown declaration"); return nullptr; } diff --git a/cpp/src/compilation/instr-containers.h b/cpp/src/compilation/instr-containers.h index 5651085..9fe4a08 100644 --- a/cpp/src/compilation/instr-containers.h +++ b/cpp/src/compilation/instr-containers.h @@ -1,87 +1,87 @@ #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); + static Iterator* create(compilation::Context context, const Symbol& var); }; class Instructions { public: - Instructions(CompilePass::Context ctx); + Instructions(compilation::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* compileLoopContext(const Expression& expression, const std::string& hintRetVar); 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; + compilation::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/compilation/latecontext.cpp b/cpp/src/compilation/latecontextcompiler.cpp similarity index 55% rename from cpp/src/compilation/latecontext.cpp rename to cpp/src/compilation/latecontextcompiler.cpp index 9269b4a..418b655 100644 --- a/cpp/src/compilation/latecontext.cpp +++ b/cpp/src/compilation/latecontextcompiler.cpp @@ -1,151 +1,136 @@ /* * LateContext.cpp * * Created on: Jan 8, 2016 * Author: pgess */ -#include "pass/compilepass.h" -#include "compilation/latecontext.h" #include "query/context.h" +#include +#include "pass/compilepass.h" #include "llvmlayer.h" namespace xreate { -LateContext::LateContext(const std::string& function, CompilePass* compilePass) - : pass(compilePass), domain(&compilePass->queryContext->getFunctionDomain(function)) +LateContextCompiler::LateContextCompiler(const std::string& function, CompilePass* compilePass) + : pass(compilePass) {} -LateContext::~LateContext() +LateContextCompiler::~LateContextCompiler() {} llvm::Value* -LateContext::compileCheckContext(const Expression& e){ +LateContextCompiler::compileCheckContext(const Expression& e){ // llvm::Value* environment; // LLVMLayer* llvm; // // PackedExpression rep = __context.pack(e); // assert(storage.count(rep)); // // size_t id = storage.at(rep); // //TODO determine short name of expression // return llvm->builder.CreateExtractElement(environment, id, NAME("checkContext"+e.getValueString())); return nullptr; } - + llvm::Value* -LateContext::findFunction(const std::string name, ScopePacked scopeOuter, llvm::Function* functionOuter){ - LLVMLayer* llvm = pass->man->llvm; - ContextQuery* queryContext = pass->queryContext; - const FunctionSpecializations& specializations = queryContext->getFunctionSpecializations(name); - - //check external function - if (!specializations.size()){ - return nullptr; - } - - const std::list& context = queryContext->getContext(scopeOuter); - - boost::optional variant; - for(const Expression& c: context){ - if (specializations.count(c)){ - assert(!variant); - variant = specializations.at(c); - } - } - - if (variant) { - return pass->getFunctionUnit(*variant)->compile();// RETURN compiled function unit - } - - //require default variant if no appropriate static context exists - assert(specializations.count(Expression())); - llvm::Value* funcDefault = pass->getFunctionUnit(specializations.at(Expression()))->compile(); - - //choose default variant if no late context exists - if (!domain->size()) { - return funcDefault; - } - - //RUNTIME PART +LateContextCompiler::findFunction(const std::string name, ScopePacked scopeOuter, llvm::Function* functionOuter){ +/* + * , functionDomain(&compilePass->queryContext->getFunctionDomain(function)) + //RUNTIME PART llvm::BasicBlock *blockCurrent = llvm->builder.GetInsertBlock(); llvm::BasicBlock *blockEnd = llvm::BasicBlock::Create(llvm::getGlobalContext(), "ContextDeterminationEnd", functionOuter); llvm->builder.SetInsertPoint(blockEnd); llvm::Type* tyFuncCallee = funcDefault->getType(); - llvm::PHINode *ret = llvm->builder.CreatePHI(tyFuncCallee, domain->size(), "callee"); + llvm::PHINode *ret = llvm->builder.CreatePHI(tyFuncCallee, functionDomain->size(), "callee"); //check runtime context - for (const Expression& c: *domain){ - if (specializations.count(c)){ - ///if (domain[c]) return specialization.at(c) else + for (const ManagedFnPtr& f: specializations){ + const Expression& guard = f->guardContext; + if (!guard.isValid()) continue; + + if (functionDomain->count(guard)){ + ///example: if (domain[c]) return specializtion.at(c) else llvm->builder.SetInsertPoint(blockCurrent); + //TASK implement `cond` llvm::Value* cond; llvm::BasicBlock *blockNext = llvm::BasicBlock::Create(llvm::getGlobalContext(), "ContextDeterminationNext", functionOuter); llvm->builder.CreateCondBr(cond, blockEnd, blockNext); - ret->addIncoming(pass->getFunctionUnit(specializations.at(c))->compile(), blockCurrent); + ret->addIncoming(pass->getFunctionUnit(f)->compile(), blockCurrent); blockCurrent = blockNext; } } //check default variant in runtime llvm->builder.SetInsertPoint(blockCurrent); llvm->builder.CreateBr(blockEnd); ret->addIncoming(funcDefault, blockCurrent); llvm->builder.SetInsertPoint(blockEnd); return ret; + + */ return nullptr; } llvm::Value* -LateContext::compileArgument(const std::string& callee, ScopePacked scopeOuter){ +LateContextCompiler::compileArgument(const std::string& callee, ScopePacked scopeOuter){ + /* LLVMLayer* llvm = pass->man->llvm; std::unordered_set indexContextStatic; - list listContextStatic = pass->queryContext->getContext(scopeOuter); - const ContextDomain* calleeDomain = &pass->queryContext->getFunctionDomain(callee); + const ContextDomain& listContextStatic = pass->queryContext->getContext(scopeOuter); + const ContextDomain& calleeDomain = pass->queryContext->getFunctionDomain(callee); llvm::Type* tyBool = llvm::Type::getInt1Ty(llvm::getGlobalContext()); llvm::Type* tyInt32 = llvm::Type::getInt32Ty(llvm::getGlobalContext()); - llvm::Value* result = llvm->builder.CreateAlloca(tyBool, llvm::ConstantInt::get(tyInt32, calleeDomain->size())); + llvm::Value* result = llvm->builder.CreateAlloca(tyBool, llvm::ConstantInt::get(tyInt32, calleeDomain.size())); llvm::Value* valueTrue = llvm::ConstantInt::get(tyBool, 1); llvm::Value* valueFalse = llvm::ConstantInt::get(tyBool, 0); for (const Expression& e: listContextStatic){ - auto i = calleeDomain->getExpressionId(e); + auto i = calleeDomain.getId(e); //TODO it is like iteration 0..size-1, right? if (i){ result = llvm->builder.CreateInsertElement(result, llvm::ConstantInt::get(tyInt32, *i), valueTrue); indexContextStatic.insert(*i); } } - for (size_t i=0, size=calleeDomain->size(); iget(i); + for (size_t i=0, size=calleeDomain.size(); igetExpressionId(e); + auto posPrev = functionDomain->getExpressionId(e); if (posPrev){ llvm::Value* element = llvm->builder.CreateExtractElement(raw, llvm::ConstantInt::get(tyInt32, *posPrev)); result = llvm->builder.CreateInsertElement(result, llvm::ConstantInt::get(tyInt32, i), element); continue; } result = llvm->builder.CreateInsertElement(result, llvm::ConstantInt::get(tyInt32, i), valueFalse); } return result; + */ + + return nullptr; +} + +size_t +LateContextCompiler::getFunctionDomainSize() const { + return pass->queryContext->getFunctionDomain(functionName).size(); } //void //LateContext::set(const Expression& e){ // PackedExpression representation = __context.pack(e); // // assert(__context.count(representation) == 0); // __context.emplace(move(representation), __context.size()); //} } /* namespace xreate */ diff --git a/cpp/src/compilation/latecontext.h b/cpp/src/compilation/latecontextcompiler.h similarity index 53% rename from cpp/src/compilation/latecontext.h rename to cpp/src/compilation/latecontextcompiler.h index 2ccfe41..e3f6a2e 100644 --- a/cpp/src/compilation/latecontext.h +++ b/cpp/src/compilation/latecontextcompiler.h @@ -1,43 +1,45 @@ /* * LateContext.h * * Created on: Jan 8, 2016 * Author: pgess */ -#ifndef SRC_COMPILATION_LATECONTEXT_H_ -#define SRC_COMPILATION_LATECONTEXT_H_ +#ifndef SRC_COMPILATION_LATECONTEXTCOMPILER_H_ +#define SRC_COMPILATION_LATECONTEXTCOMPILER_H_ #include "ast.h" -#include "expressionserializer.h" namespace llvm { class Value; + class Function; } namespace xreate { typedef unsigned int ScopePacked; class CompilePass; -class ContextDomain; -class LateContext{ +//SECTIONTAG late-context compilation logic wrt late context + +class LateContextCompiler{ public: - LateContext(const std::string& function, CompilePass* compilePass); - ~LateContext(); + LateContextCompiler(const std::string& function, CompilePass* compilePass); + ~LateContextCompiler(); llvm::Value* compileCheckContext(const Expression& e); llvm::Value* compileArgument(const std::string& callee, ScopePacked scopeOuter); llvm::Value* findFunction(const std::string name, ScopePacked scopeOuter, llvm::Function* functionOuter); + size_t getFunctionDomainSize() const; - const ContextDomain* const domain; - llvm::Value* raw; + llvm::Value* raw = nullptr; private: + std::string functionName; CompilePass* pass; }; } /* namespace xreate */ -#endif /* SRC_COMPILATION_LATECONTEXT_H_ */ +#endif /* SRC_COMPILATION_LATECONTEXTCOMPILER_H_ */ diff --git a/cpp/src/compilation/latecontextcompiler2.cpp b/cpp/src/compilation/latecontextcompiler2.cpp new file mode 100644 index 0000000..5dccbc0 --- /dev/null +++ b/cpp/src/compilation/latecontextcompiler2.cpp @@ -0,0 +1,119 @@ +/* + * LateContextCompiler2.cpp + * + * Created on: 10 февр. 2016 + * Author: pgess + */ + +#include "latecontextcompiler2.h" +#include "llvmlayer.h" +#include "pass/compilepass.h" +#include "query/context.h" +#include + +namespace xreate { + +LateContextCompiler2::LateContextCompiler2(compilation::FunctionUnit* f, CompilePass* p) + : function(f), pass(p){} + +//TEST default variants - do not enable specialization context in order to check default variant invocation +llvm::Value* +LateContextCompiler2::findFunction(const std::string& calleeName, llvm::Function* specializationDefault){ + LLVMLayer* llvm = pass->man->llvm; + llvm::IRBuilder<>& builder = llvm->builder; + ContextQuery* context = pass->queryContext; + const string& functionName = function->function->getName(); + + const std::list& specializations = pass->man->root->getFunctionVariants(calleeName); + const FunctionContextDemand& decisions = context->getFunctionDemand(functionName); + + assert(decisions.right.count(calleeName) && "Can't determine specialization of the function"); + size_t decisionIndex = decisions.right.at(calleeName); + const ContextDomain& decisionDomain= context->getFunctionDomain(calleeName); + + llvm::IntegerType* ty32 = llvm::Type::getInt32Ty(llvm::getGlobalContext()); + llvm::Type* tyCallee = specializationDefault->getType(); + + llvm::BasicBlock* blockDefault = llvm::BasicBlock::Create(llvm::getGlobalContext(), "caseDefault", this->function->raw); + + llvm::Value* decisionRaw = builder.CreateExtractValue(this->raw, llvm::ArrayRef{decisionIndex}); + llvm::SwitchInst* instrSwitch = builder.CreateSwitch(decisionRaw, blockDefault, decisionDomain.size()); + + llvm::BasicBlock *blockEpilog = llvm::BasicBlock::Create(llvm::getGlobalContext(), "ContextDeterminationEnd", this->function->raw); + builder.SetInsertPoint(blockEpilog); + llvm::PHINode *ret = llvm->builder.CreatePHI(tyCallee, decisionDomain.size(), "callee"); + + for (const ManagedFnPtr& f: specializations){ + if (!f->guardContext.isValid()) continue; + const Code& specCode = decisionDomain.getId(f->guardContext); + llvm::ConstantInt* rawSpecCode = llvm::ConstantInt::get(ty32, specCode); + + llvm::BasicBlock* blockCase = llvm::BasicBlock::Create(llvm::getGlobalContext(), "case+" + f->guardContext.getValueString(), this->function->raw); + builder.SetInsertPoint(blockCase); + builder.CreateBr(blockEpilog); + ret->addIncoming(pass->getFunctionUnit(f)->compile(), blockCase); + + instrSwitch->addCase(rawSpecCode, blockCase); + } + + //prepare default specialization + builder.SetInsertPoint(blockDefault); + builder.CreateBr(blockEpilog); + ret->addIncoming(specializationDefault, blockDefault); + + builder.SetInsertPoint(blockEpilog); + return ret; +} + +llvm::Value* +LateContextCompiler2::compileArgument(const std::string& callee, ScopePacked scopeOuter){ + llvm::IRBuilder<>& builder = pass->man->llvm->builder; + ContextQuery* context = pass->queryContext; + const string& functionName = function->function->getName(); + const map& dictStaticDecisions = context->getStaticDecisions(scopeOuter); + + const FunctionContextDemand& decisionsCallee = context->getFunctionDemand(callee); + const FunctionContextDemand& decisionsSelf = context->getFunctionDemand(functionName); + + llvm::IntegerType* ty32 = llvm::Type::getInt32Ty(llvm::getGlobalContext()); + llvm::Type* tyDemand = llvm::ArrayType::get(ty32, decisionsCallee.size()); + + //builder.CreateAlloca(tyDemand, llvm::ConstantInt::get(ty32, 1)); + llvm::Value* res = llvm::ConstantArray::getNullValue(tyDemand); + + for (size_t i=0, size = decisionsCallee.size(); igetFunctionDomain(key); + const Code& decisionCode = dom.getId(decision); + + res = builder.CreateInsertValue(res, llvm::ConstantInt::get(ty32, decisionCode), llvm::ArrayRef{i}); + continue; + } + + //TEST decision propagtion + const size_t& decisionIndex = decisionsSelf.right.at(key); + llvm::Value* decision = builder.CreateExtractValue(this->raw, llvm::ArrayRef{decisionIndex}); + res = builder.CreateInsertElement(res, llvm::ConstantInt::get(ty32, i), decision); + } + + return res; +} + +size_t +LateContextCompiler2::getFunctionVariantsSize() const { + ContextQuery* context = pass->queryContext; + + return context->getFunctionDomain(function->function->getName()).size(); +} + +size_t +LateContextCompiler2::getFunctionDemandSize() const { + ContextQuery* context = pass->queryContext; + + return context->getFunctionDemand(function->function->getName()).size(); +} + +} /* namespace xreate */ diff --git a/cpp/src/compilation/latecontextcompiler2.h b/cpp/src/compilation/latecontextcompiler2.h new file mode 100644 index 0000000..4ef802a --- /dev/null +++ b/cpp/src/compilation/latecontextcompiler2.h @@ -0,0 +1,50 @@ +/* + * LateContextCompiler2.h + * + * Created on: 10 февр. 2016 + * Author: pgess + */ + +#ifndef LATECONTEXTCOMPILER2_H_ +#define LATECONTEXTCOMPILER2_H_ + +#include "serialization.h" + +namespace llvm { + class Value; + class Function; +} + +namespace xreate { + class CompilePass; + +namespace compilation { + class FunctionUnit; +}} + +namespace xreate { + +typedef unsigned int ScopePacked; +class LateContextCompiler2 { +public: + llvm::Value* raw = nullptr; + + LateContextCompiler2(compilation::FunctionUnit* f, CompilePass* p); + llvm::Value* findFunction(const std::string& calleeName, llvm::Function* specializationDefault); + llvm::Value* compileArgument(const std::string& callee, ScopePacked scopeOuter); + size_t getFunctionVariantsSize() const; + size_t getFunctionDemandSize() const; + +private: + typedef ExpressionSerialization::Code Code; + typedef ExpressionSerialization::Serializer Domain; + //boost::bimap __decisions; + //std::vector __scheme; + + compilation::FunctionUnit* function; + CompilePass* pass; +}; + +} /* namespace xreate */ + +#endif /* LATECONTEXTCOMPILER2_H_ */ diff --git a/cpp/src/contextrule.cpp b/cpp/src/contextrule.cpp index cea1272..6ae4fc4 100644 --- a/cpp/src/contextrule.cpp +++ b/cpp/src/contextrule.cpp @@ -1,52 +1,52 @@ /* * contextrule.cpp * * Created on: Jan 2, 2016 * Author: pgess */ #include "contextrule.h" #include "clasplayer.h" #include using namespace xreate; using namespace std; ContextRule::ContextRule(const Expression& rule) { assert(rule.op == Operator::CONTEXT_RULE); assert(rule.operands.size() == 3); head = rule.operands.at(0); guards = rule.operands.at(1); body = rule.operands.at(2); } std::string ContextRule::compile(const ScopePacked& scopeId) const{ const string prolog = " %context rule visibility implemenetation\n" - " context_rule_visibility(X, Y) :- X=Y, scope(X), scope(Y).\n" - " context_rule_visibility(X, Y) :- cfa_parent(X, scope(Y)), scope(X), scope(Y)."; + "context_rule_visibility(X, Y) :- X=Y, scope(X), scope(Y).\n" + "context_rule_visibility(X, Y) :- cfa_parent(X, scope(Y)), scope(X), scope(Y).\n"; listrepHead_ = ClaspLayer::compile(head); assert(repHead_.size() == 1); listrepGuards_ = ClaspLayer::compile(guards); assert(repGuards_.size() == 1); listrepBody_ = ClaspLayer::compile(body); assert(repBody_.size() == 1); const std::string& atomBindingScope = Config::get("clasp.bindings.scope"); boost::format formatContextVisibility("context_rule_visibility(ScopeX, %1%)"); boost::format formatScopeBind(atomBindingScope + "(ScopeX, %1%)"); const string& repHead = str(formatScopeBind % repHead_.front()); const string& repGuards = str(formatScopeBind % repGuards_.front()); const string& repVisibility = str(formatContextVisibility % scopeId); boost::format formatRule("%1%:- %2%, %3%, %4%."); return prolog + str(formatRule % repHead % repGuards % repBody_.front() % repVisibility); } diff --git a/cpp/src/expressionserializer.h b/cpp/src/expressionserializer.h deleted file mode 100644 index 910fca9..0000000 --- a/cpp/src/expressionserializer.h +++ /dev/null @@ -1,56 +0,0 @@ -/* - * expressionserializer.h - * - * Created on: Jan 4, 2016 - * Author: pgess - */ - -#ifndef SRC_EXPRESSIONSERIALIZER_H_ -#define SRC_EXPRESSIONSERIALIZER_H_ - -#include "ast.h" -#include -#include - -namespace xreate { - -struct PackedExpression{ - PackedExpression(){}; - PackedExpression(PackedExpression&& other); - ~PackedExpression(); - void operator<< (const std::pair& value); - char* operator*(){return __storage;} - bool operator==(const PackedExpression& other) const; - bool operator!=(const PackedExpression& other) const; - bool operator<(const PackedExpression& other) const; - private: - PackedExpression (const PackedExpression&)=delete; - PackedExpression& operator=(const PackedExpression&)=delete; - PackedExpression& operator=(PackedExpression&&)=delete; - - char* __storage = nullptr; - size_t size =0; - unsigned char countRemainedBits =0; -}; -typedef boost::optional OptionalPackedExpression; - -class ExpressionSerializerPrivate; - -class ExpressionSerializer { -public: - ExpressionSerializer(); - ~ExpressionSerializer(); - ExpressionSerializer(ExpressionSerializer&& other) - : strategy(other.strategy), registry(std::move(other.registry)) {} - void registerExpression(const Expression&e); - PackedExpression pack(const Expression& e); - OptionalPackedExpression packOptional(const Expression& e) const; - -private: - ExpressionSerializerPrivate* strategy; - std::map registry; -}; - -} /* namespace xreate */ - -#endif /* SRC_EXPRESSIONSERIALIZER_H_ */ diff --git a/cpp/src/pass/adhocpass.cpp b/cpp/src/pass/adhocpass.cpp index 61173cf..8473a79 100644 --- a/cpp/src/pass/adhocpass.cpp +++ b/cpp/src/pass/adhocpass.cpp @@ -1,80 +1,81 @@ /* * adhoc.cpp * * Created on: Nov 28, 2015 * Author: pgess */ #include "pass/adhocpass.h" #include "query/context.h" namespace xreate { AdhocScheme* AdhocPass::determineForScope(CodeScope* entry){ - std::list contextStack = queryContext->getContext(man->clasp->pack(entry)); + const ScopePacked scopeId = man->clasp->pack(entry); + const ContextDomain& domain = queryContext->getContext(scopeId); AdhocScheme* scheme = nullptr; - for (const Expression& context: contextStack){ + for (const Expression& context: domain){ if (context.__state != Expression::IDENT) continue; if (__schemes.count(context.getValueString())){ assert(!scheme && "ambiguous context"); scheme = __schemes.at(context.getValueString()); } } assert(scheme && "Appropriate context not found"); return scheme; } const TypeAnnotation& AdhocScheme::getResultType(){ return __resultType; } CodeScope* AdhocScheme::getImplementationForCommand(const std::string& comm) { assert(__commands.count(comm) && "Adhoc not defined"); return __commands.at(comm); } AdhocScheme::AdhocScheme(const Expression& scheme): __resultType(scheme.type), __context(scheme.getValueString()) { Expression cases = scheme.getOperands()[0]; for (const Expression& exprCase: cases.getOperands()){ CodeScope* blockComm = exprCase.blocks.front(); std::string nameCase = blockComm->__body.operands[0].getValueString(); CodeScope* blockImpl = *(++exprCase.blocks.begin()); __commands.emplace(nameCase, blockImpl); } } const std::string& AdhocScheme::getContext(){ return __context; } /* void AdhocPass::process(const Expression& expression, PassContext context, const std::string& varDecl=""){ if (expression == Exp) } */ void AdhocPass::run(){ queryContext = reinterpret_cast(man->clasp->registerQuery(new ContextQuery(), QueryId::ContextQuery)); auto range = man->root->__interfacesData.equal_range(ASTInterface::Adhoc); for (auto i=range.first; i!= range.second; ++i){ AdhocScheme* scheme = new AdhocScheme(i->second); __schemes.emplace(scheme->getContext(), scheme); } } } diff --git a/cpp/src/pass/cfgpass.cpp b/cpp/src/pass/cfgpass.cpp index 84c62b3..120b80d 100644 --- a/cpp/src/pass/cfgpass.cpp +++ b/cpp/src/pass/cfgpass.cpp @@ -1,90 +1,98 @@ #include "cfgpass.h" #include using namespace std; using namespace xreate; void 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->setCFAData(move(__context.graph)); return AbstractPass::finish(); } void CFGPass::processFnCall(ManagedFnPtr function, PassContext context) { ClaspLayer* clasp = man->clasp; __context.graph.addCallConnection(clasp->pack(context.scope), function->getName()); return AbstractPass::processFnCall(function, context); } +void +CFGPass::processFnCallUncertain(ManagedFnPtr function, PassContext context){ + ClaspLayer* clasp = man->clasp; + __context.graph.addCallConnection(clasp->pack(context.scope), function->getName()); + + return AbstractPass::processFnCallUncertain(function, context); +} + void CFGPass::process(CodeScope* scope, PassContext context, const std::string& hintBlockDecl){ ClaspLayer* clasp = man->clasp; CodeScope* scopeParent = context.scope; ScopePacked scopeId = clasp->pack(scope); if (scopeParent){ __context.graph.addParentConnection(scopeId, clasp->pack(scopeParent)); } else { __context.graph.addParentConnection(scopeId, context.function->getName()); } //TEST scope annotations //SECTIONTAG context gather scope annotations __context.graph.addScopeAnnotations(scopeId, scope->tags); __context.graph.addContextRules(scopeId, scope->contextRules); return AbstractPass::process(scope, context, hintBlockDecl); } //TEST scope annotations via scheme 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.addScopeAnnotations(clasp->pack(expression.blocks.front()), scheme.second.getOperands()); } } } return AbstractPass::process(expression, context, varDecl); } void CFGPass::process(ManagedFnPtr function) { __context.graph.addFunctionAnnotations(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 c68ba2f..8640f20 100644 --- a/cpp/src/pass/cfgpass.h +++ b/cpp/src/pass/cfgpass.h @@ -1,33 +1,34 @@ // 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 AbstractPass { public: void process(ManagedFnPtr function) override; void processFnCall(ManagedFnPtr function, PassContext context) override; + void processFnCallUncertain(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 finish() override; void run() override; private: struct { 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 4466ae2..84e1cb5 100644 --- a/cpp/src/pass/compilepass.cpp +++ b/cpp/src/pass/compilepass.cpp @@ -1,550 +1,654 @@ #include "compilepass.h" #include "clasplayer.h" +#include "llvmlayer.h" #include -#include + #include "query/containers.h" #include "query/context.h" #include "compilation/instr-containers.h" #include "ExternLayer.h" #include "pass/adhocpass.h" #include +#include +#include using namespace std; using namespace xreate; +using namespace xreate::compilation; using namespace llvm; //SECTIONTAG types/convert implementation llvm::Value* doAutomaticTypeConversion(llvm::Value* source, llvm::Type* tyTarget, LLVMLayer* 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); } } return source; } -CompilePass::CodeScopeUnit::CodeScopeUnit(CodeScope* codeScope, FunctionUnit* f, CompilePass* 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; -} +namespace xreate { -//SECTIONTAG context-based function specialization -CompilePass::FunctionUnit* -CompilePass::CodeScopeUnit::findFunctionUnit(const std::string f){ - AST* ast = pass->man->root; +class CallStatement { +public: + virtual llvm::Value* operator() (std::vector&& args, const std::string& hintDecl, llvm::IRBuilder<>&) = 0; +}; - const ScopePacked& scopeId = pass->man->clasp->pack(scope); +class CallStatementRaw: public CallStatement{ +public: + CallStatementRaw(llvm::Value* callee): __callee(callee) {} - const std::list& context = pass->queryContext->getContext(scopeId); - std::unordered_set contextIndex; - for (const Expression& c: context){ - if (c.__state != Expression::IDENT) continue; - contextIndex.insert(c.getValueString()); + llvm::Value* operator() (std::vector&& args, const std::string& hintDecl, llvm::IRBuilder<>& builder) { + return builder.CreateCall(__callee, args, hintDecl); } - ManagedFnPtr function = pass->man->root->findFunctionVariant(f, FunctionSpecializationQuery{contextIndex}); - if (!function.isValid()) return nullptr; +private: + llvm::Value* __callee; +}; + +class CallStatementInline: public CallStatement{ +public: + CallStatementInline(FunctionUnit* caller, FunctionUnit* callee) + : __caller(caller), __callee(callee) {} + + llvm::Value* operator() (std::vector&& args, const std::string& hintDecl, llvm::IRBuilder<>& builder) { + //TEST inlining + return __callee->compileInline(move(args), __caller); + } + +private: + FunctionUnit* __caller; + FunctionUnit* __callee; +}; - return pass->getFunctionUnit(function); +} + +//SECTIONTAG late-context find callee function +//TEST static late context decisions +//TEST dynamic late context decisions +CallStatement* +CodeScopeUnit::findFunction(const std::string& calleeName){ + LLVMLayer* llvm = pass->man->llvm; + ClaspLayer* clasp = pass->man->clasp; + + ContextQuery* queryContext = pass->queryContext; + + const std::list& specializations = pass->man->root->getFunctionVariants(calleeName); + + //check external function + if (!specializations.size()){ + llvm::Function* external = pass->man->llvm->layerExtern->lookupFunction(calleeName); + + return new CallStatementRaw(external); + } + + //no decisions required + if (specializations.size()==1){ + if (!specializations.front()->guardContext.isValid()) { + return new CallStatementRaw( pass->getFunctionUnit(specializations.front())->compile()); + } + } + + //prepare specializations dictionary + typedef ExpressionSerialization<>::Serializer Serializer; + typedef ExpressionSerialization<>::Code Code; + + auto adapter = [](const ManagedFnPtr& p){ return p->guardContext; }; + Serializer serializer(specializations, adapter); + + std::map dictSpecializations; + boost::optional variantDefault; + boost::optional variant; + + for(const ManagedFnPtr& f: specializations){ + const Expression& guard = f->guardContext; + + //default case: + if (!guard.isValid()){ + variantDefault = f; + continue; + } + + assert(dictSpecializations.emplace(serializer.getId(guard), f).second && "Found several appropriate specializations"); + } + + //check static context + const ScopeContextDecisions& decisions = queryContext->getStaticDecisions(clasp->pack(this->scope)); + if (decisions.count(calleeName)){ + variant = dictSpecializations.at(serializer.getId(decisions.at(calleeName))); + } + + size_t sizeDemand = this->function->contextCompiler.getFunctionDemandSize(); + + //decision made if static context found or no late context exists(and there is default variant) + bool flagHasStaticDecision = variant || (variantDefault && !sizeDemand); + + //if no late context exists + if (flagHasStaticDecision) { + FunctionUnit* calleeUnit = pass->getFunctionUnit(variant? *variant: *variantDefault); + + //inlining possible based on static decision only + if (calleeUnit->isInline()) { + return new CallStatementInline(function, calleeUnit); + } + + return new CallStatementRaw(calleeUnit->compile()); + } + + //require default variant if no static decision made + assert(variantDefault); + + llvm::Function* functionVariantDefault = this->pass->getFunctionUnit(*variantDefault)->compile(); + return new CallStatementRaw(this->function->contextCompiler.findFunction(calleeName, functionVariantDefault)); +} + +void +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::process(const Expression& expr, const std::string& hintVarDecl){ -#define VARNAME(x) (hintVarDecl.empty()? x: hintVarDecl) +CodeScopeUnit::process(const Expression& expr, const std::string& hintVarDecl){ +#define DEFAULT(x) (hintVarDecl.empty()? x: hintVarDecl) llvm::Value *left; llvm::Value *right; LLVMLayer& l = *pass->man->llvm; containers::Instructions instructions = containers::Instructions({function, this, pass}); 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]); //SECTIONTAG types/convert binary operation right = doAutomaticTypeConversion(right, left->getType(), &l); break; default:; } switch (expr.op) { case Operator::ADD: - return l.builder.CreateAdd(left, right, VARNAME("tmp_add")); + return l.builder.CreateAdd(left, right, DEFAULT("tmp_add")); break; case Operator::SUB: - return l.builder.CreateSub(left, right, VARNAME("tmp_sub")); + return l.builder.CreateSub(left, right, DEFAULT("tmp_sub")); break; case Operator::MUL: - return l.builder.CreateMul(left, right, VARNAME("tmp_mul")); + return l.builder.CreateMul(left, right, DEFAULT("tmp_mul")); break; case Operator::DIV: - return l.builder.CreateSDiv(left, right, VARNAME("tmp_div")); + return l.builder.CreateSDiv(left, right, DEFAULT("tmp_div")); break; case Operator::EQU: left->dump(); right->dump(); - return l.builder.CreateICmpEQ(left, right, VARNAME("tmp_equ")); + return l.builder.CreateICmpEQ(left, right, DEFAULT("tmp_equ")); break; case Operator::LSS: - return l.builder.CreateICmpSLT(left, right, VARNAME("tmp_lss")); + return l.builder.CreateICmpSLT(left, right, DEFAULT("tmp_lss")); break; case Operator::GTR: - return l.builder.CreateICmpSGT(left, right, VARNAME("tmp_gtr")); + return l.builder.CreateICmpSGT(left, right, DEFAULT("tmp_gtr")); break; case Operator::NEG: left = process(expr.operands[0]); - return l.builder.CreateNeg(left, VARNAME("tmp_neg")); + return l.builder.CreateNeg(left, DEFAULT("tmp_neg")); break; case Operator::CALL: { assert(expr.__state == Expression::COMPOUND); - llvm::BasicBlock* blockCurrent = pass->man->llvm->builder.GetInsertBlock(); + std::string nameCallee = expr.getValueString(); + unique_ptr callee(findFunction(nameCallee)); - std::string fname = expr.getValueString(); + //prepare arguments std::vector args; args.reserve(expr.operands.size()); std::transform(expr.operands.begin(), expr.operands.end(), std::inserter(args, args.end()), [this](const Expression &operand) { return process(operand); } ); ScopePacked outerScopeId = pass->man->clasp->pack(this->scope); - llvm::Value* callee = this->function->lateContext.findFunction(fname, outerScopeId, function->raw); - - // external function - if (!callee) { - llvm::Function* external = pass->man->llvm->layerExtern->lookupFunction(fname); - return l.builder.CreateCall(external, args, hintVarDecl); - } //SECTIONTAG late-context propagation arg - size_t calleeDomSize = pass->queryContext->getFunctionDomain(fname).size(); - if (calleeDomSize){ - llvm::Value* argLateContext = function->lateContext.compileArgument(fname, outerScopeId); + size_t calleeDemandSize = pass->queryContext->getFunctionDemand(nameCallee).size(); + if (calleeDemandSize){ + llvm::Value* argLateContext = function->contextCompiler.compileArgument(nameCallee, outerScopeId); args.push_back(argLateContext); } - //TODO implement inline functions - /* - 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(blockCurrent); - return l.builder.CreateCall(callee, args, hintVarDecl); + return (*callee)(move(args), DEFAULT("res_"+nameCallee), l.builder); } case Operator::IF: { - return instructions.compileIf(expr, hintVarDecl); + return instructions.compileIf(expr, DEFAULT("tmp_if")); } case Operator::SWITCH: { - return instructions.compileSwitch(expr, hintVarDecl); + return instructions.compileSwitch(expr, DEFAULT("tmp_switch")); } case Operator::LOOP_CONTEXT: { - return instructions.compileLoopContext(expr, hintVarDecl); + return instructions.compileLoopContext(expr, DEFAULT("tmp_loop")); } case Operator::LOGIC_AND: { assert(expr.operands.size() == 1); return process (expr.operands[0]); } case Operator::LIST: { - return instructions.compileConstantArray(expr, hintVarDecl); + return instructions.compileConstantArray(expr, DEFAULT("tmp_list")); }; case Operator::LIST_RANGE: { assert(false); //no compilation phase for a range list // return InstructionList(this).compileConstantArray(expr, l, hintRetVar); }; case Operator::LIST_NAMED: { typedef Expanded ExpandedType; 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 (size_t 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")); + return instructions.compileMapSolid(expr, DEFAULT("map")); }; case Operator::FOLD: { - return instructions.compileFold(expr, VARNAME("fold")); + return instructions.compileFold(expr, DEFAULT("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)); + return instructions.compileArrayIndex(s, indexes, DEFAULT(string("el_") + ident)); }; default: assert(false); } }; //SECTIONTAG adhoc actual compilation case Operator::ADHOC: { assert(function->adhocImplementation && "Adhoc implementation not found"); string comm = expr.operands[0].getValueString(); CodeScope* scope = function->adhocImplementation->getImplementationForCommand(comm); CodeScopeUnit* unitScope = function->getScopeUnit(scope); return unitScope->compile(); }; + case Operator::SEQUENCE: { + assert (expr.getOperands().size()); + + llvm::Value* result; + for(const Expression &op: expr.getOperands()){ + result = process(op, ""); + } + + return result; + } + 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); + return instructions.compileConstantStringAsPChar(expr.getValueString(), DEFAULT("tmp_str")); }; case Expression::VARIANT: { const ExpandedType& typVariant = pass->man->root->expandType(expr.type); llvm::Type* typRaw = l.toLLVMType(typVariant); int value = expr.getValueDouble(); return llvm::ConstantInt::get(typRaw, value); } default: { break; } }; break; default: break; } assert(false); return 0; } llvm::Value* -CompilePass::CodeScopeUnit::compile(const std::string& hintBlockDecl){ +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) +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(){ +FunctionUnit::isInline(){ Symbol ret = Symbol{0, function->__entry}; bool flagOnTheFly = SymbolAttachments::get(ret, false); return flagOnTheFly; } llvm::Function* -CompilePass::FunctionUnit::compile(){ +FunctionUnit::compile(){ if (raw != nullptr) return raw; std::vector types; LLVMLayer* llvm = pass->man->llvm; + llvm::IRBuilder<>& builder = llvm->builder; CodeScope* entry = function->__entry; AST* ast = pass->man->root; + const string& functionName = ast->getFunctionVariants(function->__name).size() > 1? function->__name + std::to_string(function.id()) : function->__name; + std::transform(entry->__args.begin(), entry->__args.end(), std::inserter(types, types.end()), [this, llvm, ast, 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(ast->expandType(entry->__definitions.at(argid))); }); //SECTIONTAG late-context signature type - size_t sizeDom = lateContext.domain->size(); - if (sizeDom) { - llvm::Type* tyBool = llvm::Type::getInt1Ty(llvm::getGlobalContext()); - llvm::Type* tyDom = llvm::ArrayType::get(tyBool, sizeDom); - types.push_back(tyDom); + size_t sizeLateContextDemand = contextCompiler.getFunctionDemandSize(); + if (sizeLateContextDemand) { + llvm::Type* ty32 = llvm::Type::getInt32Ty(llvm::getGlobalContext()); + llvm::Type* tyDemand = llvm::ArrayType::get(ty32, sizeLateContextDemand); + types.push_back(tyDemand); } //SECTIONTAG adhoc func signature determination - llvm::Type* funcResultType; + llvm::Type* expectedResultType; if (function->isPrefunction){ AdhocPass* adhocpass = reinterpret_cast(pass->man->getPassById(PassId::AdhocPass)); adhocImplementation = adhocpass->determineForScope(entry); - funcResultType = llvm->toLLVMType(ast->expandType(adhocImplementation->getResultType())); + expectedResultType = llvm->toLLVMType(ast->expandType(adhocImplementation->getResultType())); } else { - funcResultType = llvm->toLLVMType(ast->expandType(entry->__definitions[0])); + expectedResultType = llvm->toLLVMType(ast->expandType(entry->__definitions[0])); } - llvm::FunctionType *ft = llvm::FunctionType::get(funcResultType, types, false); + llvm::FunctionType *ft = llvm::FunctionType::get(expectedResultType, types, false); - raw = llvm::cast(llvm->module->getOrInsertFunction(function->__name + std::to_string(function.id()), ft)); + raw = llvm::cast(llvm->module->getOrInsertFunction(functionName, 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; } - if (sizeDom){ + if (sizeLateContextDemand){ fargsI->setName("latecontext"); - lateContext.raw = fargsI; + contextCompiler.raw = fargsI; } const std::string&blockName = "entry"; + llvm::BasicBlock* blockCurrent = builder.GetInsertBlock(); + + llvm::Value* result = entryCompilation->compile(blockName); + assert(result); //SECTIONTAG types/convert function ret value - llvm->builder.CreateRet( - doAutomaticTypeConversion( - entryCompilation->compile(blockName), funcResultType, llvm)); + builder.CreateRet(doAutomaticTypeConversion(result, expectedResultType, llvm)); + + if (blockCurrent){ + builder.SetInsertPoint(blockCurrent); + } llvm->moveToGarbage(ft); return raw; } llvm::Value* -CompilePass::FunctionUnit::compileInline(std::vector &&args, CompilePass::FunctionUnit* outer){ - CodeScopeUnit* entryCompilation = outer->getScopeUnit(function->__entry); +FunctionUnit::compileInline(std::vector &&args, 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){ +CodeScopeUnit* +FunctionUnit::getScopeUnit(CodeScope* scope){ if (!scopes.count(scope)){ - CodeScopeUnit* unit = new CodeScopeUnit(scope, this, pass); + CodeScopeUnit* unit = new CodeScopeUnit(scope, this, pass); scopes.emplace(scope, std::unique_ptr(unit)); } return scopes.at(scope).get(); } -CompilePass::CodeScopeUnit* -CompilePass::FunctionUnit::getEntry(){ +CodeScopeUnit* +FunctionUnit::getEntry(){ return getScopeUnit(function->getEntryScope()); } -CompilePass::CodeScopeUnit* -CompilePass::FunctionUnit::getScopeUnit(ManagedScpPtr scope){ +CodeScopeUnit* +FunctionUnit::getScopeUnit(ManagedScpPtr scope){ return getScopeUnit(&*scope); } -CompilePass::FunctionUnit* +FunctionUnit* CompilePass::getFunctionUnit(const ManagedFnPtr& function){ unsigned int id = function.id(); if (!functions.count(id)){ FunctionUnit* unit = new FunctionUnit(function, this); functions.emplace(id, std::unique_ptr(unit)); return unit; } return functions.at(id).get(); } void CompilePass::run(){ queryContext = reinterpret_cast (man->clasp->getQuery(QueryId::ContextQuery)); //Find out main function; ClaspLayer::ModelFragment model = man->clasp->query(Config::get("function-entry")); assert(model && "Error: No entry function found"); assert(model->first != model->second && "Error: Ambiguous entry function"); string nameMain = std::get<0>(ClaspLayer::parse(model->first->second)); FunctionUnit* unitMain = getFunctionUnit(man->root->findFunction(nameMain)); entry = unitMain->compile(); } llvm::Function* CompilePass::getEntryFunction(){ assert(entry); return entry; } void CompilePass::prepareQueries(ClaspLayer* clasp){ clasp->registerQuery(new containers::Query(), QueryId::ContainersQuery); clasp->registerQuery(new ContextQuery(), QueryId::ContextQuery); } //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/compilepass.h b/cpp/src/pass/compilepass.h index ab199a4..17b4bdf 100644 --- a/cpp/src/pass/compilepass.h +++ b/cpp/src/pass/compilepass.h @@ -1,85 +1,101 @@ #ifndef COMPILEPASS_H #define COMPILEPASS_H +#include #include "abstractpass.h" #include "llvm/IR/Function.h" -#include "compilation/latecontext.h" + +namespace xreate { + class AdhocScheme; + class ClaspLayer; + class ContextQuery; + class CallStatement; +} namespace xreate { +class CompilePass; -class AdhocScheme; -class ClaspLayer; -class ContextQuery; +namespace compilation { -class CompilePass : public AbstractPass { - friend class LateContext; +class CodeScopeUnit; +class FunctionUnit; + + +struct Context{ + FunctionUnit* function; + CodeScopeUnit* scope; + CompilePass* pass; +}; +class CodeScopeUnit { public: - class CodeScopeUnit; - class FunctionUnit{ - public: - FunctionUnit(ManagedFnPtr f, CompilePass* p) - : function(f), lateContext(f->getName(), p), pass(p) {} - - llvm::Value* compileInline(std::vector&& args, CompilePass::FunctionUnit* outer); - bool isInline(); - llvm::Function* compile(); - - CodeScopeUnit* getEntry(); - CodeScopeUnit* getScopeUnit(CodeScope* scope); - CodeScopeUnit* getScopeUnit(ManagedScpPtr scope); - - ManagedFnPtr function; - llvm::Function* raw = nullptr; - AdhocScheme* adhocImplementation=nullptr; //SECTIONTAG adhoc prefunc scheme declaration - LateContext lateContext; - - private: - CompilePass* pass; - std::map> scopes; - }; - - class CodeScopeUnit { - public: - CodeScopeUnit(CodeScope* codeScope, FunctionUnit* f, CompilePass* compilePass); - - void bindArg(llvm::Value* var, std::string&& name); - std::map __rawVars; - - void reset(){raw = nullptr;} - llvm::Value* compile(const std::string& hintBlockDecl=""); - llvm::Value* compileSymbol(const Symbol& s, std::string hintRetVar=""); - llvm::Value* process(const Expression& expr, const std::string& hintVarDecl=""); - CodeScope* scope; - - private: - CompilePass* pass; - llvm::Value* raw = nullptr; - FunctionUnit* function; - - FunctionUnit* findFunctionUnit(const std::string f); - }; - - struct Context{ - FunctionUnit* function; - CodeScopeUnit* scope; - CompilePass* pass; - }; + CodeScopeUnit(CodeScope* codeScope, FunctionUnit* f, CompilePass* compilePass); + void bindArg(llvm::Value* var, std::string&& name); + std::map __rawVars; + + void reset(){raw = nullptr;} + llvm::Value* compile(const std::string& hintBlockDecl=""); + llvm::Value* compileSymbol(const Symbol& s, std::string hintRetVar=""); + llvm::Value* process(const Expression& expr, const std::string& hintVarDecl=""); + CodeScope* scope; + +private: + CompilePass* pass; + llvm::Value* raw = nullptr; + FunctionUnit* function; + + CallStatement* findFunction(const std::string& callee); +}; + +class FunctionUnit{ +public: + FunctionUnit(ManagedFnPtr f, CompilePass* p) + : function(f), pass(p), contextCompiler(this, p) {} + + llvm::Value* compileInline(std::vector&& args, FunctionUnit* outer); + bool isInline(); + llvm::Function* compile(); + + CodeScopeUnit* getEntry(); + CodeScopeUnit* getScopeUnit(CodeScope* scope); + CodeScopeUnit* getScopeUnit(ManagedScpPtr scope); + + ManagedFnPtr function; + llvm::Function* raw = nullptr; + AdhocScheme* adhocImplementation=nullptr; //SECTIONTAG adhoc prefunc scheme declaration + +private: + CompilePass* pass; + std::map> scopes; + +public: + LateContextCompiler2 contextCompiler; +}; + +} // end of namespace `xreate::compilation` + +class CompilePass : public AbstractPass { + friend class LateContextCompiler; + friend class LateContextCompiler2; + friend class compilation::CodeScopeUnit; + friend class compilation::FunctionUnit; + +public: CompilePass(PassManager* manager): AbstractPass(manager) {} - FunctionUnit* getFunctionUnit(const ManagedFnPtr& function); + compilation::FunctionUnit* getFunctionUnit(const ManagedFnPtr& function); void run() override; llvm::Function* getEntryFunction(); static void prepareQueries(ClaspLayer* clasp); private: - std::map> functions; + std::map> functions; llvm::Function* entry = 0; ContextQuery* queryContext; }; } #endif // COMPILEPASS_H diff --git a/cpp/src/pass/loggerpass.cpp b/cpp/src/pass/loggerpass.cpp index b6fe477..ce8e552 100644 --- a/cpp/src/pass/loggerpass.cpp +++ b/cpp/src/pass/loggerpass.cpp @@ -1,106 +1,106 @@ /* * logging.cpp * * Created on: Jun 23, 2015 * Author: pgess */ #include #include "compilation/instr-containers.h" #include "utils.h" using namespace std; using namespace llvm; namespace xreate { void LoggerPass::init(ClaspLayer* clasp){ auto model = clasp->query(Config::get("logging.id")); if(!model) return; for (ClaspLayer::ModelIterator rec = model->first; rec!=model->second; ++rec){ std::tuple _v =ClaspLayer::parse(rec->second); Symbol v = clasp->unpack(get<0>(_v)); SymbolAttachments::put(v, true); } } void LoggerPass::process(const Expression& expression, PassContext context, const std::string& varDecl){ if (varDecl.size()){ Symbol v = context.scope->findSymbol(varDecl); if (SymbolAttachments::get(v, false)){ - CompilePass::FunctionUnit* func = compiler->getFunctionUnit(context.function); - CompilePass::CodeScopeUnit* scope = func->getScopeUnit(context.scope); + compilation::FunctionUnit* func = compiler->getFunctionUnit(context.function); + compilation::CodeScopeUnit* scope = func->getScopeUnit(context.scope); - CompilePass::Context compilationContext{func, scope, compiler}; + compilation::Context compilationContext{func, scope, compiler}; inject(v, compilationContext); } } return AbstractPass::process(expression, context, varDecl); } -void LoggerPass::inject(const Symbol& symbol, const CompilePass::Context& context){ +void LoggerPass::inject(const Symbol& symbol, const compilation::Context& context){ llvm::Value* source = context.scope->compileSymbol(symbol); ExpandedType typSource = man->root->expandType(CodeScope::findDefinition(symbol)); string format = ""; switch (typSource->__value) { case TypePrimitive::Int : case TypePrimitive::Num : case TypePrimitive::I32: case TypePrimitive::I8: format = "%d\n"; break; case TypePrimitive::String: format = "%s\n"; break; default: assert(false && "No appropriate type for logging"); } containers::Instructions compiler(context); LLVMLayer* llvm = context.pass->man->llvm; llvm->builder.SetInsertPoint(*source->use_begin()); llvm::Value* formatRaw = compiler.compileConstantStringAsPChar(format, "logformat"); llvm->builder.CreateCall2(refPrintf, formatRaw, source); } void LoggerPass::initOutput(){ LLVMLayer* llvm = man->llvm; refPrintf = llvm->module->getFunction("printf"); if (!refPrintf) { PointerType* typPtrI8 = PointerType::get(IntegerType::get(llvm->module->getContext(), 8), 0); std::vectorargsPrintf{typPtrI8}; FunctionType* signaturePrintf = FunctionType::get( /*Result=*/IntegerType::get(llvm->module->getContext(), 32), /*Params=*/argsPrintf, /*isVarArg=*/true); refPrintf = llvm::Function::Create( /*Type=*/signaturePrintf, /*Linkage=*/GlobalValue::ExternalLinkage, /*Name=*/"printf", llvm->module); // (external, no body) refPrintf->setCallingConv(CallingConv::C); } } LoggerPass::LoggerPass(PassManager* manager) : AbstractPass(manager) { initOutput(); init(man->clasp); } void LoggerPass::initDependencies(CompilePass* pass){ compiler = pass; } } /* namespace xreate */ diff --git a/cpp/src/pass/loggerpass.h b/cpp/src/pass/loggerpass.h index bfa3d0b..2c15b70 100644 --- a/cpp/src/pass/loggerpass.h +++ b/cpp/src/pass/loggerpass.h @@ -1,44 +1,44 @@ /* * logging.h * * Created on: Jun 23, 2015 * Author: pgess */ #ifndef SRC_LOGGING_H_ #define SRC_LOGGING_H_ #include "ast.h" #include #include "pass/compilepass.h" #include "pass/abstractpass.h" #include "clasplayer.h" namespace xreate { class LoggerPass:public AbstractPass, public IQuery { public: - void inject(const Symbol& symbol, const CompilePass::Context& context); + void inject(const Symbol& symbol, const compilation::Context& context); LoggerPass(PassManager* manager); virtual void init(ClaspLayer* clasp); void initDependencies(CompilePass* pass); virtual void process(const Expression& expression, PassContext context, const std::string& varDecl=""); private: CompilePass* compiler = nullptr; llvm::Function* refPrintf; void initOutput(); }; struct IsLogging{}; template<> struct AttachmentsDict { typedef bool Data; static const unsigned int key = 5; }; } /* namespace xreate */ #endif /* SRC_LOGGING_H_ */ diff --git a/cpp/src/passmanager.cpp b/cpp/src/passmanager.cpp index 87d8b8d..5f2dac3 100644 --- a/cpp/src/passmanager.cpp +++ b/cpp/src/passmanager.cpp @@ -1,102 +1,112 @@ #include #include #include "query/containers.h" #include "passmanager.h" #include "pass/compilepass.h" #include "pass/adhocpass.h" #include "Parser.h" #include "pass/cfgpass.h" #include "pass/dfgpass.h" #include +#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); + return prepareForCode(&scanner); } PassManager* -PassManager::prepareForCode(Scanner& scanner){ - Parser parser(&scanner); +PassManager::prepareForCode(FILE* code){ + Scanner scanner(code); + return prepareForCode(&scanner); +} + +PassManager* +PassManager::prepareForCode(Scanner* code){ + Parser parser(code); 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); CFGPass* passCFG = new CFGPass(man); //TODO is it really DFGPass needs CFGpass? man->registerPass(new DFGPass(man), PassId::DFGPass, passCFG); man->registerPass(passCFG, PassId::CFGPass); man->registerPass(new AdhocPass(man), PassId::AdhocPass); CompilePass::prepareQueries(man->clasp); return man; } void PassManager::registerPass(AbstractPassBase* pass, const PassId& id, AbstractPassBase* parent) { __passes.emplace(id, pass); __passDependencies.emplace(parent, pass); } AbstractPassBase* PassManager::getPassById(const PassId& id){ assert(__passes.count(id)); return __passes[id]; } void* PassManager::run() { runWithoutCompilation(); CompilePass* compiler = new CompilePass(this); compiler->run(); //Compiler Dependents: LoggerPass* logger = new LoggerPass(this); logger->initDependencies(compiler); logger->run(); llvm->print(); llvm->initJit(); return llvm->getFunctionPointer(compiler->getEntryFunction()); } void PassManager::runWithoutCompilation(){ + if (flagIsProcessed) return; + std::list passes{nullptr}; while (passes.size()){ AbstractPassBase* parent = passes.front(); auto range = __passDependencies.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->run(); + flagIsProcessed = true; } PassManager::~PassManager(){} diff --git a/cpp/src/passmanager.h b/cpp/src/passmanager.h index 389487f..86de4f3 100644 --- a/cpp/src/passmanager.h +++ b/cpp/src/passmanager.h @@ -1,45 +1,53 @@ #ifndef PASSMANAGER_H #define PASSMANAGER_H -#include "Scanner.h" #include #include +//stdio external +struct _IO_FILE; +typedef struct _IO_FILE FILE; + +class Scanner; + namespace xreate { class AbstractPassBase; class ClaspLayer; class LLVMLayer; class AST; enum class PassId { CFGPass, CompilePass, DFGPass, EnvironmentTestsPass, LoggerPass, AdhocPass, RulesPass }; class PassManager { public: ~PassManager(); void*run(); void runWithoutCompilation(); void registerPass(AbstractPassBase* pass, const PassId& id, AbstractPassBase* prerequisite=nullptr); AbstractPassBase* getPassById(const PassId& id); static PassManager* prepareForCode(std::string&& code); - static PassManager* prepareForCode(Scanner& scanner); + static PassManager* prepareForCode(FILE* code); ClaspLayer* clasp; LLVMLayer* llvm; AST* root; private: //typedef std::multimap FILTERS_STORAGE; //FILTERS_STORAGE __filters; std::map __passes; std::multimap __passDependencies; + bool flagIsProcessed = false; + + static PassManager* prepareForCode(Scanner* code); }; } #endif diff --git a/cpp/src/query/context.cpp b/cpp/src/query/context.cpp index 0f4399b..732ca16 100644 --- a/cpp/src/query/context.cpp +++ b/cpp/src/query/context.cpp @@ -1,129 +1,167 @@ /* * adhoc.cpp * * Created on: Dec 1, 2015 * Author: pgess */ #include #include +#include using namespace std; namespace xreate { -std::list -ContextQuery::getContext(const ScopePacked& scopeId){ - std::list result; +ContextQuery::ContextQuery() + : domainEmpty(vector()) {} - for (auto i: boost::make_iterator_range(__modelContext.equal_range(scopeId))){ - result.push_back(i.second); +const ContextDomain& +ContextQuery::getContext(const ScopePacked& scopeId){ + if (!__modelContext.count(scopeId)){ + return domainEmpty; } - for (auto i: boost::make_iterator_range(__modelForcedContext.equal_range(scopeId))){ - result.push_back(i.second); - } + return __modelContext.at(scopeId); +} - return result; +const ContextDomain& +ContextQuery::getContext(CodeScope* const scope){ + return getContext(clasp->pack(scope)); } void ContextQuery::forceContext(const ScopePacked& scopeId, std::list context){ - // TODO remove forced context only of the same class, possibly - + // TODO remove forced context of the same class/type only, possibly //remove any previous forced context for this scopeId - __modelForcedContext.erase(scopeId); + //__modelForcedContext.erase(scopeId); + //TASK restore forceContext + //std::multimap __modelForcedContext; + /* std::transform(context.begin(), context.end(), inserter(__modelForcedContext, __modelForcedContext.end()), [scopeId](const Expression& context){return make_pair(scopeId, context);}); + */ } void ContextQuery::init(ClaspLayer* clasp){ const std::string& atomEarlyBinding = Config::get("clasp.bindings.scope"); - ClaspLayer::ModelFragment model = clasp->query(atomEarlyBinding); - if (model){ - for (auto i = model->first; i!=model->second; ++i){ + this->clasp = clasp; + ClaspLayer::ModelFragment query = clasp->query(atomEarlyBinding); + + //static context + if (query){ + map> dictContext; + + for (auto i = query->first; i!=query->second; ++i){ ScopePacked idScope; Expression context; tie(idScope, context) = ClaspLayer::parse(i->second); - __modelContext.emplace(idScope, context); + dictContext[idScope].push_back(context); } - } - const std::string& atomLateBinding = Config::get("clasp.bindings.scope_weak"); - model = clasp->query(atomEarlyBinding); + for (map>::value_type& entry: dictContext){ + __modelContext.insert(move(entry)); + } + } - std::map> modelLateContext; - if (model){ - for (auto i = model->first; i!=model->second; ++i){ - string nameFunction; - Expression context; - tie(nameFunction, context) = ClaspLayer::parse(i->second); - modelLateContext.at(nameFunction).push_back(context); + //static decisions + query = clasp->query(Config::get("clasp.bindings.scope_decision")); + if (query){ + for (auto i = query->first; i!=query->second; ++i){ + ScopePacked scopeId; + string function; + Expression specialization; + tie(scopeId, function, specialization) = ClaspLayer::parse(i->second); + ScopeContextDecisions& scope = __modelStaticDecisions[scopeId]; + assert(scope.emplace(function, specialization).second && "Possibly more than one decision"); } + } - for(auto& entry: modelLateContext){ - __modelFunctionContext.emplace(entry.first, move(entry.second)); + //Fetch function specialization domains + std::multimap modelDomains; + const list& functions = clasp->ast->getAllFunctions(); + for (auto f: functions){ + if (f->guardContext.isValid()){ + modelDomains.emplace(f->getName(), f->guardContext); } } + + auto adapter = [](const std::pair& p){ return p.second; }; + + auto iBegin = modelDomains.begin(); + while (iBegin!=modelDomains.end()){ + string function = iBegin->first; + auto iEnd = modelDomains.upper_bound(function); + auto iBeginAdapted = boost::make_transform_iterator(iBegin,adapter); + auto iEndAdapted = boost::make_transform_iterator(iEnd,adapter); + ContextDomain dom(iBeginAdapted, iEndAdapted); + __modelFunctionDomain.emplace(function, move(dom)); + iBegin = iEnd; + } + + prepareDemandModel(); } const ContextDomain& ContextQuery::getFunctionDomain(const std::string& name) const { - static ContextDomain domainNULL({}); - - if (__modelFunctionContext.count(name)){ - return __modelFunctionContext.at(name); + if (__modelFunctionDomain.count(name)){ + return __modelFunctionDomain.at(name); } - return domainNULL; + return domainEmpty; } -ContextDomain::ContextDomain(const std::vector&& expressions) - : std::vector(move(expressions)){ - for (const Expression& e: expressions){ - serializer.registerExpression(e); - } - - size_t id =0; - for (const Expression& e: expressions){ - scheme.emplace(serializer.pack(e), id++); +const FunctionContextDemand& +ContextQuery::getFunctionDemand(const std::string& name) const { + if (__modelFunctionDemand.count(name)){ + return __modelFunctionDemand.at(name); } -} -size_t -ContextDomain::size() const{ - return PARENT::size(); + return decisionsEmpty; } +const ScopeContextDecisions& +ContextQuery::getStaticDecisions(const ScopePacked& scopeId){ + if (__modelStaticDecisions.count(scopeId)){ + return __modelStaticDecisions[scopeId]; + } -ContextDomain::const_iterator -ContextDomain::begin() const { - return begin(); -} - -ContextDomain::const_iterator -ContextDomain::end() const { - return end(); + return contextDecisionsEmpty; } -boost::optional -ContextDomain::getExpressionId(const Expression& e) const{ - const auto& exprPacked = serializer.packOptional(e); - if (!exprPacked){ - return boost::none; - } - - if (scheme.count(*exprPacked)){ - return scheme.at(*exprPacked); +void +ContextQuery::prepareDemandModel(){ + const std::string& atomFunctionDemand = Config::get("clasp.bindings.function_demand"); + + ClaspLayer::ModelFragment query = clasp->query(atomFunctionDemand); + if (query) + for (auto i = query->first; i!=query->second; ++i){ + string function; + string decision; + tie(function, decision) = ClaspLayer::parse(i->second); + + FunctionContextDemand& decisions = __modelFunctionDemand[function]; + decisions.left.insert(make_pair(decisions.size(), decision)); } - - return boost::none; } -const Expression& -ContextDomain::get(size_t id) const{ - return at(id); -} +// const std::string& atomLateBinding = Config::get("clasp.bindings.function_uncertain"); +// query = clasp->query(atomLateBinding); +// +// std::map> dictFunctionDomain; +// if (query){ +// for (auto i = query->first; i!=query->second; ++i){ +// string nameFunction; +// Expression context; +// tie(nameFunction, context) = ClaspLayer::parse(i->second); +// dictFunctionDomain.at(nameFunction).push_back(context); +// } +// +// for(auto& entry: dictFunctionDomain){ +// __modelFunctionDomain.emplace(entry.first, move(entry.second)); +// } +// } + } /* namespace xreate */ diff --git a/cpp/src/query/context.h b/cpp/src/query/context.h index 6da9f9d..7117ac0 100644 --- a/cpp/src/query/context.h +++ b/cpp/src/query/context.h @@ -1,81 +1,89 @@ /* * adhoc.h * * Created on: Dec 1, 2015 * Author: pgess */ #ifndef SRC_QUERY_CONTEXT_H_ #define SRC_QUERY_CONTEXT_H_ #include "clasplayer.h" #include "ast.h" -#include "expressionserializer.h" +#include "serialization.h" #include + +#include namespace xreate { -class ContextDomain: private std::vector{ - typedef std::vector PARENT; +typedef ExpressionSerialization::Serializer ContextDomain; +typedef boost::bimap FunctionContextDemand; +typedef std::map ScopeContextDecisions; +class ContextQuery: public IQuery { public: - ContextDomain(const std::vector&& expressions); - ContextDomain(ContextDomain&& other) - : scheme(std::move(other.scheme)), serializer(std::move(serializer)){} - boost::optional getExpressionId(const Expression& e) const; - const Expression& get(size_t id) const; - size_t size() const; - ContextDomain::const_iterator begin() const; - ContextDomain::const_iterator end() const; - + //AdhocQuery(); + const ContextDomain& getContext(const ScopePacked& scopeId); + const ContextDomain& getContext(CodeScope* const scope); + void forceContext(const ScopePacked& scopeId, std::list context); + const ContextDomain& getFunctionDomain(const std::string& name) const; + const FunctionContextDemand& getFunctionDemand(const std::string& name) const; + const ScopeContextDecisions& getStaticDecisions(const ScopePacked& scopeId); + virtual void init(ClaspLayer* clasp); + ContextQuery(); + virtual ~ContextQuery(){}; private: - ContextDomain(const ContextDomain&)=delete; + ClaspLayer* clasp; + std::map __modelContext; + std::map __modelFunctionDomain; + std::map __modelFunctionDemand; + std::map __modelStaticDecisions; + + const ContextDomain domainEmpty; + const FunctionContextDemand decisionsEmpty; + const ScopeContextDecisions contextDecisionsEmpty; - std::map scheme; - ExpressionSerializer serializer; + void prepareDemandModel(); }; +} /* namespace xreate */ + +/* template class ContextAttachments: private std::unordered_map { typedef std::unordered_map PARENT; public: + ContextAttachments(ContextAttachments&& other) + : PARENT(std::move(other)), domain(std::move(other.domain)) {} + + ContextAttachments(std::vector&& expressions, std::vector&& attachments) + : domain(move(expressions)) + { + size_t size = domain.size(); + for (size_t i=0; i FunctionSpecializations ; - -class ContextQuery: public IQuery { -public: - //AdhocQuery(); - std::list getContext(const ScopePacked& scopeId); - void forceContext(const ScopePacked& scopeId, std::list context); - const ContextDomain& getFunctionDomain(const std::string& name) const; - const FunctionSpecializations& getFunctionSpecializations(const std::string& name) const; - - virtual void init(ClaspLayer* clasp); - virtual ~ContextQuery(){}; -private: - std::multimap __modelContext; - std::multimap __modelForcedContext; - std::map __modelFunctionContext; - std::map __modelFunctionSpecializations; - -}; - -} /* namespace xreate */ +*/ #endif /* SRC_QUERY_CONTEXT_H_ */ diff --git a/cpp/src/serialization.h b/cpp/src/serialization.h new file mode 100644 index 0000000..08425af --- /dev/null +++ b/cpp/src/serialization.h @@ -0,0 +1,30 @@ +/* + * serialization.h + * + * Created on: 13 февр. 2016 + * Author: pgess + */ + +#ifndef SRC_SERIALIZATION_SERIALIZATION_H_ +#define SRC_SERIALIZATION_SERIALIZATION_H_ + +#include "serialization/expressionserializer.h" + +namespace xreate { +struct RequirementIntegralCode{}; + +template +struct ExpressionSerialization { + typedef PackedExpression Code; + typedef ExpressionSerializer Serializer; +}; + +template<> +struct ExpressionSerialization{ + typedef size_t Code; + typedef ExpressionSerializerIntegral Serializer; +}; +} + + +#endif /* SRC_SERIALIZATION_SERIALIZATION_H_ */ diff --git a/cpp/src/expressionserializer.cpp b/cpp/src/serialization/expressionserializer.cpp similarity index 76% rename from cpp/src/expressionserializer.cpp rename to cpp/src/serialization/expressionserializer.cpp index 34d67c2..af7e8f1 100644 --- a/cpp/src/expressionserializer.cpp +++ b/cpp/src/serialization/expressionserializer.cpp @@ -1,231 +1,287 @@ /* * expressionserializer.cpp * * Created on: Jan 4, 2016 * Author: pgess */ -#include +#include "serialization/expressionserializer.h" #include #include #include #include using namespace std; using namespace boost::bimaps; namespace xreate { struct Index { string name; size_t degree; //count of parameters unsigned char level; //level in expression tree (depth of tree layer) bool operator< (const Index other) const{ if (name != other.name) return name < other.name; if (degree != other.degree) return degree < other.degree; if (name != other.name) return level < other.level; return false; } }; class ExpressionSerializerPrivate { - boost::bimap> __registry; + //boost::bimap> __registry; + struct { + map left; + } __registry; map __range; public: void pack(const Expression& e, unsigned char level, OptionalPackedExpression& target){ if (!target) return; - switch (e.op){ case Operator::NONE: { switch (e.__state) { case Expression::STRING: case Expression::IDENT: { Index index{e.getValueString(), 0, level}; if (!__registry.left.count(index)){ target = boost::none; return; } size_t id = __registry.left.at(index); size_t range = __range[level]; (*target) << make_pair(id, range); return; } default: break; } break; } case Operator::CALL: { Index index{e.getValueString(), e.operands.size(), level}; - if(__registry.left.count(index)){ + if(!__registry.left.count(index)){ target = boost::none; return; } size_t id = __registry.left.at(index); size_t range = __range[level]; (*target) << make_pair(id, range); for (const Expression& operand: e.operands){ pack(operand, level+1, target); } return; } default: break; } assert(false && "Expression too complicate for serialization"); } void registerExpression(const Expression&e, unsigned char level){ switch (e.op){ case Operator::CALL: { Index index{e.getValueString(), e.operands.size(), level}; if (__registry.left.insert(make_pair(index, __range[level])).second){ __range[level]++; } for (const Expression& operand: e.operands){ registerExpression(operand, level+1); } return; } case Operator::NONE: { switch (e.__state) { case Expression::STRING: case Expression::IDENT: { Index index{e.getValueString(), 0, level}; if (__registry.left.insert(make_pair(index, __range[level])).second){ __range[level]++; } return; } default: break; } break; } default: break; } assert(false && "Expression too complicate for serialization"); } }; ExpressionSerializer::ExpressionSerializer() : strategy(new ExpressionSerializerPrivate()){ } ExpressionSerializer::~ExpressionSerializer() { delete strategy; } void ExpressionSerializer::registerExpression(const Expression&e){ + if (e.isValid()) strategy->registerExpression(e, 0); } PackedExpression -ExpressionSerializer::pack(const Expression& e){ - OptionalPackedExpression result; +ExpressionSerializer::getId(const Expression& e){ + OptionalPackedExpression result(move(PackedExpression())); strategy->pack(e, 0, result); assert(result); return move(*result); } OptionalPackedExpression -ExpressionSerializer::packOptional(const Expression& e) const{ - OptionalPackedExpression result; +ExpressionSerializer::getIdOptional(const Expression& e) const{ + OptionalPackedExpression result(move(PackedExpression())); strategy->pack(e, 0, result); return result; } +ExpressionSerializerIntegral::ExpressionSerializerIntegral(const std::vector&& expressions) + : std::vector(move(expressions)), serializer(*this){ + + size_t id =0; + for (const Expression& e: expressions){ + __registry.emplace(serializer.getId(e), id++); + } +} + +size_t +ExpressionSerializerIntegral::size() const{ + return PARENT::size(); +} + +size_t +ExpressionSerializerIntegral::count(const Expression& e) const { + return (getIdOptional(e)? 1: 0); +} + +ExpressionSerializerIntegral::const_iterator +ExpressionSerializerIntegral::begin() const { + return PARENT::begin(); +} + +ExpressionSerializerIntegral::const_iterator +ExpressionSerializerIntegral::end() const { + return PARENT::end(); +} + +size_t +ExpressionSerializerIntegral::getId(const Expression& e) const{ + const auto& exprPacked = serializer.getIdOptional(e); + assert(exprPacked); + + return __registry.at(*exprPacked); +} + +boost::optional +ExpressionSerializerIntegral::getIdOptional(const Expression& e) const{ + const auto& exprPacked = serializer.getIdOptional(e); + if (!exprPacked){ + return boost::none; + } + + return __registry.at(*exprPacked); +} + +const Expression& +ExpressionSerializerIntegral::get(size_t id) const{ + return at(id); +} + + void PackedExpression::operator<< (const std::pair& value){ static const size_t sizeSizeT = sizeof(size_t); const size_t& id = value.first; const size_t& range = value.second; int countSufficientBits = range <=1? 0 : ceil(log2(range)); if (0 < countRemainedBits && countRemainedBits < countSufficientBits) { size_t* tail = reinterpret_cast(__storage + size- sizeSizeT); (*tail) += id >> (countSufficientBits - countRemainedBits); countSufficientBits-=countRemainedBits; countRemainedBits = 0; } if (countRemainedBits == 0) { if (countSufficientBits == 0) return; char* __storageNew = new char[size+sizeSizeT]; std::memcpy (__storageNew, __storage, size); std::memset(__storageNew + size, 0, sizeSizeT); delete[] __storage; __storage = __storageNew; size += sizeSizeT; countRemainedBits = 8 * sizeSizeT; } if (countRemainedBits >= countSufficientBits) { size_t* tail = reinterpret_cast(__storage + size- sizeSizeT); (*tail) += id << (countRemainedBits - countSufficientBits); countRemainedBits -= countSufficientBits; return; } assert("Unreachable block"); } PackedExpression::PackedExpression(PackedExpression&& other){ __storage = other.__storage; size = other.size; countRemainedBits = other.countRemainedBits; other.__storage = nullptr; } bool PackedExpression::operator==(const PackedExpression& other) const{ if (size == other.size && countRemainedBits == other.countRemainedBits){ return std::memcmp(__storage, other.__storage, size) == 0 ; } return false; } bool PackedExpression::operator<(const PackedExpression& other) const{ if (size < other.size) { return true; } if (countRemainedBits < other.countRemainedBits) return true; if (size == other.size && countRemainedBits == other.countRemainedBits){ return std::memcmp(__storage, other.__storage, size) < 0 ; } return false; } bool PackedExpression::operator!=(const PackedExpression& other) const{ return ! ((*this) == other); } PackedExpression::~PackedExpression() { delete[] __storage; } //PackedExpression::PackedExpression (const PackedExpression& other) // : size(other.size), countRemainedBits(other.countRemainedBits) //{ // __storage = new char[size]; // std::memcpy (__storage, other.__storage, size); //} } /* namespace xreate */ diff --git a/cpp/src/serialization/expressionserializer.h b/cpp/src/serialization/expressionserializer.h new file mode 100644 index 0000000..b4b2354 --- /dev/null +++ b/cpp/src/serialization/expressionserializer.h @@ -0,0 +1,100 @@ +/* + * expressionserializer.h + * + * Created on: Jan 4, 2016 + * Author: pgess + */ + +#ifndef SRC_EXPRESSIONSERIALIZER_H_ +#define SRC_EXPRESSIONSERIALIZER_H_ + +#include "ast.h" +#include +#include + +namespace xreate { + +struct PackedExpression{ + PackedExpression(){}; + PackedExpression(PackedExpression&& other); + ~PackedExpression(); + void operator<< (const std::pair& value); + char* operator*(){return __storage;} + bool operator==(const PackedExpression& other) const; + bool operator!=(const PackedExpression& other) const; + bool operator<(const PackedExpression& other) const; + private: + PackedExpression (const PackedExpression&)=delete; + PackedExpression& operator=(const PackedExpression&)=delete; + PackedExpression& operator=(PackedExpression&&)=delete; + + char* __storage = nullptr; + size_t size =0; + unsigned char countRemainedBits =0; +}; +typedef boost::optional OptionalPackedExpression; + +class ExpressionSerializerPrivate; + +class ExpressionSerializer { +public: + template + ExpressionSerializer(const Container& source): ExpressionSerializer(){ + for (const Expression& e: source) { + registerExpression(e); + } + } + + template + ExpressionSerializer(const Container& source, Transformer op): ExpressionSerializer(){ + for (const typename Container::value_type& e: source) { + registerExpression(op(e)); + } + } + + ExpressionSerializer(ExpressionSerializer&& other) + : strategy(other.strategy) {other.strategy = 0; } + + virtual ~ExpressionSerializer(); + + PackedExpression getId(const Expression& e); + OptionalPackedExpression getIdOptional(const Expression& e) const; + +private: + ExpressionSerializerPrivate* strategy; + + void registerExpression(const Expression&e); + ExpressionSerializer(); +}; + +class ExpressionSerializerIntegral: private std::vector{ + typedef std::vector PARENT; + +public: + ExpressionSerializerIntegral(const std::vector&& expressions); + template + ExpressionSerializerIntegral(Iterator first, Iterator last) + : ExpressionSerializerIntegral(std::vector(first, last)){} + + ExpressionSerializerIntegral(ExpressionSerializerIntegral&& other) + : PARENT(std::move(other)), __registry(std::move(other.__registry)), serializer(std::move(other.serializer)){} + size_t getId(const Expression& e) const; + boost::optional getIdOptional(const Expression& e) const; + const Expression& get(size_t id) const; + size_t size() const; + size_t count(const Expression& e) const; + ExpressionSerializerIntegral::const_iterator begin() const; + ExpressionSerializerIntegral::const_iterator end() const; + +private: + ExpressionSerializerIntegral(const ExpressionSerializerIntegral&)=delete; + + std::map __registry; + ExpressionSerializer serializer; +}; + + + +} /* namespace xreate */ + +#endif /* SRC_EXPRESSIONSERIALIZER_H_ */ diff --git a/cpp/src/serialization/expressionserializer2.cpp b/cpp/src/serialization/expressionserializer2.cpp new file mode 100644 index 0000000..5c63641 --- /dev/null +++ b/cpp/src/serialization/expressionserializer2.cpp @@ -0,0 +1,98 @@ +/* + * ExpressionSerializer2.cpp + * + * Created on: 9 февр. 2016 + * Author: pgess + */ + +#include "expressionserializer2.h" + +using namespace std; + +namespace xreate { + +typedef size_t ElementId; +struct Element{ + string name; + unsigned char degree; + ElementId terminal = 0; + std::list childs; + + bool operator< (const Element& other) { + int cmp = name.compare(other.name); + if (cmp !=0) return (cmp < 0); + return (degree < other.degree); + } + + bool operator== (const Element& other) { + int cmp = name.compare(other.name); + if (cmp != 0) return false; + return degree == other.degree; + } + + Element(string nameElement, unsigned int degreeElement) + : name(nameElement), degree(degreeElement) {} +}; + +const Element End{"", 0}; + +class ExpressionSerializerStrategyB { + vector __registry; + + ElementId push(const Element& e, ElementId rootId){ + typedef list::iterator ElementIt; + + list& elements = __registry[rootId].childs; + list::iterator pos = std::__lower_bound(elements.begin(), elements.end(), e, + [this](const ElementIt& testIt, const Element& value){return __registry[*testIt] < value;}); + + if (!(__registry[*pos] == e)) { + __registry.push_back(e); + ElementId result = __registry.size()-1; + elements.insert(pos, result); + return result; + } + + return *pos; + } + + ElementId registerExpression(const Expression& e, ElementId rootId) { + switch(e.op){ + case Operator::NONE: { + switch (e.__state) { + case Expression::STRING: + case Expression::IDENT: { + const string& name = e.getValueString(); + Element element(name, 0); + ElementId rootId = push(element, rootId); + return rootId; + } + + default: { + break; + } + } + break; + } + + case Operator::CALL: { + const string& name = e.getValueString(); + Element element(name, e.operands.size()); + ElementId rootId = push(element, rootId); + + for (const Expression& op: e.operands){ + Element element(op.getValueString(), op.operands.size()); + rootId = push(element, rootId); + } + + return rootId; + } + + default: break; + } + + assert(false && "Expression too complicate for serialization"); + } +}; + +} /* namespace xreate */ diff --git a/cpp/src/serialization/expressionserializer2.h b/cpp/src/serialization/expressionserializer2.h new file mode 100644 index 0000000..3b29756 --- /dev/null +++ b/cpp/src/serialization/expressionserializer2.h @@ -0,0 +1,25 @@ +/* + * ExpressionSerializer2.h + * + * Created on: 9 февр. 2016 + * Author: pgess + */ + +#ifndef EXPRESSIONSERIALIZER2_H_ +#define EXPRESSIONSERIALIZER2_H_ + +#include + +namespace xreate { + +class ExpressionSerializer2 { +public: + ExpressionSerializer2(); + virtual ~ExpressionSerializer2(); + + void registerExpression(const Expression& e); +}; + +} /* namespace xreate */ + +#endif /* EXPRESSIONSERIALIZER2_H_ */ diff --git a/cpp/tests/ExpressionSerializer2_test.cpp b/cpp/tests/ExpressionSerializer2_test.cpp new file mode 100644 index 0000000..9170de7 --- /dev/null +++ b/cpp/tests/ExpressionSerializer2_test.cpp @@ -0,0 +1,12 @@ +/* + * ExpressionSerializer2_test.cpp + * + * Created on: 9 февр. 2016 + * Author: pgess + */ + +#include "serialization/expressionserializer2.h" + +namespace xreate { + +} /* namespace xreate */ diff --git a/cpp/tests/compilation.cpp b/cpp/tests/compilation.cpp index c305e3e..97e4087 100644 --- a/cpp/tests/compilation.cpp +++ b/cpp/tests/compilation.cpp @@ -1,5 +1,62 @@ +#include "passmanager.h" #include "gtest/gtest.h" +using namespace xreate; //TEST FunctionUnit::compileInline TEST(Compilation, DISABLED_functionInline1){ } + +//DEBT implement no pkgconfig ways to link libs +TEST(Compilation, Sequence1){ + PassManager* man = PassManager::prepareForCode( + "interface(extern-c){\n" + " libFake = library:: pkgconfig(\"libxml-2.0\").\n" + " \n" + " include {\n" + " libFake = [\"stdio.h\", \"stdlib.h\"]\n" + " }.\n" + "}" + + "main = function:: int; entry {\n" + " sequence [" + " printf(\"FIRST-\"),\n" + " printf(\">SECOND\")\n" + " ]" + "}" + ); + + int (*main)() = (int (*)()) man->run(); + + testing::internal::CaptureStdout(); + main(); + std::string output = testing::internal::GetCapturedStdout(); + + ASSERT_STREQ("FIRST->SECOND", output.c_str()); +} + +TEST(Compilation, full_IFStatementWithVariantType){ + PassManager* man = PassManager::prepareForCode( + "COLORS = type variant (RED, BLUE, GREEN).\n" + "\n" + " main = function(x::int):: int; entry {\n" + " color = if (x == 0 )::COLORS {RED} else {BLUE}.\n" + " if (color == BLUE)::int {1} else {0}\n" + " }" + ); + + int (*main)(int) = (int (*)(int)) man->run(); + ASSERT_EQ(0, main(0)); + ASSERT_EQ(1, main(1)); +} + +// "main = function:: int; entry {\n" +// " context:: expectNoErrors. " +// " buf1 = \"aaaaa\"::string.\n" +// " buf2 = \"aaaaa\"::string.\n" +// " sequence [" +// " sprintf(buf1, \"%d\", exec(\"bazaar --version\"))," +// " sprintf(buf2, \"%d\", exec(\"svn --version\"))," +// " printf(buf1),\n" +// " printf(buf2)\n" +// "]" +// "}" diff --git a/cpp/tests/containers.cpp b/cpp/tests/containers.cpp index 611ccfe..e2c3e76 100644 --- a/cpp/tests/containers.cpp +++ b/cpp/tests/containers.cpp @@ -1,54 +1,54 @@ /* * containers.cpp * * Created on: Jun 9, 2015 * Author: pgess */ -#include "gtest/gtest.h" + #include "passmanager.h" -#include "Parser.h" #include "query/containers.h" +#include "Parser.h" +#include "gtest/gtest.h" using namespace std; using namespace xreate; using namespace containers; 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(input)); void* mainPtr = program->run(); int (*main)() = (int (*)())(intptr_t)mainPtr; int answer = main(); ASSERT_EQ(16, answer); fclose(input); } diff --git a/cpp/tests/context.cpp b/cpp/tests/context.cpp index 485a7c1..77f2d8a 100644 --- a/cpp/tests/context.cpp +++ b/cpp/tests/context.cpp @@ -1,198 +1,267 @@ /* * frame-context.cpp * * Created on: Dec 3, 2015 * Author: pgess */ #include "passmanager.h" #include "query/context.h" #include "gtest/gtest.h" +#include using namespace xreate; TEST(Context, frame_Context1){ PassManager* man = PassManager::prepareForCode( " import raw (\"core/control-context.lp\")\n" " testC = function::int {\n" " context:: testC.\n" " 0\n" " }\n" " testA = function:: int {\n" " context:: testA; test.\n" " testC()\n" " }\n" " testB = function:: int {\n" " context:: testB; test.\n" " testC()\n" " }\n" ); ContextQuery* query = (ContextQuery*) man->clasp->registerQuery(new ContextQuery(), QueryId::ContextQuery); man->runWithoutCompilation(); CodeScope* scopeTestC = man->root->findFunction("testC")->getEntryScope(); - const std::list& context = query->getContext(man->clasp->pack(scopeTestC)); + const ContextDomain& context = query->getContext(man->clasp->pack(scopeTestC)); int contextSize = context.size(); EXPECT_EQ(2, contextSize); } TEST(Context, full_ContextBasedFunctionSpecialization){ PassManager* man = PassManager::prepareForCode( " case context::toMillimeters {\n" " convert = function(source:: num)::num {\n" " 10 * source \n" " }\n" " }\n" " case context::toInches {\n" " convert = function(source:: num)::num {\n" " 2 * source \n" " }\n" " }\n" "test = function(vrnt:: int)::int; entry {\n" " switch(vrnt):: int\n" " case 0 {\n" " context:: toMillimeters.\n" " convert(1)\n" " }\n" "\n" " case 1 {\n" " context:: toInches.\n" " convert(1)\n" " }\n" " case default {0}\n" " }" ); int (*main)(int) = (int (*)(int)) man->run(); ASSERT_EQ(10, main(0)); ASSERT_EQ(2, main(1)); } TEST(Context, full_LoopContext){ PassManager* man = PassManager::prepareForCode("case context:: a {\n" " print = function:: string {\n" " \"a\"\n" " }}\n" "\n" " case context:: b {\n" " print = function:: string {\n" " \"b\"\n" " }}\n" "\n" " case context:: c {\n" " print = function:: string {\n" " \"c\"\n" " }}\n" "\n" " case context:: d {\n" " print = function:: string {\n" " \"d\"\n" " }}\n" "\n" " start = function(command::int)::string; entry {\n" " switch (command) :: string \n" " case 0 {\n" " context:: print(a); print(b); print(d).\n" "\n" " loop context (\"print\") {\n" " print()\n" " }\n" " }\n" "\n" " case default {\n" " context:: print(c).\n" " loop context (\"print\") {\n" " print()\n" " }\n" " }\n" " }"); char* (*main)(int) =(char* (*)(int)) man->run(); ASSERT_STREQ("c", main(1)); ASSERT_STREQ("a", main(0)); } TEST(Context, full_RuleContext){ /* "rule context:: childs(Child)\n" " case artefact(Item)\n" " {\n" " artefact_depends(Item, Child)\n" " }"; */ PassManager* man = PassManager::prepareForCode( " case context:: toMilli {\n" " convert = function(length::int)::int{\n" " 10 * length\n" " }\n" " }\n" "\n" " case context:: toCenti {\n" " convert = function(length::int)::int{\n" " length\n" " }\n" " }\n" "\n" " main=function::int; entry {\n" " context:: output(milli).\n" "\n" " rule context::toMilli\n" " case output(milli) {true}\n" "\n" " convert(1)\n" " }" ); man->clasp->addRawScript("true."); int (*entry)() = (int (*)()) man->run(); ASSERT_EQ(10, entry()); } TEST(Context, full_InheritedRuleContext){ PassManager* man = PassManager::prepareForCode( " import raw (\"core/control-context.lp\") \n" " case context:: toMilli {\n" " convert = function(length::int)::int{\n" " 10 * length\n" " }\n" " }\n" " case context:: toCenti {\n" " convert = function(length::int)::int{\n" " length\n" " }\n" " }\n" "\n" "main = function(comm:: num)::num; entry{\n" " rule context::X case output(X) {true}\n" "\n" " switch (comm)::num \n" " case 0 {\n" " context:: output(toMilli).\n" " convert(1)\n" " }\n" " case default {\n" " context:: output(toCenti).\n" " convert(1)\n" " }\n" " }"); man->clasp->addRawScript("true."); int (*entry)(int) = (int (*)(int)) man->run(); ASSERT_EQ(10, entry(0)); ASSERT_EQ(1, entry(1)); } + + + +TEST(Context, full_LateContext){ + PassManager* man = PassManager::prepareForCode( + "import raw (\"core/control-context.lp\")\n" + + " convert = function(length:: num)::num{\n" + " 0\n" + " }\n" + + "case context:: milli {\n" + " convert = function(length:: num)::num{\n" + " 1000 * length\n" + " }\n" + "}\n" + "\n" + "case context:: centi {\n" + " convert = function(length:: num)::num{\n" + " 100 * length\n" + " }\n" + "}\n" + "\n" + "calculate = function(length:: num)::num {\n" + " convert(length)\n" + "}\n" + "\n" + "main = function(com:: num):: num; entry {\n" + " switch (com):: num \n" + " case 0 {\n" + " context:: milli.\n" + " calculate(1)\n" + " }\n" + "\n" + " case default{\n" + " context:: centi. \n" + " calculate(1)\n" + " }\n" + "}"); + + man->runWithoutCompilation(); + ContextQuery* queryContext = reinterpret_cast(man->clasp->getQuery(QueryId::ContextQuery)); + Expression exprSwitch = man->root->findFunction("main")->__entry->__body; + CodeScope* blockDefault = man->root->findFunction("main")->__entry->__body.operands[1].blocks.front(); + ScopePacked blockDefaultId = man->clasp->pack(blockDefault); + const ContextDomain& domDefault = queryContext->getContext(blockDefaultId); + ASSERT_EQ(1, domDefault.count(Expression(Atom("centi")))); + + std::list variants = man->root->getFunctionVariants("convert"); + for (ManagedFnPtr f: variants){ + const Expression guard = f->guardContext; + bool result = (guard.getValueString() == "centi" || guard.getValueString() == "milli" || !guard.isValid()); + ASSERT_TRUE(result); + } + + const FunctionContextDemand& demMain = queryContext->getFunctionDemand("main"); + ASSERT_EQ(0, demMain.size()); + + const FunctionContextDemand& demCalculate = queryContext->getFunctionDemand("calculate"); + ASSERT_EQ(1, demCalculate.size()); + ASSERT_EQ(1, demCalculate.right.count("convert")); + + int (*entry)(int) = (int (*)(int)) man->run(); + ASSERT_EQ(1000, entry(0)); + ASSERT_EQ(100, entry(1)); +} + + diff --git a/cpp/tests/expressions.cpp b/cpp/tests/expressions.cpp deleted file mode 100644 index 6b6e732..0000000 --- a/cpp/tests/expressions.cpp +++ /dev/null @@ -1,31 +0,0 @@ -/* - * expressions.cpp - * - * Created on: Dec 21, 2015 - * Author: pgess - */ - -#include "passmanager.h" -#include "gtest/gtest.h" - -using namespace std; -using namespace xreate; - -TEST(Expressions, switch1){ - string&& code = - " colors = type variant (RED, BLUE, GREEN).\n" - " test = function:: colors; entry {GREEN}" - - "main = function:: int; entry {\n" - " switch(test():: color)\n" - " case GREEN {0}\n" - " case default {1}\n" - "}"; - - PassManager* man = PassManager::prepareForCode(move(code)); - int (*main)() = (int (*)()) man->run(); - - EXPECT_EQ(0, main()); -} - - diff --git a/cpp/tests/pass-Logger.cpp b/cpp/tests/pass-Logger.cpp index a1da4c7..2999b73 100644 --- a/cpp/tests/pass-Logger.cpp +++ b/cpp/tests/pass-Logger.cpp @@ -1,87 +1,85 @@ /* * testLogging.cpp * * Created on: Jun 23, 2015 * Author: pgess */ #include #include "gtest/gtest.h" #include "passmanager.h" #include "llvmlayer.h" #include "Parser.h" -#include "pass/compilepass.h" using namespace std; using namespace xreate; TEST(LoggerPass, simpleInjection){ PassManager* man = PassManager::prepareForCode("test= function():: int; entry{x = 2+8::int. return x}"); man->runWithoutCompilation(); CompilePass* compiler = new CompilePass(man); compiler->run(); - CompilePass::FunctionUnit* fTest = compiler->getFunctionUnit(man->root->findFunction("test")); + compilation::FunctionUnit* fTest = compiler->getFunctionUnit(man->root->findFunction("test")); ASSERT_NE(fTest, nullptr); - CompilePass::CodeScopeUnit* scopeUnitTest = fTest->getEntry(); + compilation::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, compiler}; + compilation::Context params{fTest, scopeUnitTest, compiler}; LoggerPass 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(LoggerPass, simpleInjection2){ PassManager* man = PassManager::prepareForCode("test= function():: int; entry{x = 2+8::int; logging. x}"); man->runWithoutCompilation(); CompilePass* compiler= new CompilePass(man); compiler->run(); LoggerPass* logger = new LoggerPass(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(LoggerPass, simpleInjection3){ FILE* input = fopen("scripts/cases/log.xreate","r"); - assert(input != nullptr); + assert(input); - Scanner scanner(input); - std::unique_ptr program(PassManager::prepareForCode(scanner)); + std::unique_ptr program(PassManager::prepareForCode(input)); void* mainPtr = program->run(); int (*main)() = (int (*)())(intptr_t)mainPtr; int answer = main(); fclose(input); } diff --git a/cpp/tests/sprint1-installation.cpp b/cpp/tests/sprint1-installation.cpp new file mode 100644 index 0000000..b4dda10 --- /dev/null +++ b/cpp/tests/sprint1-installation.cpp @@ -0,0 +1,22 @@ +/* + * sprint1-installation.cpp + * + * Created on: 26 Feb 2016 + * Author: pgess + */ + +#include "passmanager.h" +#include "gtest/gtest.h" +#include +using namespace std; +using namespace xreate; + +//TODO replace string identifiers with Atoms in order to hold position, etc +TEST(Sprint1, test1){ + const string filenameSource("scripts/testspass/sprint1-Installation1.xreate"); + FILE* fileSource; + ASSERT_TRUE(fileSource = fopen(filenameSource.c_str(), "rb")); + + PassManager* man = PassManager::prepareForCode(fileSource); + man->run(); +} diff --git a/cpp/tests/testExpressionSerializer.cpp b/cpp/tests/testExpressionSerializer.cpp index 9fd30f3..c5dc128 100644 --- a/cpp/tests/testExpressionSerializer.cpp +++ b/cpp/tests/testExpressionSerializer.cpp @@ -1,50 +1,65 @@ /* * testExpressionSerializer.cpp * * Created on: Jan 4, 2016 * Author: pgess */ -#include "expressionserializer.h" +#include "serialization/expressionserializer.h" +#include "serialization.h" #include "ast.h" #include "gtest/gtest.h" + using namespace xreate; using namespace std; TEST(ExpressionSerializer, pack1){ PackedExpression x; x << std::make_pair(0xA1, 0x100); size_t* storage = reinterpret_cast (*x); ASSERT_EQ(0xA100000000000000, *storage); x << std::make_pair(0x23456, 0x100000); ASSERT_EQ(0xA123456000000000, *storage); x << std::make_pair(0x7654321, 0x10000000); ASSERT_EQ(0xA123456765432100, *storage); x << std::make_pair(0xABBA, 0x10000); storage = reinterpret_cast (*x); ASSERT_EQ(0xA1234567654321AB, *storage); ASSERT_EQ(0xBA00000000000000, *(storage+1)); } TEST(ExpressionSerializer, serialize1){ Expression a(Operator::CALL, {Expression(string("a")), Expression(string("a"))}); Expression b(Operator::CALL, {Expression(string("a")), Expression(string("b"))}); - ExpressionSerializer serializer; - serializer.registerExpression(a); - serializer.registerExpression(b); + ExpressionSerializer serializer(vector{a, b}); - PackedExpression packA = serializer.pack(a); - PackedExpression packB = serializer.pack(b); - PackedExpression packA2 = serializer.pack(a); + PackedExpression packA = serializer.getId(a); + PackedExpression packB = serializer.getId(b); + PackedExpression packA2 = serializer.getId(a); ASSERT_EQ(packA, packA2); ASSERT_NE(packA, packB); } +TEST(ExpressionSerializer, serialize2){ + Expression a(Operator::CALL, {Expression(string("a")), Expression(string("a"))}); + Expression b(Operator::CALL, {Expression(string("a")), Expression(string("b"))}); + Expression c(Atom("c")); + + typedef ExpressionSerialization::Serializer Serializer; + Serializer serializer(vector{a, b}); + + ASSERT_EQ(2, serializer.size()); + ASSERT_EQ(1, serializer.count(a)); + ASSERT_EQ(1, serializer.count(b)); + ASSERT_EQ(0, serializer.count(c)); + Serializer serializer2(move(serializer)); + ASSERT_EQ(1, serializer2.count(a)); +} diff --git a/cpp/tests/types.cpp b/cpp/tests/types.cpp index 9801984..5815c3b 100644 --- a/cpp/tests/types.cpp +++ b/cpp/tests/types.cpp @@ -1,149 +1,167 @@ /* * types.cpp * * Created on: Jun 4, 2015 * Author: pgess */ #include "gtest/gtest.h" #include "passmanager.h" #include "llvmlayer.h" #include "Parser.h" using namespace std; using namespace xreate; TEST(Types, DependantTypes1) { string&& code = "XmlNode = type alias {\n" " tag:: string,\n" " /* attrs:: [string],*/\n" " content:: string\n" "}.\n"; std::unique_ptr program(PassManager::prepareForCode(move(code))); ExpandedType typeXmlNode = program->root->findType("XmlNode"); ASSERT_EQ(TypeOperator::STRUCT, typeXmlNode->__operator); ASSERT_EQ(2, typeXmlNode->__operands.size()); ASSERT_EQ(TypePrimitive::String, typeXmlNode->__operands.at(0).__value); ASSERT_EQ(TypePrimitive::String, typeXmlNode->__operands.at(1).__value); } TEST(Types, DependantTypes2) { string&& code = "XmlNode = type alias {\n" " tag:: string,\n" " /* attrs:: [string],*/\n" " content:: string\n" "}.\n" "" "Template = type Template(Leaf) [Leaf, [Leaf[content]]]." "Concrete = type alias Template(XmlNode)."; std::unique_ptr program(PassManager::prepareForCode(move(code))); ExpandedType typeConcrete = program->root->findType("Concrete"); ASSERT_EQ(TypeOperator::TUPLE, typeConcrete->__operator); ASSERT_EQ(2, typeConcrete->__operands.size()); ASSERT_EQ(TypeOperator::STRUCT, typeConcrete->__operands.at(0).__operator); ASSERT_EQ(TypeOperator::ARRAY, typeConcrete->__operands.at(1).__operator); ASSERT_EQ(TypePrimitive::String, typeConcrete->__operands.at(1).__operands.at(0).__value); } TEST(Types, TreeType1) { string&& code = "XmlNode = type alias {\n" " tag:: string,\n" " /* attrs:: [string],*/\n" " content:: string\n" "}.\n" "" "Tree = type Tree(Leaf) [Leaf, [Tree(Leaf)]]." "Concrete = type alias Tree(XmlNode)."; std::unique_ptr program(PassManager::prepareForCode(move(code))); ExpandedType typeConcrete = program->root->findType("Concrete"); ASSERT_EQ(TypeOperator::TUPLE, typeConcrete->__operator); ASSERT_EQ(2, typeConcrete->__operands.size()); ASSERT_EQ(TypeOperator::STRUCT, typeConcrete->__operands.at(0).__operator); ASSERT_EQ(TypeOperator::ARRAY, typeConcrete->__operands.at(1).__operator); auto typeLink = typeConcrete->__operands.at(1).__operands.at(0); ASSERT_EQ(TypeOperator::LINK, typeLink.__operator); ASSERT_EQ(typeConcrete->conjuctionId,typeLink.conjuctionId); } TEST(Types, TreeType1LLvm){ string&& code = "XmlNode = type alias {\n" " tag:: string,\n" " /* attrs:: [string],*/\n" " content:: string\n" "}.\n" "" "Tree = type Tree(Leaf) [Leaf, [Tree(Leaf)]]." "Concrete = type alias Tree(XmlNode)."; std::unique_ptr program(PassManager::prepareForCode(move(code))); ExpandedType typeConcrete = program->root->findType("Concrete"); llvm::Type* raw = program->llvm->toLLVMType(typeConcrete); } TEST(Types, ArrayOfExternal1){ FILE* input = fopen("scripts/testspass/Containers_Implementation_LinkedList1.xreate","r"); assert(input != nullptr); Scanner scanner(input); Parser parser(&scanner); parser.Parse(); AST& ast = parser.root; CodeScope* body = ast.findFunction("test")->getEntryScope(); Symbol symb = body->findSymbol("childrenRaw"); const TypeAnnotation& t = CodeScope::findDefinition(symb); const ExpandedType& t2 = ast.expandType(t); EXPECT_EQ(t2->__operator, TypeOperator::ARRAY); } TEST(Types, ExternType1){ FILE* input = fopen("scripts/testspass/Containers_Implementation_LinkedList1.xreate","r"); assert(input != nullptr); Scanner scanner(input); Parser parser(&scanner); parser.Parse(); AST& ast = parser.root; CodeScope* body = ast.findFunction("test")->getEntryScope(); Symbol symbTree = body->findSymbol("tree"); const TypeAnnotation& t = CodeScope::findDefinition(symbTree); const ExpandedType& t2 = ast.expandType(t); EXPECT_EQ(t2->__operator, TypeOperator::CUSTOM); } TEST(Types, ast_VariantType1){ string&& code = " colors = type variant (RED, BLUE, GREEN).\n" " test = function:: colors; entry {GREEN}"; std::unique_ptr program(PassManager::prepareForCode(move(code))); ExpandedType typ = program->root->findType("colors"); EXPECT_EQ(TypeOperator::VARIANT, typ->__operator); Expression eRed = program->root->findFunction("test")->getEntryScope()->__body; EXPECT_EQ(Expression::VARIANT, eRed.__state); const ExpandedType& typ2 = program->root->expandType(eRed.type); EXPECT_EQ(TypeOperator::VARIANT, typ2->__operator); program->run(); } +TEST(Types, full_VariantType_Switch1){ + string&& code = + " colors = type variant (RED, BLUE, GREEN).\n" + " test = function:: colors; entry {GREEN}" + + "main = function:: int; entry {\n" + " switch(test():: color)\n" + " case GREEN {0}\n" + " case default {1}\n" + "}"; + + PassManager* man = PassManager::prepareForCode(move(code)); + int (*main)() = (int (*)()) man->run(); + + EXPECT_EQ(0, main()); +} + + //TEST string type diff --git a/cpp/tests/xml.cpp b/cpp/tests/xml.cpp index cb62100..653f60e 100644 --- a/cpp/tests/xml.cpp +++ b/cpp/tests/xml.cpp @@ -1,31 +1,29 @@ #include "passmanager.h" -#include "Scanner.h" - #include "gtest/gtest.h" +#include using namespace xreate; TEST(Xml, Main){ - FILE* input = fopen("scripts/xml/input.xreate", "r"); - assert(input != nullptr); + FILE* input = fopen("scripts/testspass/xml-test1.xreate", "r"); + assert(input); - Scanner scanner(input); - PassManager* program = PassManager::prepareForCode(scanner); + std::unique_ptr program(PassManager::prepareForCode(input)); void* mainPtr = program->run(); int (*main)() = (int (*)())(intptr_t)mainPtr; int answer = main(); } TEST(Xml, DISABLED_AliasTuple){ } TEST(Xml, DISABLED_FoldProtoEnhanced){ } TEST(Xml, DISABLED_TransfucPropagation){ } diff --git a/scripts/containers/Containers_Implementation_LinkedList1.xreate b/scripts/containers/Containers_Implementation_LinkedList1.xreate new file mode 120000 index 0000000..25bdd31 --- /dev/null +++ b/scripts/containers/Containers_Implementation_LinkedList1.xreate @@ -0,0 +1 @@ +/private/prg/code/xreate/scripts/testspass/Containers_Implementation_LinkedList1.xreate \ No newline at end of file diff --git a/scripts/cases/containers.xreate b/scripts/containers/containers.xreate similarity index 100% rename from scripts/cases/containers.xreate rename to scripts/containers/containers.xreate diff --git a/scripts/environment-tests/dependencies.lp b/scripts/environment-tests/dependencies.lp deleted file mode 120000 index 7db9889..0000000 --- a/scripts/environment-tests/dependencies.lp +++ /dev/null @@ -1 +0,0 @@ -/private/prg/code/xreate/core/dependencies.lp \ No newline at end of file diff --git a/scripts/environment-tests/sequence b/scripts/environment-tests/sequence deleted file mode 100644 index 1fc241b..0000000 --- a/scripts/environment-tests/sequence +++ /dev/null @@ -1,62 +0,0 @@ -include raw "core/dependencies.lp" -include raw "core/control-context.lp" -include raw "core/unit-tests.lp" - -start = function:: int; entry { - context:: goal(artefact(gcc)). - - provideGoals() -} - -provideGoals = function():: int { - loop context (goal) { - visit_artefact() - } -} - -visitArtefact = function(){ - switch (EXISTS()){ - case INSTALLED { - ad hoc NOACTION - } - - case NON_INSTALLED { - run [ - PROVIDE_DEPENDENCIES(), - PROVIDE()) - ] - } - } -} - -provideDependencies() = function() { - rule context { - childs(Child) <- artefact(Item); artefact_depends(Item, Child). - } - - loop context (childs) { - VISIT_ARTEFACT(). - } -} - -case context:: artefact(subversion) { - EXISTS = function() { - exec("svn --version"):: ExpectNoErrors; log("Check svn"). - } - - PROVIDE = function(){ - exec("sudo apt-get install subversion"):: log("[Subversion] Installation"). - } -} - - -// DRAFT -/* - flagIsProvided = if(dictProvided()) {true} else - dictProvided = dictProvided + - -expectErrorCode = pre function(x::int){ - if (x==0)::bool {ad hoc "Success"} - else {ad hoc "Error"} -} -*/ \ No newline at end of file diff --git a/scripts/environment-tests/tests-early_late_binding.lp b/scripts/environment-tests/tests-early_late_binding.lp deleted file mode 100644 index a59a8fe..0000000 --- a/scripts/environment-tests/tests-early_late_binding.lp +++ /dev/null @@ -1,21 +0,0 @@ -%body - function(a). - function(b). - function(c). - function(d1). - function(d2). - - -scope(0..4). -cfa_parent(0, function(a)). -cfa_parent(1, function(b)). -cfa_parent(2, function(c)). -cfa_parent(3, function(d1)). -cfa_parent(4, function(d2)). - -cfa_call(0, function(c)). -cfa_call(1, function(c)). -cfa_call(2, function(d)). - -bind_scope(0, a). -bind_scope(1, b). \ No newline at end of file diff --git a/scripts/environment-tests/tests-context.lp b/scripts/metatests/(invalid)tests-context.lp similarity index 100% rename from scripts/environment-tests/tests-context.lp rename to scripts/metatests/(invalid)tests-context.lp diff --git a/scripts/metatests/context-latecontext-ContextLoopResolution-direct.lp b/scripts/metatests/context-latecontext-ContextLoopResolution-direct.lp new file mode 100644 index 0000000..8d1c8b6 --- /dev/null +++ b/scripts/metatests/context-latecontext-ContextLoopResolution-direct.lp @@ -0,0 +1 @@ + diff --git a/core/control-context.lp b/scripts/metatests/control-context-demandContext.lp similarity index 56% copy from core/control-context.lp copy to scripts/metatests/control-context-demandContext.lp index 1c27c0f..494ab0f 100644 --- a/core/control-context.lp +++ b/scripts/metatests/control-context-demandContext.lp @@ -1,27 +1,20 @@ -%TODO context-dependent function specialization implemenetation(inline/...) - % context propagation +bind_scope_demand(Scope, FnCallee):- cfa_call(Scope, FnCallee), cfa_function_specializations(FnCallee, Context), not bind_scope(Scope, Context). bind_scope_demand(Scope, Context):- bind_scope_demand(ScopeChild, Context), cfa_parent(ScopeChild, scope(Scope)). -bind_scope_demand(Scope, Context):- bind_function_demand(FnChild, Context), cfa_call(Scope, FnChild). -bind_function_demand(Fn, Context):- bind_scope_demand(ScopeChild, Context), cfa_parent(ScopeChild, function(Fn)). +bind_scope_demand(Scope, Context):- bind_function_demand(FnChild, Context), cfa_call(Scope, FnChild), not bind_scope(Scope, Context). + +bind_function_demand(Fn, Context):- bind_scope_demand(Scope, Context), cfa_parent(Scope, function(Fn)). bind_scope(Scope, Context) :- bind_scope(ScopeParent, Context), cfa_parent(Scope, scope(ScopeParent)). bind_scope(Scope, Context) :- bind_scope(ScopeParent, Context): cfa_call(ScopeParent, FnCurrent); cfa_call(_, FnCurrent) , cfa_parent(Scope, function(FnCurrent)), bind_scope(_, Context), scope(Scope). -bind_scope_weak(Scope, Context) :- bind_scope(Scope, Context), bind_scope_demand(Scope, Context). -bind_scope_weak(Scope, Context) :- cfa_parent(Scope, scope(ScopeParent)), bind_scope_weak(ScopeParent, Context), scope(Scope), scope(ScopeParent). -bind_scope_weak(Scope, Context) :- bind_scope_weak(ScopeParent, Context), - cfa_call(ScopeParent, FnCurrent), cfa_parent(Scope, function(FnCurrent)). - % adhoc classes(unfinished): -%bind_func(Fn, adhoc_class(Context)) := bind_func(Fn, adhoc(Context)), bind_scope(Scope, Context), cfa_parent(Scope, function(Fn)). +%bind_func(Fn, adhoc_class(Context)) :- bind_func(Fn, adhoc(Context)), bind_scope(Scope, Context), cfa_parent(Scope, function(Fn)). %scope_parent(Scope, ScopeParent) :- cfa_parent(Scope, scope(ScopeParent)). %scope_parent(Scope, ScopeParent2) :- cfa_parent(Scope, scope(ScopeParent)), scope_parent(ScopeParent, ScopeParent2). %scope_function(Scope, Fn) :- cfa_parent(Scope, function(Fn)). -%scope_function(Scope, Fn) :- cfa_parent(Scope, scope(ScopeParent)), scope_function(ScopeParent, Fn). - - +%scope_function(Scope, Fn) :- cfa_parent(Scope, scope(ScopeParent)), scope_function(ScopeParent, Fn). \ No newline at end of file diff --git a/scripts/metatests/tests-context-late_context.lp b/scripts/metatests/tests-context-late_context.lp new file mode 100644 index 0000000..536cdd3 --- /dev/null +++ b/scripts/metatests/tests-context-late_context.lp @@ -0,0 +1,26 @@ +#include "control-context.lp". + +%body +function(a;b;c;d). +scope(0..4). +cfa_parent(0, function(a)). +cfa_parent(1, function(b)). +cfa_parent(2, function(c)). +cfa_parent(3, function(d)). +cfa_parent(4, function(d)). + +cfa_call(0, c). +cfa_call(1, c). +cfa_call(2, d). + +bind_scope(0, a). +bind_scope(1, b). + +cfa_function_specializations(d, a). +cfa_function_specializations(d, b). + +#show bind_scope_decision/3. +%#show bind_scope_demand/2. +#show bind_function_demand/2. +%#show cfa_call/2. +%#show bind_function_demand/2. \ No newline at end of file diff --git a/scripts/environment-tests/control-context.lp b/scripts/sprint1_environment/control-context.lp similarity index 100% rename from scripts/environment-tests/control-context.lp rename to scripts/sprint1_environment/control-context.lp diff --git a/scripts/environment-tests/current b/scripts/sprint1_environment/current similarity index 100% rename from scripts/environment-tests/current rename to scripts/sprint1_environment/current diff --git a/core/dependencies.lp b/scripts/sprint1_environment/dependencies.lp similarity index 100% rename from core/dependencies.lp rename to scripts/sprint1_environment/dependencies.lp diff --git a/scripts/sprint1_environment/sprint1-Installation1.xreate b/scripts/sprint1_environment/sprint1-Installation1.xreate new file mode 120000 index 0000000..31eab23 --- /dev/null +++ b/scripts/sprint1_environment/sprint1-Installation1.xreate @@ -0,0 +1 @@ +/private/prg/code/xreate/scripts/testspass/sprint1-Installation1.xreate \ No newline at end of file diff --git a/scripts/environment-tests/xreate-environment b/scripts/sprint1_environment/xreate-environment similarity index 100% rename from scripts/environment-tests/xreate-environment rename to scripts/sprint1_environment/xreate-environment diff --git a/scripts/testspass/log.xreate b/scripts/testspass/log.xreate new file mode 100644 index 0000000..997edf1 --- /dev/null +++ b/scripts/testspass/log.xreate @@ -0,0 +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/testspass/sprint1-Installation1.xreate b/scripts/testspass/sprint1-Installation1.xreate new file mode 100644 index 0000000..e02797f --- /dev/null +++ b/scripts/testspass/sprint1-Installation1.xreate @@ -0,0 +1,100 @@ +import raw ("core/dependencies.lp") +import raw ("core/control-context.lp") +import raw ("core/unit-tests.lp") + +InstallationStatus = type variant(NOT_INSTALLED, INSTALLED). + +interface(adhoc){ + pre function expectNoErrors:: InstallationStatus { + case Error {NOT_INSTALLED} + case Success {INSTALLED} + } +} + +interface(extern-c){ + libFake = library:: pkgconfig("libxml-2.0"). + + include { + libFake = ["stdio.h", "stdlib.h"] + }. +} + +exec = pre function(comm:: string) { + result = system(comm):: num. + + if (result==0)::InstallationStatus + {ad hoc "Success"} + else {ad hoc "Error"} +} + +start = function:: int; entry { + context:: goal(artefact(gcc)). + + provideGoals() +} + +provideGoals = function:: int { + loop context ("goal") { + provideArtefact() + } +} + +provideArtefact = function:: int{ + switch (actionEXISTS())::int + + case INSTALLED {0} + + case NOT_INSTALLED { + sequence [ + provideDependencies(), + actionPROVIDE() + ] + } + + case default {-1} +} + +provideDependencies = function::int { + rule context:: childs(Child) + case artefact(Item) { + artefact_depends(Item, Child) + } + + loop context ("childs") { + provideArtefact() + } +} + +case context:: artefact(subversion) { + actionEXISTS = function::int { + context:: expectNoErrors. + + exec("svn --version") + } + + actionPROVIDE = function::int { + context:: expectNoErrors. + + exec("sudo apt-get install subversion") + } +} + +actionEXISTS = function::int { + -1 +} + +actionPROVIDE = function::int { + -1 +} + + +// DRAFT +/* + flagIsProvided = if(dictProvided()) {true} else + dictProvided = dictProvided + + +expectErrorCode = pre function(x::int){ + if (x==0)::bool {ad hoc "Success"} + else {ad hoc "Error"} +} +*/ diff --git a/scripts/xml/input.xreate b/scripts/testspass/xml-test1.xreate similarity index 100% rename from scripts/xml/input.xreate rename to scripts/testspass/xml-test1.xreate diff --git a/scripts/xml/xml-test1.xreate b/scripts/xml/xml-test1.xreate new file mode 120000 index 0000000..a65ed28 --- /dev/null +++ b/scripts/xml/xml-test1.xreate @@ -0,0 +1 @@ +/private/prg/code/xreate/scripts/testspass/xml-test1.xreate \ No newline at end of file