diff --git a/.gitignore b/.gitignore index 870c5b5..02054df 100644 --- a/.gitignore +++ b/.gitignore @@ -1,91 +1,82 @@ # Compiled Object files *.slo *.lo *.o *.obj # Compiled Dynamic libraries *.so *.so.* *.dylib *.dll # Compiled Static libraries *.lai *.la *.a *.lib # Executables *.exe *.out *.app *.class # Mobile Tools for Java (J2ME) .mtj.tmp/ # Package Files # *.jar *.war *.ear # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml hs_err_pid* # Qt-es /.qmake.cache /.qmake.stash *.pro.user *.pro.user.* *.moc moc_*.cpp qrc_*.cpp ui_*.h Makefile* *-build-* # QtCreator *.autosave coco/*.old coco/*~ *~ - cpp/build-*/* cpp/xreate-debug/* cpp/xreate-release/* cpp/.idea CMakeLists.txt.user cmake_install.cmake project/* nb*.xml .* target/* /tools/phabricator/xreate-frontend/nbproject/private/ documentation/trash4/ trash/ CMakeFiles/ gen-cpp/ generated-cpp/ gen-php/ generated-js/ books/ build/ coco/Parser.* coco/Scanner.* -cpp/src/compilation/latecontextcompiler.cpp -cpp/src/compilation/latecontextcompiler.h -cpp/src/pass/environmenttestspass.cpp -cpp/src/pass/environmenttestspass.h -cpp/src/query/ptrvalid.cpp -cpp/src/query/ptrvalid.h -cpp/tests/deferred/ -cpp/tests/vendorAPI/ - -scripts/metatests/ tools/phabricator/administration/ +**/tmp-* +cpp/tests/vendorsAPI/ diff --git a/coco/gen-grammar b/coco/gen-grammar deleted file mode 100755 index ed6c115..0000000 --- a/coco/gen-grammar +++ /dev/null @@ -1,6 +0,0 @@ -COCO_EXECUTABLE=${1:-cococpp} -COCO_FRAMES_PATH=${2:-/usr/share/coco-cpp/} - -echo "Run coco generator: " -$COCO_EXECUTABLE ./xreate.ATG -frames $COCO_FRAMES_PATH - diff --git a/coco/xreate.ATG b/coco/xreate.ATG deleted file mode 100644 index 61a41af..0000000 --- a/coco/xreate.ATG +++ /dev/null @@ -1,550 +0,0 @@ -//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 = "::". - lse = "<=". - lss = "<". - gte = ">=". - gtr = ">". - - ne1 = "!=". - ne2= "<>". - - -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 argName; TypeAnnotation typIn; TypeAnnotation typOut; bool flagIsPrefunct = false; Expression binding; .) -Ident assign -[pre (. flagIsPrefunct = true; .)] -function (. f = new Function(fname); f->isPrefunction = flagIsPrefunct; CodeScope* entry = f->getEntryScope(); .) - -['(' Ident tagcolon ExprAnnotations (. f->addBinding(Atom(argName), move(binding)); .) -{',' Ident tagcolon ExprAnnotations (. f->addBinding(Atom (argName), move(binding));.) -} ')'] - -[ tagcolon -( IF(flagIsPrefunct) FnTag - | Type (. f->setReturnType(typOut); .) -) -{';' FnTag }] -BDecl (. entry->getBody().bindType(move(typOut));.) -. - -ContextSection<>= (. Expression context; Function* f; .) -"case" "context" tagcolon MetaSimpExpr -lcurbrack { FDecl (. f->guardContext = context; root.add(f); .) -} rcurbrack. - - /** - * TYPES - * - */ -TypeTerm = (. std::wstring tid; .) - ("string" | "num" | "int" | "i8" | "i32" | "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;.) -Ident assign ExprTyped (. f->addDeclaration(Atom(vname), move(e)); .) -. - -ContextDecl = (. Expression tag; .) -context tagcolon -MetaSimpExpr (. scope->tags.push_back(tag); .) -{';' MetaSimpExpr (. scope->tags.push_back(tag); .) -}. - -//TODO forbid multiple body declaration (ExprTyped) -BDecl = '{' (. Expression body; 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)); .) -"if" '(' Expr ')' (. e = Expression(Operator::IF, {cond}); .) -tagcolon ExprAnnotations -BDecl<&*blockTrue> "else" BDecl<&*blockFalse> (. e.addBlock(blockTrue); e.addBlock(blockFalse); .) -. - -LoopDecl = - (. Expression eIn, eAcc, eFilters; std::wstring varEl, varAcc, contextClass; Expression tagsEl; - ManagedScpPtr block = root.add(new xreate::CodeScope(context.scope)); .) - "loop" - ("map" '(' Expr implic Ident (. e = Expression(Operator::MAP, {eIn}); .) - tagcolon ExprAnnotations ')' tagcolon ExprAnnotations BDecl<&*block> - (. - e.addBindings({Atom(varEl)}); - block->addBinding(Atom(varEl), move(tagsEl)); - e.addBlock(block); - .) - - |"fold" - ("inf" '(' Expr implic Ident ')' - (. - e = Expression(Operator::FOLD_INF, {eAcc}); - e.addBindings({Atom(varAcc)}); - .) - tagcolon ExprAnnotations BDecl<&*block> - (. - block->addBinding(Atom(varAcc), Expression()); - e.addBlock(block); - .) - - | '(' Expr implic Ident tagcolon ExprAnnotations ['|' Expr ] ',' Expr implic Ident')' - (. - e = Expression(Operator::FOLD, {eIn, eAcc}); - e.addBindings({Atom(varEl), Atom(varAcc)}); - .) - tagcolon ExprAnnotations BDecl<&*block> - (. - - block->addBinding(Atom(varEl), move(tagsEl)); - block->addBinding(Atom(varAcc), Expression()); - 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 ExprAnnotations (. eSwitch.operands.push_back(eCondition);.) - ) -] - 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 = (. 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 ===============================*/ -ExprAnnotations = (. TypeAnnotation typ; Expression tag; e.tags.clear();.) -Type (. e.bindType(move(typ)); .) - {';' MetaSimpExpr (. e.tags.emplace(tag.getValueString(), tag); .) - }. - -ExprTyped = Expr [tagcolon ExprAnnotations]. - -Expr< Expression& e> (. Operator op; Expression e2; .) -= SimExpr - [ RelOp -SimExpr (. 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; e = Expression(); .) -= - (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 */.) - | SequenceDecl - | LoopDecl - | IfDecl - | SwitchDecl - | AdhocDecl - - | number (. e = Expression(Atom(t->val)); .) - | string (. e = Expression(Atom(t->val)); .) - | '-' Factor< e> (. e = Expression(Operator::NEG, {e}); .) - | '(' ExprTyped ')' - ). - -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(Expression(val)); keys.push_back(Atom(key)); .) - } '}' (. e.addBindings(keys.begin(), keys.end()); .) - . - -ListLiteral = (. Expression eFrom, eTo; .) -'[' -[ Expr (. e.addArg(Expression(eFrom)); .) -(".." Expr (. e.addArg(Expression(eTo)); e.setOp(Operator::LIST_RANGE); .) - |{',' Expr (. e.addArg(Expression(eFrom)); .) -} (. e.setOp(Operator::LIST); .) -) ] ']'. - -AdhocDecl = (. Expression command; .) -"ad" "hoc" Expr (. e.setOp(Operator::ADHOC); e.addArg(std::move(command)); .). - -CalleeParams = (. Expression e2; .) - ExprTyped (. e.addArg(Expression(e2)); .) - {',' ExprTyped (. e.addArg(Expression(e2)); .) - }. - -AddOp< Operator& op> -= (. op = Operator::ADD; .) - ( '+' - | '-' (. op = Operator::SUB; .) - ). - -MulOp< Operator& op> -= (. op = Operator::MUL; .) - ( '*' - | '/' (. op = Operator::DIV; .) - ). - -RelOp< Operator& op> -= (. op = Operator::EQU; .) - ( equal - | (ne1 | ne2) (. op = Operator::NE; .) - - | lse (. op = Operator::LSE; .) - | lss (. op = Operator::LSS; .) - - | gte (. op = Operator::GTE; .) - | gtr (. op = Operator::GTR; .) - - ). - -END Xreate. diff --git a/config/default.json b/config/default.json index f72b68e..09f405f 100644 --- a/config/default.json +++ b/config/default.json @@ -1,73 +1,73 @@ { "containers": { "id": { - "implementations": "impl_fulfill_cluster", - "clusters": "var_cluster", - "prototypes": "proto_cluster", + "implementations": "containers_impl", "linkedlist": "linkedlist" }, "impl": { "solid": "solid", "onthefly": "on_the_fly" } }, "logging": { "id": "logging" }, "function-entry": "entry", - "clasp": { + "transcend": { "bindings" : { "variable": "bind", "function": "bind_func", "scope": "bind_scope", "function_demand" : "bind_function_demand", "scope_decision": "bind_scope_decision" }, "context" : { "decisions":{ "dependent": "resolution_dependency" - }, + } }, "nonevalue": "nonevalue", "ret": { "symbol": "retv", "tag": "ret" } }, "tests": { - "template": "containers", + "template": "troubleshooting", "templates": { - "default": "*-", - - "basic": "Basic.*", + "troubleshooting":"*", + "default": "*", "ast": "AST.*", + "effects": "Effects.*", + "basic": "Attachments.*", + "compilation": "Compilation.*", + "communication": "Communication.*", "cfa": "CFA.*", + "containers": "Containers.*", "dfa": "DFA.*", - "compilation": "Compilation.*", - "containers": "Containers.ListAsArray2-", "diagnostic": "Diagnostic.*", - "serializer": "ExpressionSerializer.*", - "externc": "InterfaceExternC.*", - "context": "ExpressionSerializer.*:Context.*", - "types": "Types.*-", - "log": "Logging*", - "clang": "ClangAPI.*", - "skip": "SkipDetection*:Adhoc_Loop_SkipDetection.*", - "raw-xml": "libxml2*", - "xml": "Xml.*", - "installation": "Compilation.*:Sprint1.*", + "dsl": "Association.*:Interpretation.*", "exploitation": "Exploitation.*", + "ExpressionSerializer": "ExpressionSerializer.*", + "externc": "InterfaceExternC.*", "loops": "Loop.*", - "dsl": "Interpretation.*", - "adhocs": "Adhoc.*", + "latereasoning": "LateReasoning.*", + "latex": "Latex.*", + "modules": "Modules.*", + "polymorphs": "Polymorphs.*", + "intrinsic-query": "Types.SlaveTypes*:Association.TypedQuery*", + "types": "Types.*", + "virtualization": "Virtualization.*", + "vendorsAPI/clang": "ClangAPI.*", + "vendorsAPI/xml2": "libxml2*" } } } diff --git a/core/aux/graphs_trees_depth.lp b/core/aux/graphs_trees_depth.lp deleted file mode 100644 index a322358..0000000 --- a/core/aux/graphs_trees_depth.lp +++ /dev/null @@ -1,2 +0,0 @@ -graphs_tree_depth(X, 0) :- not graphs_tree_depends(X, _); graphs_node(X). -graphs_tree_depth(X, LEVEL):- LEVEL = #max{L+1, graphs_tree_depth(Y, L): graphs_tree_depth(Y, L), graphs_tree_depends(X, Y)}; graphs_node(X); LEVEL > 0. \ No newline at end of file diff --git a/core/containers.lp b/core/containers.lp deleted file mode 100644 index 63b7269..0000000 --- a/core/containers.lp +++ /dev/null @@ -1,58 +0,0 @@ -%defines - impl(solid; on_the_fly; linked_list). - op(seqaccess; randaccess). - - relation(recommends; satisfied; unsupported). - relation_score(satisfied, 0). - relation_score(recommends, 1). - relation_score(unsupported, -1). - score(-1..1). - -%domain facts: - relation_op(seqaccess, on_the_fly, recommends). - - relation_op(randaccess, solid, recommends). - relation_op(randaccess, on_the_fly, unsupported). - -%dfa analysis: -%scheme: dfa_connection(Vto, Vfrom, proto); -%-- dfa_connection(VTo, VFrom, alias); -%-- dfa_connection(VFormal, VActual, arg); -%-- dfa_connection(VActual, VFormal, ret) - -%compilation: -%-- - -%domain rules: - %aliases: - var_origin(VAR) :- not dfa_connection(VAR, _, alias), v(VAR). - var_alias(VAR0, VAR_TO) :- dfa_connection(VAR_TO, VAR0, alias), var_origin(VAR0). - var_alias(VAR0, VAR_TO2) :- dfa_connection(VAR_TO2, VAR_TO1, alias), var_alias(VAR0, VAR_TO1). - var_alias(VAR0, VAR0):- var_origin(VAR0). - - %prototypes: - var_proto(V0, Vproto) :- var_origin(V0); var_origin(Vproto); var_alias(Vproto, Vp); dfa_connection(V0, Vp, proto). - - %implementations: - -impl_fulfill(OP, IMPL) :- relation_op(OP, IMPL, unsupported). - impl_fulfill(OP, IMPL, SCORE):- SCORE = #sum{SCORE1, (OP, IMPL, RL): relation_op(OP, IMPL, RL),relation_score(RL, SCORE1)} - ; op(OP); impl(IMPL); not -impl_fulfill(OP, IMPL). - - -var_impl_fulfill(Var0, Impl) :- var_alias(Var0, Var_Any); bind(Var_Any, op(Op)); -impl_fulfill(Op, Impl). - var_impl_fulfill(VAR0, IMPL, Score) :- - Score = #sum{SCORE, (OP, IMPL, VAR_ANY): impl_fulfill(OP, IMPL, SCORE), var_alias(VAR0, VAR_ANY), bind(VAR_ANY, op(OP))} - ; bind(VAR0, impl(IMPL)); var_origin(VAR0); not -var_impl_fulfill(VAR0, IMPL). - - %transfunction implementation: - %bind(Vactual, op(Op)) :- var_alias(Vformal, V1); bind(V1, op(Op)); dfa_connection(Vformal, Vactual, arg); op(Op). - - %bind(Vactual, op(Op)) :- var_alias(VO, Vformal); var_alias(VO, V); bind(V, op(Op)); dfa_connection(Vactual,Vformal, ret); op(Op). - % --uncomment to add possible implementations(impl) to an actual var - %bind(Vres, op(Op)) :- var_alias(VO, VA); bind(VA, op(Op)); dfa_connection(VArg,VO, result); op(Op). - -%optimization -% #maximize {SCORE, (VAR0, IMPL) : var_impl_fulfill(VAR0, IMPL, SCORE)}. - -#show var_alias/2. -#show var_impl_fulfill/3. -#show proto_alias2. diff --git a/core/control-context-v1.lp b/core/control-context-v1.lp deleted file mode 100644 index 62237fe..0000000 --- a/core/control-context-v1.lp +++ /dev/null @@ -1,24 +0,0 @@ - % context propagation - -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, _). - - %demand propagation -bind_scope_demand(Scope, Subject):- bind_scope_demand(ScopeChild, Subject), cfa_parent(ScopeChild, scope(Scope)). -bind_scope_demand(Scope, Subject):- cfa_call(Scope, FnChild), bind_function_demand(FnChild, Subject), not bind_scope_decision(Scope, Subject, _). -bind_function_demand(Fn, Subject):- bind_scope_demand(Scope, Subject), 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). - -% adhoc classes(unfinished): -%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). diff --git a/core/control-context-v3.lp b/core/control-context-v3.lp deleted file mode 100644 index 1b651f1..0000000 --- a/core/control-context-v3.lp +++ /dev/null @@ -1,52 +0,0 @@ - %% SCHEMA: - %% specialization(Fn, Scope) - problem of what specialization of Fn should be picked up in Scope. - %% resolution_dependency(Resolution, Dependency) - Dependency is necessary prerequisite for choosing Resolution. - %% - -true. - - %nested scope propagation: -bind_scope(Scope, Context, Info) :- bind_scope(ScopeParent, Context, Info), cfa_parent(Scope, scope(ScopeParent)). - - %strong/uniform inter-function propagation: -bind_scope(Scope, Context,Info) :- bind_scope(ScopeParent, Context, Info): cfa_call(ScopeParent, FnCurrent); cfa_parent(Scope, function(FnCurrent)); cfa_call(_, FnCurrent); bind_scope(_, Context, Info); scope(Scope). - - %weak inter-function propagation -bind_scope(Scope, Context, weak(ScopeParent)):- not bind_scope(Scope, Context, strong), bind_scope(ScopeParent, Context, strong), cfa_call(ScopeParent, FnCurrent), cfa_parent(Scope, function(FnCurrent)). -bind_scope(Scope, Context, weak(ScopeParent, Info)):- Info<>strong, not bind_scope(Scope, Context, Info), bind_scope(ScopeParent, Context, Info), cfa_call(ScopeParent, FnCurrent), cfa_parent(Scope, function(FnCurrent)). - - - %make decisions -%%%bind_scope_decision(Scope, loop(Subject), Scope):- cfa_contextloop(Scope, Subject), demand_dependency(loop(Subject), X), bind_scope(Scope, X, strong).* -%%%bind_scope_decision(Scope, loop(Subject), Scope):- cfa_call(Scope, FnChild), bind_function_demand(FnChild, loop(Subject)), demand_dependency(loop(Subject), X), bind_scope(Scope, X, strong). - - %on-site decision -% ASSERT: ON-SITE DECISION SHOULD BE FIRST CLASS (checks at least one specialization exists) -bind_scope_decision(Scope, Subject, Resolution):- bind_scope(Scope, Resolution, strong), Subject = specialization(Fn, Scope), cfa_call(Scope, Fn), cfa_function_specializations(Fn, Resolution). -bind_scope_decision(ScopeSource, Subject, Resolution):- bind_scope(Scope, Resolution, weak(ScopeSource)), Subject = specialization(Fn, Scope), cfa_call(Scope, Fn), cfa_function_specializations(Fn, Resolution). -bind_scope_decision(ScopeSource, Subject, resolution_dependency(Resolution, Dependency)):- bind_scope(Scope, Resolution, weak(ScopeSource, Dependency)), Subject = specialization(Fn, Scope), cfa_call(Scope, Fn), cfa_function_specializations(Fn, Resolution). - - %dependent decisions -bind_scope_demand(Scope, dependency(Subject, Scope)) :- bind_scope_decision(Scope, Subject, resolution_dependency(_, Dependency)). -bind_scope_demand(ScopeSource, dependency(Subject, ScopeSource)) :- Dependency = weak(ScopeSource, DependencyTail), bind_scope_demand(Scope, dependency(Subject, Scope)), scope_dependencies(dependency(Subject, Scope), Dependency). - -bind_scope_decision(ScopeSource, dependency(Subject, Scope), Dependency) :- Dependency = weak(ScopeSource), bind_scope_demand(Scope, dependency(Subject, Scope)), scope_dependencies(dependency(Subject, Scope), Dependency). -bind_scope_decision(ScopeSource, dependency(Subject, Scope), resolution_dependency(Dependency, DependencyTail)) :- Dependency = weak(ScopeSource, DependencyTail), bind_scope_demand(Scope, dependency(Subject, Scope)), scope_dependencies(dependency(Subject, Scope), Dependency). - - - %dependent decision helpers: -scope_dependencies(dependency(Subject, Scope), Dependency) :- bind_scope_decision(Scope, Subject, resolution_dependency(_, Dependency)). -scope_dependencies(dependency(Subject, ScopeSource), DependencyTail) :- Dependency = weak(ScopeSource, DependencyTail), bind_scope_demand(Scope, dependency(Subject, Scope)), scope_dependencies(dependency(Subject, Scope), Dependency). - - %on-site demand -% ASSERT: ON-SITE DEMAND SHOULD BE dependent OF on-site decision (check there are no specializations AT ALL) -%%%bind_scope_demand(Scope, Subject):- cfa_contextloop(Scope, Subject), not bind_scope_decision(Scope, loop(Subject), _). -bind_scope_demand(Scope, Subject):- Subject = specialization(FnCallee, Scope), cfa_call(Scope, FnCallee), cfa_function_specializations(FnCallee, _), not bind_scope_decision(Scope, Subject, _). - - %nested scope demand propagation -%ASSERT: NO DECISION CHECKS. because decisions linked to a leaf(function execution sites) scopes -bind_scope_demand(Scope, Subject):- bind_scope_demand(ScopeChild, Subject), cfa_parent(ScopeChild, scope(Scope)). -bind_function_demand(Fn, Subject):- bind_scope_demand(Scope, Subject), cfa_parent(Scope, function(Fn)). - - %inter-function propagation demand -bind_scope_demand(Scope, Subject):- cfa_call(Scope, FnChild), bind_function_demand(FnChild, Subject), not bind_scope_decision(Scope, Subject, _). diff --git a/core/control-context.lp b/core/control-context.lp deleted file mode 120000 index f0191b9..0000000 --- a/core/control-context.lp +++ /dev/null @@ -1 +0,0 @@ -/private/prg/code/xreate/core/control-context-v3.lp \ No newline at end of file diff --git a/core/dominators.lp b/core/dominators.lp deleted file mode 100644 index e69de29..0000000 diff --git a/core/exploitation.lp b/core/exploitation.lp deleted file mode 100644 index 20f47d5..0000000 --- a/core/exploitation.lp +++ /dev/null @@ -1,12 +0,0 @@ -expl_sites(Data, Site) :- S=(_, Site); bind(S, exploitation_initialized(file)); bind(S, static(data(Data))). -expl_sites(Data, Site) :- S=(_, Site); bind(S, exploitation_initialized(file)); bind(S, static(ref(Root))); bind(Root, static(data(Data))). - - -expl_parent(Site, dom(Parent)) :- cfa_forwdom(Parent, range(A, B)); cfa_forwdom(Site, range(A1, B1)); A + * + * \file ExternLayer.h + * \brief Support of external C code. Wrapper over Clang + */ #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 "clang/Lex/PreprocessorOptions.h" +#include "clang/CodeGen/ModuleBuilder.h" +#include "clang/CodeGen/CodeGenABITypes.h" #include #include #include +#include +#include +#include -#include "../../vendors/clang-codegen-private-3.8/CodeGenModule.h" - -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; +namespace xreate{ -class FinderCallbackTypeDecl : public MatchFinder::MatchCallback { -public : +class FinderCallbackTypeDecl : public MatchFinder::MatchCallback{ +public: QualType typeResult; - virtual void run(const MatchFinder::MatchResult &Result) { - if (const TypedefDecl* decl = Result.Nodes.getNodeAs("typename")) { + virtual void + run(const MatchFinder::MatchResult &Result) { + if (const TypedefDecl * decl = Result.Nodes.getNodeAs("typename")) { typeResult = decl->getUnderlyingType(); } } -}; +} ; -class FinderCallbackFunction : public MatchFinder::MatchCallback { -public : +class FinderCallbackFunction : public MatchFinder::MatchCallback{ +public: QualType typeResult; - virtual void run(const MatchFinder::MatchResult &Result) { - if (const FunctionDecl* decl = Result.Nodes.getNodeAs("function")) { + virtual void + run(const MatchFinder::MatchResult &Result) { + if (const FunctionDecl * decl = Result.Nodes.getNodeAs("function")) { typeResult = decl->getType(); } } -}; +} ; void -ExternData::addLibrary(Atom&& name, Atom&& package) -{ +ExternData::addLibrary(Atom&& name, Atom&& package) { __dictLibraries.emplace(name.get(), package.get()); } void -ExternData::addIncludeDecl(Expression&& e) -{ +ExternData::addIncludeDecl(Expression&& e) { assert(e.op == Operator::LIST_NAMED); - //TODO ?? implement Expression parsing(Array of Expr as vector); - for(size_t i=0, size=e.operands.size(); i); + for(size_t i = 0, size = e.operands.size(); i < size; ++i) { std::string library = e.bindings.at(i); assert(__dictLibraries.count(library)); std::string package = __dictLibraries.at(library); Expression listHeaders = e.operands.at(i); assert(listHeaders.op == Operator::LIST); std::vector headers; std::transform(listHeaders.operands.begin(), listHeaders.operands.end(), std::inserter(headers, headers.end()), - [](const Expression& o){ - assert(o.__state == Expression::STRING); - return o.getValueString(); - }); + [](const Expression & o) { + assert(o.__state == Expression::STRING); + return o.getValueString(); + }); entries.emplace_back(ExternEntry{package, std::move(headers)}); } } void -ExternLayer::addExternalData(const std::vector& data){ +ExternLayer::addExternalData(const std::vector& data) { entries.insert(entries.end(), data.begin(), data.end()); } ExternLayer::ExternLayer(LLVMLayer *llvm) - : __llvm(llvm) -{} - +: __llvm(llvm) { } std::vector -ExternLayer::fetchPackageFlags(const ExternEntry& entry){ +ExternLayer::fetchPackageFlags(const ExternEntry& entry) { std::vector args; FILE* flags = popen((string("pkg-config --cflags ") + entry.package).c_str(), "r"); - size_t linesize=0; - char* linebuf=0; - ssize_t linelen=0; - while ((linelen=getdelim(&linebuf, &linesize, ' ', flags))>0) { - if (linebuf[0]=='\n') continue; - if (linelen==1 && linebuf[0]==' ') continue; - - //cut unwanted symbols at the end - char symbLast = linebuf[linelen-1 ]; - if (symbLast == ' ' || symbLast == '\n') linebuf[linelen-1] = 0; - - //print header for debug purposes + size_t linesize = 0; + char* linebuf = 0; + ssize_t linelen = 0; + while ((linelen = getdelim(&linebuf, &linesize, ' ', flags)) > 0) { + if (linebuf[0] == '\n') continue; + if (linelen == 1 && linebuf[0] == ' ') continue; + + //cut unwanted symbols at the end + char symbLast = linebuf[linelen - 1 ]; + if (symbLast == ' ' || symbLast == '\n') linebuf[linelen - 1] = 0; + + //print header for debug purposes llvm::outs() << '<' << linebuf << "> "; args.push_back(linebuf); free(linebuf); linebuf = 0; } pclose(flags); return (args); } std::vector -ExternLayer::fetchPackageLibs(const ExternEntry& entry){ - std::vector libs; - - FILE* flags = popen((string("pkg-config --libs ") + entry.package).c_str(), "r"); - size_t linesize=0; - char* linebuf=0; - ssize_t linelen=0; - while ((linelen=getdelim(&linebuf, &linesize, ' ', flags))>0) { - if (linebuf[0]=='\n') continue; - if (linelen==1 && linebuf[0]==' ') continue; - - //cut unwanted symbols at the end - char symbLast = linebuf[linelen-1 ]; - if (symbLast == ' ' || symbLast == '\n') linebuf[linelen-1] = 0; - - //cut unwanted symbols at the beginning - if (linelen>1 && linebuf[0] == '-' && linebuf[1] == 'l'){ - libs.push_back(linebuf + 2); - - } else { - libs.push_back(linebuf); - } - - //print lib name for debug purposes - llvm::outs() << '<' << linebuf << "> "; - free(linebuf); - linebuf = 0; - } - - pclose(flags); - return (libs); +ExternLayer::fetchPackageLibs(const ExternEntry& entry) { + std::vector libs; + + FILE* flags = popen((string("pkg-config --libs ") + entry.package).c_str(), "r"); + size_t linesize = 0; + char* linebuf = 0; + ssize_t linelen = 0; + while ((linelen = getdelim(&linebuf, &linesize, ' ', flags)) > 0) { + if (linebuf[0] == '\n') continue; + if (linelen == 1 && linebuf[0] == ' ') continue; + + //cut unwanted symbols at the end + char symbLast = linebuf[linelen - 1 ]; + if (symbLast == ' ' || symbLast == '\n') linebuf[linelen - 1] = 0; + + //cut unwanted symbols at the beginning + if (linelen > 1 && linebuf[0] == '-' && linebuf[1] == 'l') { + libs.push_back(linebuf + 2); + + } else { + libs.push_back(linebuf); + } + + //print lib name for debug purposes + llvm::outs() << '<' << linebuf << "> "; + free(linebuf); + linebuf = 0; + } + + pclose(flags); + return (libs); } void -ExternLayer::loadLibraries(vector&& libs){ - string msgErr; - for (const string& lib: libs) { - const string& libName = string("lib")+lib+".so"; - if (!llvm::sys::DynamicLibrary::LoadLibraryPermanently(libName.c_str(), &msgErr)){ - llvm::errs()<<"\n"<<"Loading library "<&& libs) { + string msgErr; + for (const string& lib : libs) { + const string& libName = string("lib") + lib + ".so"; + if (!llvm::sys::DynamicLibrary::LoadLibraryPermanently(libName.c_str(), &msgErr)) { + llvm::errs() << "\n" << "Loading library " << lib << ". " << msgErr << "\n"; + } } } void ExternLayer::init(const AST* root) { addExternalData(root->__externdata); - // TODO -EXTERN01.DIP, use default include path from 'clang -xc++ -E' + // TODO -EXTERN01.DIP, use default include path from 'clang -xc++ -E' list code; std::vector args{ "-I/usr/include" - ,"-I/usr/local/include" - ,"-I/usr/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" + , "-I/usr/local/include" + , "-I/usr/lib64/clang/5.0.1/include" + // ,"-I/usr/lib/gcc/x86_64-linux-gnu/4.9/include" + // ,"-I/usr/include/x86_64-linux-gnu" }; std::vector libs; boost::format formatInclude("#include \"%1%\""); - for(const ExternEntry& entry: entries) - { - llvm::outs()<<"[ExternC] Processing package: "<< entry.package << "\n"; - llvm::outs()<<"[ExternC] args: "; + for(const ExternEntry& entry : entries) { + llvm::outs() << "[ExternC] Processing package: " << entry.package << "\n"; + llvm::outs() << "[ExternC] args: "; vector&& args2 = fetchPackageFlags(entry); args.insert(args.end(), args2.begin(), args2.end()); - for(const string arg: args2) { - llvm::outs()<< "<" << arg << "> "; + for(const string arg : args2) { + llvm::outs() << "<" << arg << "> "; } - llvm::outs()<<"\n[ExternC] libs: "; + llvm::outs() << "\n[ExternC] libs: "; args2 = fetchPackageLibs(entry); - for(const string arg: args2) { - llvm::outs()<< "<" << arg << "> "; + for(const string arg : args2) { + llvm::outs() << "<" << arg << "> "; } libs.insert(libs.end(), args2.begin(), args2.end()); - llvm::outs()<<"\n[ExternC] headers: "; + llvm::outs() << "\n[ExternC] headers: "; std::transform(entry.headers.begin(), entry.headers.end(), std::inserter(code, code.begin()), [&formatInclude](const string header ) { string line = boost::str(formatInclude % header); - llvm::outs()<< "<" << line << "> "; + llvm::outs() << "<" << line << "> "; return line; - }); + }); llvm::outs() << '\n'; } loadLibraries(move(libs)); ast = buildASTFromCodeWithArgs(boost::algorithm::join(code, "\n"), args); - __cgo.reset(new CodeGenOptions); - __llvm->module->setDataLayout(ast->getASTContext().getTargetInfo().getDataLayoutString()); - - std::unique_ptr __hso(new HeaderSearchOptions()); - std::unique_ptr __ppo(new PreprocessorOptions()); - - __cgm.reset(new CodeGen::CodeGenModule( - ast->getASTContext(), - - *__hso, - *__ppo, - *__cgo, - *__llvm->module, - ast->getASTContext().getDiagnostics())); + __llvm->module->setDataLayout(ast->getASTContext().getTargetInfo().getDataLayout()); + __clang.reset(new CompilerInstance()); + __clang->createDiagnostics(); + + __codegen.reset(CreateLLVMCodeGen( + __clang->getDiagnostics(), + __llvm->module->getName(), + __clang->getHeaderSearchOpts(), + __clang->getPreprocessorOpts(), + clang::CodeGenOptions(), + __llvm->llvmContext + )); + + __codegen->Initialize(ast->getASTContext()); }; - - bool ExternLayer::isPointer(const clang::QualType &t) { const clang::Type * tInfo = t.getTypePtr(); assert(tInfo); return tInfo->isAnyPointerType(); } llvm::Type* -ExternLayer::toLLVMType(const clang::QualType& t){ - return __cgm->getTypes().ConvertType(t); +ExternLayer::toLLVMType(const clang::QualType& t) { + return CodeGen::convertTypeForMemory( __codegen->CGM(), t); } std::vector -ExternLayer::getStructFields(const clang::QualType& ty) -{ +ExternLayer::getStructFields(const clang::QualType& ty) { clang::QualType t = ty; - if (isPointer(ty)){ + if (isPointer(ty)) { const clang::PointerType* tPtr = ty->getAs(); t = tPtr->getPointeeType(); } assert(t.getTypePtr()->isRecordType()); const RecordType *record = t->getAsStructureType(); assert(record); std::vector result; //FieldDecl* field: record->getDecl()->fields() - for (auto i=record->getDecl()->field_begin(); i!= record->getDecl()->field_end(); ++i){ + for (auto i = record->getDecl()->field_begin(); i != record->getDecl()->field_end(); ++i) { result.push_back(i->getName()); } return result; } clang::QualType -ExternLayer::lookupType(const std::string& id){ +ExternLayer::lookupType(const std::string& id) { MatchFinder finder; FinderCallbackTypeDecl callbackTypeDecl; auto matcherTypeDecl = typedefDecl(hasName(id)).bind("typename"); finder.addMatcher(matcherTypeDecl, &callbackTypeDecl); finder.matchAST(ast->getASTContext()); assert(! callbackTypeDecl.typeResult.isNull()); return callbackTypeDecl.typeResult; } - llvm::Function* -ExternLayer::lookupFunction(const std::string& name){ - if (__functions.count(name)){ - return __functions.at(name); - } +ExternLayer::lookupFunction(const std::string& name) { + if (__functions.count(name)) { + return __functions.at(name); + } MatchFinder finder; FinderCallbackFunction callback; auto matcher = functionDecl(hasName(name)).bind("function"); finder.addMatcher(matcher, &callback); finder.matchAST(ast->getASTContext()); - if (callback.typeResult.isNull()){ - cout <<"[External Layer] " << "Unknown function: "<getTypes().ConvertType(tyFuncQual); + llvm::Type *tyRaw = CodeGen::convertTypeForMemory(__codegen->CGM(), tyFuncQual); llvm::FunctionType* tyRawFunc = llvm::dyn_cast(tyRaw); - llvm::Function* function = llvm::Function::Create(tyRawFunc, llvm::GlobalValue::ExternalLinkage, name, __llvm->module); + llvm::Function* function = llvm::Function::Create( + tyRawFunc, + llvm::GlobalValue::ExternalLinkage, + name, + __llvm->module.get()); __functions.emplace(name, function); return function; } +}//end of xreate namespace diff --git a/cpp/src/ExternLayer.h b/cpp/src/ExternLayer.h index a126843..49fe4b3 100644 --- a/cpp/src/ExternLayer.h +++ b/cpp/src/ExternLayer.h @@ -1,54 +1,65 @@ -// -// Created by pgess on 4/21/15. -// +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * ExternLayer.h + * + * Created on: 4/21/15 + * Author: pgess + */ #ifndef XREATE_EXTERNLAYER_H #define XREATE_EXTERNLAYER_H #include "llvmlayer.h" #include #include #include #include "ast.h" #include "clang/AST/ASTContext.h" #include "clang/Frontend/ASTUnit.h" #include "clang/Frontend/CodeGenOptions.h" #include "clang/CodeGen/CodeGenABITypes.h" +#include "clang/Lex/PreprocessorOptions.h" -namespace xreate { - struct ExternData { - void addLibrary(Atom&& name, Atom&& package); - void addIncludeDecl(Expression&& e); - - std::vector entries; - std::map __dictLibraries; - }; - - class ExternLayer { - public: - ExternLayer(LLVMLayer* llvm); - - llvm::Function* lookupFunction(const std::string& name); - clang::QualType lookupType(const std::string& id); - std::vector getStructFields(const clang::QualType& ty); - - llvm::Type* toLLVMType(const clang::QualType& t); - bool isPointer(const clang::QualType& t); - - void init(const AST* root); - static std::vector fetchPackageFlags(const ExternEntry& entry); - static std::vector fetchPackageLibs(const ExternEntry& entry); - private: - - std::unique_ptr ast; - std::unique_ptr __cgm; - std::unique_ptr __cgo; - LLVMLayer* __llvm; - std::vector entries; - std::map __functions; - - void addExternalData(const std::vector& data); - void loadLibraries(std::vector&& libs); - }; +namespace clang{ +class CodeGenerator; +} + +namespace xreate{ + +struct ExternData{ + void addLibrary(Atom&& name, Atom&& package); + void addIncludeDecl(Expression&& e); + + std::vector entries; + std::map __dictLibraries; +}; + +class ExternLayer{ +public: + ExternLayer(LLVMLayer* llvm); + void init(const AST* root); + + llvm::Function* lookupFunction(const std::string& name); + clang::QualType lookupType(const std::string& id); + std::vector getStructFields(const clang::QualType& ty); + llvm::Type* toLLVMType(const clang::QualType& t); + bool isPointer(const clang::QualType& t); + + static std::vector fetchPackageFlags(const ExternEntry& entry); + static std::vector fetchPackageLibs(const ExternEntry& entry); + +private: + std::unique_ptr ast; + std::unique_ptr __codegen; + std::unique_ptr __clang; + LLVMLayer* __llvm; + std::vector entries; + std::map __functions; + + void addExternalData(const std::vector& data); + void loadLibraries(std::vector&& libs); +}; } #endif //XREATE_EXTERNLAYER_H diff --git a/cpp/src/analysis/DominatorsAnalysisProvider.cpp b/cpp/src/analysis/DominatorsAnalysisProvider.cpp new file mode 100644 index 0000000..69f4b71 --- /dev/null +++ b/cpp/src/analysis/DominatorsAnalysisProvider.cpp @@ -0,0 +1,274 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * File: DominatorsAnalysisProvider.cpp + * Author: pgess + * + * Created on May 13, 2016, 11:39 AM + */ + +/** + * \file DominatorsAnalysisProvider.h + * \brief Dominators Tree analysis + */ + +#include "analysis/cfagraph.h" +#include "analysis/DominatorsAnalysisProvider.h" + +#include "llvm/ADT/GraphTraits.h" +#include "llvm/Support/GenericDomTreeConstruction.h" +#include "llvm/Support/GenericDomTree.h" + +#include +#include +#include + +using namespace std; +using namespace xreate; +using namespace boost; +using namespace boost::bimaps; + +namespace xreate { namespace dominators { + +struct CFAGraphAdapter; + +struct ScopeNode { + ScopePacked id; + CFAGraphAdapter* parent; + std::list nodesFrom; + std::list nodesTo; + + CFAGraphAdapter* getParent(){ return parent; } + void printAsOperand(llvm::raw_ostream&, bool) {} + ScopeNode(ScopePacked scope, CFAGraphAdapter* parentAdapter): + id(scope), parent(parentAdapter) {} +}; + +} +} //end of namespace xreate::dominators + +namespace llvm { +using namespace xreate::dominators; + +template<> +struct GraphTraits { + typedef ScopeNode* NodeRef; + typedef std::list::iterator ChildIteratorType; + + static ChildIteratorType + child_begin(ScopeNode* node) { + return node->nodesTo.begin(); + } + + static ChildIteratorType + child_end(ScopeNode* node) { + return node->nodesTo.end(); + } +}; + +template<> +struct GraphTraits> +{ + typedef ScopeNode* NodeRef; + typedef std::list::iterator ChildIteratorType; + + static ChildIteratorType + child_begin(ScopeNode* node) { + return node->nodesFrom.begin(); + } + + static ChildIteratorType + child_end(ScopeNode* node) { + return node->nodesFrom.end(); + } +}; + +template<> +struct GraphTraits { + typedef std::list::iterator nodes_iterator; + + static nodes_iterator + nodes_begin(CFAGraphAdapter* graph) { + return graph->nodes.begin(); + } + + static nodes_iterator + nodes_end(CFAGraphAdapter* graph) { + return graph->nodes.end(); + } + + static ScopeNode* + getEntryNode(CFAGraphAdapter* F) { + return F->nodeRoot; + } + + static unsigned int + size(CFAGraphAdapter* graph) { + return graph->nodes.size(); + } +}; +} + +namespace xreate { +namespace dominators { + +class DominatorTree : public llvm::DominatorTreeBase { +friend class DominatorsAnalysisProvider; +public: + DominatorTree() : llvm::DominatorTreeBase() {} + + void + run(CFAGraphAdapter& program) { + recalculate(program); + updateDFSNumbers(); + + //extract dominators info + for(auto& entry : DomTreeNodes) { + if(!entry.getFirst()) continue; + + dominators.emplace(entry.getFirst()->id, make_pair(entry.getSecond()->getDFSNumIn(), entry.getSecond()->getDFSNumOut())); + } + } + + void + print(std::ostringstream& output, const std::string& atom) const { + boost::format formatAtom(atom+"(%1%, range(%2%, %3%))."); + + for(auto entry : dominators) { + output< { +friend class DominatorsAnalysisProvider; +public: + PostDominatorTree() : llvm::DominatorTreeBase() {} + + void + run(CFAGraphAdapter& program) { + recalculate(program); + updateDFSNumbers(); + //extract dominators info + for(auto& entry : DomTreeNodes) { + if(!entry.getFirst()) continue; + + dominators.emplace(entry.getFirst()->id, make_pair(entry.getSecond()->getDFSNumIn(), entry.getSecond()->getDFSNumOut())); + } + } + + void + print(std::ostringstream& output, const std::string& atom) const { + boost::format formatAtom(atom+"(%1%, range(%2%, %3%))."); + + for(auto entry : dominators) { + output<id < b->id;}; + auto posLowerBound = std::lower_bound(nodes.begin(), nodes.end(), &elemNew, fnComp); + + if(posLowerBound==nodes.end()|| (*posLowerBound)->id > scope){ + ScopeNode* elemNewP = new ScopeNode(elemNew); + *elemNewP = elemNew; + return *nodes.insert(posLowerBound, elemNewP); + } + + return *posLowerBound; +} + +CFAGraphAdapter* +CFAGraphAdapter::build(const cfa::CFAGraph* graph) { + return build(graph->__dependencyRelations); +} + +CFAGraphAdapter* +CFAGraphAdapter::build(const std::multimap& dataScopesOrder){ + CFAGraphAdapter* tree=new CFAGraphAdapter(); + + enum NODE_MARK{NO_ROOT, POSSIBLE_ROOT}; + std::unordered_map nodeMarks; + for (const auto& edge: dataScopesOrder){ + + ScopeNode* nodeTo = tree->registerScope(edge.first); + ScopeNode* nodeFrom = tree->registerScope(edge.second); + nodeTo->nodesFrom.push_back(nodeFrom); + nodeFrom->nodesTo.push_back(nodeTo); + + nodeMarks.emplace(edge.second, POSSIBLE_ROOT); //weak optional insert + auto result = nodeMarks.emplace(edge.first, NO_ROOT); //strong insert or update + if(!result.second){ + result.first->second = NO_ROOT; + } + } + + std::list nodeRoots; + for(auto nodeMark: nodeMarks){ + if(nodeMark.second == POSSIBLE_ROOT) nodeRoots.push_back(nodeMark.first); + } + + if(nodeRoots.size()>1){ + ScopeNode* nodeGlobalRoot = tree->registerScope(SCOPE_ABSTRACT_GLOBAL); + for(auto rootLocal: nodeRoots){ + ScopeNode* nodeLocalRoot = tree->registerScope(rootLocal); + nodeLocalRoot->nodesFrom.push_back(nodeGlobalRoot); + nodeGlobalRoot->nodesTo.push_back(nodeLocalRoot); + } + + tree->nodeRoot = nodeGlobalRoot; + + } else if (nodeRoots.size()==1){ + tree->nodeRoot = tree->registerScope(nodeRoots.front()); + + } else { + ScopeNode* nodeGlobalRoot = tree->registerScope(SCOPE_ABSTRACT_GLOBAL); + tree->nodeRoot = nodeGlobalRoot; + } + + return tree; +} + +void +DominatorsAnalysisProvider::run(CFAGraphAdapter* program) { + treeForwardDominators.reset(new DominatorTree()); + treePostDominators.reset(new PostDominatorTree()); + + treeForwardDominators->run(*program); + treePostDominators->run(*program); +} + +void +DominatorsAnalysisProvider::print(std::ostringstream& output) const { + treeForwardDominators->print(output, "cfa_forwdom"); + treePostDominators->print(output, "cfa_postdom"); +} + +const DominatorsAnalysisProvider::Dominators& +DominatorsAnalysisProvider::getForwardDominators() const { + return treeForwardDominators->dominators; +} + +const DominatorsAnalysisProvider::Dominators& +DominatorsAnalysisProvider::getPostDominators() const { + return treePostDominators->dominators; +} + +DominatorsAnalysisProvider::DominatorsAnalysisProvider() {} +DominatorsAnalysisProvider::~DominatorsAnalysisProvider() { } + + +}} //end of namespace xreate::dominators diff --git a/cpp/src/analysis/DominatorsAnalysisProvider.h b/cpp/src/analysis/DominatorsAnalysisProvider.h new file mode 100644 index 0000000..a7124cc --- /dev/null +++ b/cpp/src/analysis/DominatorsAnalysisProvider.h @@ -0,0 +1,56 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * File: DominatorsAnalysisProvider.h + * Author: pgess + * + * Created on May 13, 2016, 11:39 AM + */ + +#ifndef DominatorsAnalysisProvider_H +#define DominatorsAnalysisProvider_H + +#include "transcendlayer.h" +#include + +namespace xreate{namespace dominators{ + +class DominatorTree; +class PostDominatorTree; +class ScopeNode; + +struct CFAGraphAdapter { + std::list nodes; + ScopeNode* nodeRoot; + + ScopeNode* registerScope(ScopePacked scope); + static CFAGraphAdapter* build(const cfa::CFAGraph* graph); + static CFAGraphAdapter* build(const std::multimap& dataScopesOrder); + CFAGraphAdapter() { } +}; + +/** \brief Dominators Analysis report */ +class DominatorsAnalysisProvider: public IAnalysisReport { +public: + typedef std::pair DominatedRange; + typedef std::map Dominators; + + DominatorsAnalysisProvider(); + virtual ~DominatorsAnalysisProvider(); + + void run(CFAGraphAdapter* program); + void print(std::ostringstream& output) const override; + + const Dominators& getForwardDominators() const; + const Dominators& getPostDominators() const; + +private: + boost::shared_ptr treeForwardDominators; + boost::shared_ptr treePostDominators; +}; + +}} //end of namespace xreate::dominators + +#endif /* DominatorsAnalysisProvider_H */ + diff --git a/cpp/src/analysis/DominatorsTreeAnalysisProvider.cpp b/cpp/src/analysis/DominatorsTreeAnalysisProvider.cpp deleted file mode 100644 index 9bd280d..0000000 --- a/cpp/src/analysis/DominatorsTreeAnalysisProvider.cpp +++ /dev/null @@ -1,233 +0,0 @@ -/* - * To change this license header, choose License Headers in Project Properties. - * To change this template file, choose Tools | Templates - * and open the template in the editor. - */ - -/* - * File: DominatorsTreeAnalysisProvider.cpp - * Author: pgess - * - * Created on May 13, 2016, 11:39 AM - */ - -#include "analysis/cfagraph.h" -#include "analysis/DominatorsTreeAnalysisProvider.h" - -#include "llvm/ADT/GraphTraits.h" -#include "llvm/Support/GenericDomTreeConstruction.h" -#include "llvm/Support/GenericDomTree.h" - -#include -#include -#include - -using namespace std; -using namespace xreate; -using namespace boost; -using namespace boost::bimaps; - -struct ControlFlowTree; - -struct Node { - ScopePacked scope; - ControlFlowTree* tree; -}; - -/* -bool operator !=(const Node& a, const Node& b){ - return (a.tree != b.tree) || (a.scope != b.scope); -} - -Node& operator++(Node& a){ - ++a.scope; - return a; -} - */ - -struct ControlFlowTree{ - typedef bimap, multiset_of> CHILD_RELATIONS; - CHILD_RELATIONS edges; - std::vector nodes; - Node* entry = nullptr; - size_t size; - - ControlFlowTree(const size_t nodesCount): nodes(nodesCount), size(nodesCount){ - } - - static ControlFlowTree* build(const ClaspLayer* engine){ - ControlFlowTree* tree = new ControlFlowTree(engine->getScopesCount()); - - xreate::analysis::CFAGraph* graph = engine->dataCFA.get(); - - for (const auto& edge: graph->__parentScopeRelations){ - tree->edges.insert(CHILD_RELATIONS::value_type(edge.second, edge.first)); - } - - for (const auto& edge: graph->__callRelations){ - unsigned int calleeFunction = edge.right; - ScopePacked caller = edge.left; - - auto range = graph->__parentFunctionRelations.right.equal_range(calleeFunction); - for (auto& i=range.first; i!= range.second; ++i){ - tree->edges.insert(CHILD_RELATIONS::value_type(caller, i->second)); - } - } - - for (size_t i=0; isize; ++i){ - tree->nodes[i]= Node{(unsigned int) i, tree}; - } - - return tree; - } - - std::list getRootFunctions() const{ - size_t idMax = size; - size_t id =0; - std::list results; - auto i = edges.right.begin(); - - while (id < idMax) { - if (i!= edges.right.end() && i->first == id){ - i = edges.right.upper_bound(i->first); - - } else { - results.push_back(id); - } - - ++id; - } - - return std::move(results); - } -}; - -namespace llvm { - template <> struct GraphTraits { - typedef Node* nodes_iterator; - typedef Node NodeType; - - typedef std::function Transformer; - typedef typename boost::transform_iterator ChildIteratorType; - - static ChildIteratorType child_begin(const nodes_iterator& node) { - auto range = node->tree->edges.left.equal_range(node->scope); - Transformer x = [node](auto edge){return &node->tree->nodes[edge.second];}; - - return boost::make_transform_iterator(range.first, x); - } - - static ChildIteratorType child_end(const nodes_iterator& node) { - auto range = node->tree->edges.left.equal_range(node->scope); - Transformer x = [node](auto edge){return &node->tree->nodes[edge.second];}; - - return boost::make_transform_iterator(range.second, x); - } - }; - - template <> struct GraphTraits> { - typedef Node* nodes_iterator; - typedef Node NodeType; - - typedef std::function Transformer; - typedef typename boost::transform_iterator ChildIteratorType; - - static ChildIteratorType child_begin(const nodes_iterator& node) { - auto range = node->tree->edges.right.equal_range(node->scope); - Transformer x = [node](auto edge){return &node->tree->nodes[edge.second];}; - - return boost::make_transform_iterator(range.first, x); - } - - static ChildIteratorType child_end(const nodes_iterator& node) { - auto range = node->tree->edges.right.equal_range(node->scope); - Transformer x = [node](auto edge){return &node->tree->nodes[edge.second];}; - - return boost::make_transform_iterator(range.second, x); - } - }; - - template <> struct GraphTraits: public GraphTraits { - static NodeType* - getEntryNode(ControlFlowTree* F) { - if (F->entry) return F->entry; - - list&& roots = F->getRootFunctions(); - assert(roots.size()==1); - - return F->entry = &F->nodes[roots.front()]; - } - - static nodes_iterator nodes_begin(ControlFlowTree* F) { return &F->nodes[0]; } - static nodes_iterator nodes_end(ControlFlowTree* F) { return &F->nodes[F->size]; } - static size_t size(ControlFlowTree* F) { return F->size; } - }; -} - -class xreate::DominatorTree: public llvm::DominatorTreeBase { -public: - DominatorsTreeAnalysisProvider::Dominators dominators; - - DominatorTree(bool isPostDom): llvm::DominatorTreeBase(isPostDom) {} - - void run(ControlFlowTree& program){ - recalculate(program); - - //extract dominators info - for (auto& entry: DomTreeNodes){ - if (!entry.getFirst()) continue; - - dominators.emplace(entry.getFirst()->scope, make_pair(entry.getSecond()->getDFSNumIn(), entry.getSecond()->getDFSNumOut())); - } - } - - void print(std::ostringstream& output, const std::string& atom) const { - boost::format formatAtom(atom + "(%1%, range(%2%, %3%))."); - for (auto entry: dominators){ - output << formatAtom % (entry.first) % (entry.second.first) % (entry.second.second) - << endl; - } - } -}; - -void -DominatorsTreeAnalysisProvider::run(const ClaspLayer* engine){ - boost::scoped_ptr program(ControlFlowTree::build(engine)); - - treeForwardDominators->run(*program); - treePostDominators->run(*program); -} - -void -DominatorsTreeAnalysisProvider::print(std::ostringstream& output) const{ - treeForwardDominators->print(output, "cfa_forwdom"); - treePostDominators->print(output, "cfa_postdom"); -} - -const DominatorsTreeAnalysisProvider::Dominators& -DominatorsTreeAnalysisProvider::getForwardDominators() const{ - return treeForwardDominators->dominators; -} - -const DominatorsTreeAnalysisProvider::Dominators& -DominatorsTreeAnalysisProvider::getPostDominators() const{ - return treePostDominators->dominators; -} - -DominatorsTreeAnalysisProvider::DominatorsTreeAnalysisProvider() - : treeForwardDominators(new DominatorTree(false)) - , treePostDominators(new DominatorTree(true)) -{} - -DominatorsTreeAnalysisProvider::~DominatorsTreeAnalysisProvider() {} - -//void -//CodeScopesTree::print(){ -// typedef llvm::GraphTraits Traits; -// for (size_t i=0; i" << (*j)->scope << endl; -// } -// } -//} \ No newline at end of file diff --git a/cpp/src/analysis/DominatorsTreeAnalysisProvider.h b/cpp/src/analysis/DominatorsTreeAnalysisProvider.h deleted file mode 100644 index 5574891..0000000 --- a/cpp/src/analysis/DominatorsTreeAnalysisProvider.h +++ /dev/null @@ -1,44 +0,0 @@ -/* - * To change this license header, choose License Headers in Project Properties. - * To change this template file, choose Tools | Templates - * and open the template in the editor. - */ - -/* - * File: DominatorsTreeAnalysisProvider.h - * Author: pgess - * - * Created on May 13, 2016, 11:39 AM - */ - -#ifndef DOMINATORSTREEANALYSISPROVIDER_H -#define DOMINATORSTREEANALYSISPROVIDER_H - -#include "clasplayer.h" -#include - -namespace xreate{ - class DominatorTree; - - class DominatorsTreeAnalysisProvider: public IAnalysisData { - public: - typedef std::pair DominatedRange; - typedef std::map Dominators; - - DominatorsTreeAnalysisProvider(); - virtual ~DominatorsTreeAnalysisProvider(); - - void run(const ClaspLayer* engine); - void print(std::ostringstream& output) const; - - const Dominators& getForwardDominators() const; - const Dominators& getPostDominators() const; - - private: - boost::scoped_ptr treeForwardDominators; - boost::scoped_ptr treePostDominators; - }; -} - -#endif /* DOMINATORSTREEANALYSISPROVIDER_H */ - diff --git a/cpp/src/analysis/aux.h b/cpp/src/analysis/aux.h deleted file mode 100644 index c8bad41..0000000 --- a/cpp/src/analysis/aux.h +++ /dev/null @@ -1,25 +0,0 @@ -/* - * File: aux.h - * Author: pgess - * - * Created on June 26, 2016, 6:49 PM - */ - -#ifndef AUX_H -#define AUX_H - -#include "ast.h" -#include "clasplayer.h" - -#include -#include - -namespace xreate { namespace analysis { - std::list compile(const Expression &e); - std::list compileNeg(const Expression &e); - std::list multiplyLists(std::list> &&lists); - boost::format formatSymbol(const SymbolPacked& s); -}} - -#endif /* AUX_H */ - diff --git a/cpp/src/analysis/cfagraph.cpp b/cpp/src/analysis/cfagraph.cpp index be428ed..df29784 100644 --- a/cpp/src/analysis/cfagraph.cpp +++ b/cpp/src/analysis/cfagraph.cpp @@ -1,166 +1,220 @@ -/* +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * * File: CFAGraph.cpp - * Author: pgess + * Author: pgess * * Created on June 27, 2016, 2:09 PM */ +/** + * \file cfagraph.h + * \brief Control Flow Analysis(CFA) graph data + * + */ + #include "analysis/cfagraph.h" -#include "analysis/aux.h" +#include "analysis/utils.h" -using namespace xreate::analysis; +using namespace xreate::cfa; using namespace std; void CFAGraph::print(std::ostringstream& output) const { - const std::string& atomBinding = Config::get("clasp.bindings.function"); - const std::string& atomBindingScope = Config::get("clasp.bindings.scope"); + const std::string& atomBinding = Config::get("transcend.bindings.function"); + const std::string& atomBindingScope = Config::get("transcend.bindings.scope"); - //show function tags + output << endl << "%\t\tStatic analysis: CFA" << endl; + output << __outputPrecomputed.str(); + + //show function tags int counterTags = 0; std::ostringstream bufFunctionNames; boost::format formatFunction("function(%1%)."); boost::format formatBind(atomBinding + "(%1%, %2%)."); - for (auto function: this->__nodesFunction.left) { + for (auto function : this->__nodesFunction.left) { const auto tags = this->__functionTags.equal_range(function.first); if (tags.first == tags.second) { //no tags bufFunctionNames << "; " << function.second ; continue; } output << formatFunction % (function.second) << std::endl; - for (const auto& tag_: boost::make_iterator_range(tags)){ + for (const auto& tag_ : boost::make_iterator_range(tags)) { const Expression& tag = tag_.second; list tagRaw = xreate::analysis::compile(tag); - assert(tagRaw.size() == 1); + assert(tagRaw.size() == 1); output << formatBind - % (function.second) - % (tagRaw.front()) + % (function.second) + % (tagRaw.front()) << endl; ++counterTags; } } - if (bufFunctionNames.tellp()){ - output << formatFunction % (bufFunctionNames.str().substr(2)) << std::endl; + if (bufFunctionNames.tellp()) { + output << formatFunction % (bufFunctionNames.str().substr(2)) << std::endl; } if (counterTags == 0) { - output << "%no functtion tags at all" << endl; + output << "%no function tags at all" << endl; } - //declare scopes + //declare scopes boost::format formatScope("scope(0..%1%)."); - output << formatScope % (__clasp->getScopesCount() - 1) << std::endl; + output << formatScope % (__transcend->getScopesCount() - 1) << std::endl; //show context rules: - for (auto rule: this->__contextRules) { - output << ContextRule(rule.second).compile(rule.first) << std::endl; + for (auto rule : this->__contextRules) { + output << ContextRule(rule.second).compile(rule.first) << std::endl; }; - //show scope tags: + //show scope tags: counterTags = 0; boost::format formatScopeBind(atomBindingScope + "(%1%, %2%, strong)."); - for (auto entry: this->__scopeTags) { + for (auto entry : this->__scopeTags) { ScopePacked scopeId = entry.first; const Expression& tag = entry.second; list tagRaw = xreate::analysis::compile(tag); assert(tagRaw.size() == 1); - output << formatScopeBind % scopeId %(tagRaw.front()) << endl; + output << formatScopeBind % scopeId % (tagRaw.front()) << endl; ++counterTags; } if (counterTags == 0) { - output << "%scope tags: no tags at all" << endl; + output << "%scope tags: no tags at all" << endl; } - output << endl << "%\t\tStatic analysis: CFA" << endl; - - //parent connections - //TOTEST CFG parent function + //parent connections + //TOTEST CFG parent function boost::format formatFunctionParent("cfa_parent(%1%, function(%2%))."); - for (const auto &relation: this->__parentFunctionRelations) { + for (const auto &relation : this->__parentFunctionRelations) { const string& function = this->__nodesFunction.left.at(relation.right); output << formatFunctionParent % relation.left % function << endl; } - //TOTEST CFG parent scope + //TOTEST CFG parent scope boost::format formatScopeParent("cfa_parent(%1%, scope(%2%))."); - for (const auto &relation: this->__parentScopeRelations) { + for (const auto &relation : this->__parentScopeRelations) { output << formatScopeParent % relation.first % relation.second << endl; } - //call connections + //call connections boost::format formatCall("cfa_call(%1%, %2%)."); - for (const auto &relation: this->__callRelations) { + for (const auto &relation : this->__callRelations) { const ScopePacked scopeFrom = relation.left; const string& functionTo = this->__nodesFunction.left.at(relation.right); output << formatCall % (scopeFrom) % (functionTo) << endl; } - //function specializations descrtiption - //SECTIONTAG late-context cfa_function_specializations + //function specializations description boost::format formatSpecializations("cfa_function_specializations(%1%, %2%)."); - const list& functions = __clasp->ast->getAllFunctions(); - for (auto f: functions){ - if (f->guardContext.isValid()){ - list guardRaw = xreate::analysis::compile(f->guardContext); + const list& functions = __transcend->ast->getAllFunctions(); + for (auto f : functions) { + if (f->guard.isValid()) { + list guardRaw = xreate::analysis::compile(f->guard); assert(guardRaw.size() == 1); output << formatSpecializations % (f->getName()) % (guardRaw.front()) << endl; } } + + //Dependencies + boost::format formatDependencies("cfa_scope_depends(%1%, %2%)."); + for(const auto relation : __dependencyRelations) { + output << formatDependencies % relation.first % relation.second << endl; + } + std::multimap __dependencyRelations; } void CFAGraph::addFunctionAnnotations(const std::string& function, const std::map& tags) { unsigned int fid = registerNodeFunction(function); - for (auto& tag: tags){ - __functionTags.emplace(fid, tag.second); + for (auto& tag : tags) { + __functionTags.emplace(fid, tag.second); } } void -CFAGraph::addScopeAnnotations(const ScopePacked& scope, const std::vector& tags){ - for (Expression tag: tags){ - __scopeTags.emplace(scope, tag); +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); +CFAGraph::addContextRules(const ScopePacked& scope, const std::vector& rules) { + for (Expression rule : rules) { + __contextRules.emplace(scope, rule); } } void CFAGraph::addCallConnection(const ScopePacked& scopeFrom, const std::string& functionTo) { unsigned int idFuncTo = registerNodeFunction(functionTo); __callRelations.insert(CALL_RELATIONS::value_type(scopeFrom, idFuncTo)); } void -CFAGraph::addParentConnection(const ScopePacked& scope, const std::string& functionParent){ +CFAGraph::addParentConnection(const ScopePacked& scope, const std::string& functionParent) { __parentFunctionRelations.insert(PARENT_FUNCTION_RELATIONS::value_type(scope, registerNodeFunction(functionParent))); } void -CFAGraph::addParentConnection(const ScopePacked& scope, const ScopePacked& scopeParent){ +CFAGraph::addParentConnection(const ScopePacked& scope, const ScopePacked& scopeParent) { __parentScopeRelations.emplace(scope, scopeParent); } unsigned int -CFAGraph::registerNodeFunction(const std::string& fname){ +CFAGraph::registerNodeFunction(const std::string& fname) { auto pos = __nodesFunction.left.insert(make_pair(__nodesFunction.size(), fname)); return pos.first->first; } + +void +CFAGraph::addDependency(const ScopePacked& scope, const ScopePacked& scopeDependency) { + __dependencyRelations.emplace(scope, scopeDependency); +} + +bool +CFAGraph::isDependent(const ScopePacked& scope) const { + return __dependencyRelations.count(scope) > 0; +} + +void +CFAGraph::transmitDependencies(const ScopePacked& scopeTo, const ScopePacked& scopeFrom) { + auto range = __dependencyRelations.equal_range(scopeFrom); + + std::list dependencies; + for (auto pairI = range.first; pairI != range.second; ++pairI) { + dependencies.push_back(pairI->second); + } + + for(auto dep : dependencies) { + __dependencyRelations.emplace(scopeTo, dep); + } +} + +void +CFAGraph::addScope(CodeScope* scope) { + boost::format formatScopeBinding("ast_scope_binding(%1%, %2%, \"%3%\")."); + + ScopePacked scopeId = __transcend->pack(scope); + for (int id=0, size = scope->__bindings.size(); id < size; ++id) { + __outputPrecomputed << formatScopeBinding + % scopeId + % id + % scope->__bindings.at(id) + << endl; + } +} diff --git a/cpp/src/analysis/cfagraph.h b/cpp/src/analysis/cfagraph.h index a60499a..a4e1dc4 100644 --- a/cpp/src/analysis/cfagraph.h +++ b/cpp/src/analysis/cfagraph.h @@ -1,56 +1,64 @@ -/* +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * * File: CFAGraph.h - * Author: pgess + * Author: pgess * * Created on June 27, 2016, 2:09 PM */ #ifndef CFAGRAPH_H #define CFAGRAPH_H -#include "clasplayer.h" +#include "transcendlayer.h" -namespace xreate {namespace analysis { - - class CFAGraph: public IAnalysisData { +namespace xreate {namespace cfa { + + /** \brief Represents CFA analysis data produced by CFAPass */ + class CFAGraph: public IAnalysisReport { public: typedef boost::bimap> PARENT_FUNCTION_RELATIONS; PARENT_FUNCTION_RELATIONS __parentFunctionRelations; std::map __parentScopeRelations; + std::multimap __dependencyRelations; typedef boost::bimap< boost::bimaps::multiset_of, boost::bimaps::multiset_of, boost::bimaps::set_of_relation<> > CALL_RELATIONS; CALL_RELATIONS __callRelations; boost::bimap __nodesFunction; std::multimap __functionTags; std::multimap __scopeTags; std::multimap __contextRules; - void print(std::ostringstream& output) const; - CFAGraph(ClaspLayer* engine): __clasp(engine){} + void print(std::ostringstream& output) const override; + CFAGraph(TranscendLayer* engine): __transcend(engine){} void addFunctionAnnotations(const std::string& function, const std::map& 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); + void addDependency(const ScopePacked& scope, const ScopePacked& scopeDependency); + bool isDependent(const ScopePacked& scope) const; + void transmitDependencies(const ScopePacked& scopeTo, const ScopePacked& scopeFrom); + void addScope(CodeScope* scope); private: - ClaspLayer* __clasp; + TranscendLayer* __transcend; + std::ostringstream __outputPrecomputed; unsigned int registerNodeFunction(const std::string& fname); }; -}} +}} //end of namespace xreate::cfa #endif /* CFAGRAPH_H */ diff --git a/cpp/src/analysis/dfagraph.cpp b/cpp/src/analysis/dfagraph.cpp index 00a3006..ee076b6 100644 --- a/cpp/src/analysis/dfagraph.cpp +++ b/cpp/src/analysis/dfagraph.cpp @@ -1,250 +1,244 @@ -#include "analysis/dfagraph.h" -#include "analysis/aux.h" - -#include +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * File: DFAGraph.h + * Author: pgess + * + */ + +/** + * \file dfagraph.h + * \brief Data Flow Analysis(DFA) graph data + * + */ +#include "analysis/dfagraph.h" +#include "analysis/utils.h" -using namespace xreate; -using namespace xreate::analysis; using namespace std; +using namespace xreate::analysis; -namespace xreate { - namespace analysis { - - void - DFAGraph::print(std::ostringstream& output) const { - std::set symbols; - - output << endl << "%\t\tStatic analysis: DFA" << endl; - - std::vector>::const_iterator i1; - std::vector::const_iterator i2; - - boost::format formatDfaConnection("dfa_connection(%1%, %2%, %3%)."); - for (i1 = this->__edges.begin(), i2 = this->__data.begin(); i1 != this->__edges.end(); ++i1, ++i2) { - string edgeName; - switch (*i2) { - case DFGConnection::WEAK: edgeName = "weak"; - break; - case DFGConnection::STRONG: edgeName = "strong"; - break; - case DFGConnection::PROTOTYPE: edgeName = "proto"; - break; - } - - output << formatDfaConnection - % formatSymbol(i1->first) - % formatSymbol(i1->second) - % edgeName - << " %" << this->__clasp->getHintForPackedSymbol(i1->first) << " - " << this->__clasp->getHintForPackedSymbol(i1->second) - << endl; - - symbols.insert(i1->first); - symbols.insert(i1->second); - } - - boost::format formatDfaDependency("dfa_dependency(%1%, %2%)."); - for (auto i = this->__dependencies.begin(); i != this->__dependencies.end(); ++i) { - output << formatDfaDependency - % formatSymbol(i->first) - % formatSymbol(i->second) - << " %" - << this->__clasp->getHintForPackedSymbol(i->first) << " - " - << this->__clasp->getHintForPackedSymbol(i->second) - << endl; - } - - boost::format formatBind("bind(%1%, %2%)."); - for (const pair& tag : this->__tags) { - for (string variant : xreate::analysis::compile(tag.second)) { - output << formatBind - % formatSymbol(tag.first) - % (variant) - << "%" << this->__clasp->getHintForPackedSymbol(tag.first) - << endl; - } - - symbols.insert(tag.first); - } - - for (const SymbolPacked& s : symbols) { - output << "v(" << formatSymbol(s) << ")." - << " %" << this->__clasp->getHintForPackedSymbol(s) - << endl; - } - } - - 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"); - } +namespace xreate { namespace dfa { - VisitorAddTag(DFAGraph * const dfagraph, Expression&& tag) : - __graph(dfagraph), __tag(tag) { - } +void +DFACallInstance::print(std::ostringstream& output) const{ + boost::format formatArgs; + boost::format formatInstance("dfa_callfn(%1%, %2%)."); - private: - DFAGraph * const __graph; - Expression __tag; - }; + switch (type) { + case WEAK: + formatArgs = boost::format("weak(dfa_callargs(%1%, %2%, %3%))."); + break; - class VisitorAddLink : public boost::static_visitor<> { - public: + case STRONG: + formatArgs = boost::format("weak(dfa_callargs(%1%, %2%, %3%)).\ndfa_callargs(%1%, %2%, %3%)."); + break; + } - void operator()(const SymbolPacked& nodeFrom) { - if (!__graph->isConnected(__nodeTo, nodeFrom)) { - __graph->__edges.emplace_back(__nodeTo, nodeFrom); - __graph->__data.push_back(__link); + output << formatInstance + % analysis::writeSymbolNode(retActual) + % fnName + << endl; - DFAGraph::EdgeId eid = __graph->__edges.size() - 1; - __graph->__outEdges.emplace(nodeFrom, eid); - } - } + for(std::pair rec: args) { + SymbolNode argFormal(rec.first); - void operator()(const SymbolTransient& symbolFrom) { - switch (__link) { - case DFGConnection::WEAK: - { - //virtual symbol to hold transient annotations - SymbolPacked symbPivot = __graph->createAnonymousSymbol(symbolFrom.scope); - - __graph->addConnection(symbPivot, symbolFrom, DFGConnection::STRONG); - __graph->addConnection(__nodeTo, symbPivot, DFGConnection::WEAK); - break; - } - - case DFGConnection::STRONG: - { - for (const Expression& tag : symbolFrom.tags) { - __graph->__tags.emplace(__nodeTo, tag); - } - break; - } - - default: - assert(false && "Undefined behavior"); - } - } + output << formatArgs + % analysis::writeSymbolNode(retActual) + % analysis::writeSymbolNode(argFormal) + % analysis::writeSymbolNode(rec.second) + << endl; + } +} - void operator()(const SymbolInvalid&) { - if (__link == DFGConnection::STRONG) return; - if (__link == DFGConnection::WEAK) return; +void +DFAGraph::addDependency(const SymbolNode& node, const SymbolNode& subnode){ + __dependencies.emplace(node, subnode); - assert(false && "Undefined behavior"); - } + if (boost::get(&node)){ + __usedSymbols.insert(node); + } - VisitorAddLink(DFAGraph * const dfagraph, const SymbolPacked& nodeTo, DFGConnection link) : - __graph(dfagraph), __nodeTo(nodeTo), __link(link) { - } + if (boost::get(&subnode)){ + __usedSymbols.insert(node); + } +} - private: - DFAGraph * const __graph; - SymbolPacked __nodeTo; - DFGConnection __link; - }; - - class VisitorGetDependencyConnection : public boost::static_visitor> - { - public: - - list - operator()(const SymbolPacked & nodeFrom) { - return - { - nodeFrom - }; - } +void +DFAGraph::printDependencies(std::ostringstream& output) const{ + for(const SymbolNode& root: __roots){ + printDependency(output, root, root); + } +} - list - operator()(const SymbolTransient & nodeFrom) { - return nodeFrom.dependencies; +void +DFAGraph::printDependency(std::ostringstream& output, const SymbolNode& nodeCurrent, const SymbolNode& nodeDependent) const { + auto range = __dependencies.equal_range(nodeCurrent); + for (auto it = range.first; it != range.second; ++it){ + if (boost::get(&it->second)){ + if (!__usedSymbols.count(it->second)){ + printDependency(output, it->second, nodeDependent); + continue; } + } - list - operator()(const SymbolInvalid&) { - assert(false && "Undefined behavior"); - } + boost::format formatDependency("dfa_depends(%1%, %2%)."); - VisitorGetDependencyConnection(DFAGraph * const g) : graph(g) { - } - DFAGraph * const graph; - }; + output << formatDependency + % analysis::writeSymbolNode(nodeDependent) + % analysis::writeSymbolNode(it->second) + << endl; - class VisitorSetDependencyConnection : public boost::static_visitor<> { - public: + printDependency(output, it->second, it->second); + } +} + +void +DFAGraph::printInplaceAnnotation(const SymbolNode& node, const Expression& expression) { + // write down in-place expression tags: + boost::format formatBind("bind(%1%, %2%)."); + __usedSymbols.insert(node); + + for (const string& tag: xreate::analysis::compile(expression)) { + __output << formatBind + % analysis::writeSymbolNode(node) + % tag + << endl; + } +} + +void +DFAGraph::printLateAnnotation(const SymbolNode& node, + const Expression& expression, + const std::list& symbols, + const std::list& domains){ + boost::format formatLateAnnotation("late(%1%, (%2%), (%3%), %4%):- %5%."); + boost::format formatDom("%1%(%2%)"); + std::list exprSerialized = xreate::analysis::compile(expression); + assert(exprSerialized.size() == 1); + + list identSymbols, identNames, domainsSerialised; + + auto domainI = domains.begin(); + for(auto symbol: symbols){ + identSymbols.push_back(analysis::writeSymbolNode(symbol.second).str()); + identNames.push_back(symbol.first); + domainsSerialised.push_back((formatDom % *domainI % symbol.first).str()); + ++domainI; + } - void operator()(SymbolPacked& nodeTo) { - VisitorGetDependencyConnection visitorGetDepenencies(graph); - auto deps = boost::apply_visitor(visitorGetDepenencies, nodeFrom); + __output << formatLateAnnotation + % analysis::writeSymbolNode(node) + % boost::algorithm::join(identSymbols, ", ") + % boost::algorithm::join(identNames, ", ") + % exprSerialized.front() + % boost::algorithm::join(domainsSerialised, "; ") + << endl; +} + +void +DFAGraph::printAlias(const SymbolNode& symbFormal, const SymbolNode& symbActual){ + __usedSymbols.insert(symbFormal); __usedSymbols.insert(symbActual); + + boost::format formatAlias("dfa_alias(%1%, %2%)."); + __output << formatAlias + % analysis::writeSymbolNode(symbFormal) + % analysis::writeSymbolNode(symbActual) + << endl; +} + +void +DFAGraph::printWeakAlias(const SymbolNode& symbFormal, const SymbolNode& symbActual){ + __usedSymbols.insert(symbFormal); __usedSymbols.insert(symbActual); + + boost::format formatAlias("weak(dfa_alias(%1%, %2%))."); + __output << formatAlias + % analysis::writeSymbolNode(symbFormal) + % analysis::writeSymbolNode(symbActual) + << endl; +} + +void +DFAGraph::printFunctionRet(ManagedFnPtr function, const SymbolNode& symbolRet){ + boost::format formatRet("dfa_fnret(%1%, %2%)."); + __usedSymbols.insert(symbolRet); + + __output << formatRet + % function->getName() + % analysis::writeSymbolNode(symbolRet) + << endl; + + __roots.insert(symbolRet); +} + +void +DFAGraph::addCallInstance(DFACallInstance&& instance){ + __usedSymbols.insert(instance.retActual); + for(const auto arg: instance.args){ + __usedSymbols.insert(SymbolNode(arg.first)); + __usedSymbols.insert(arg.second); + } - for (const SymbolPacked& dep : deps) { - graph->__dependencies.emplace(nodeTo, dep); - } - } + __callInstances.push_back(std::move(instance)); +} - void operator()(SymbolTransient& nodeTo) { - VisitorGetDependencyConnection visitorGetDepenencies(graph); - auto deps = boost::apply_visitor(visitorGetDepenencies, nodeFrom); +void +DFAGraph::print(std::ostringstream& output) const{ + output << endl << "%\t\tStatic analysis: DFA" << endl; - for (const SymbolPacked& dep : deps) { - nodeTo.dependencies.push_back(dep); - } - } + //Dependencies + printDependencies(output); - void operator()(SymbolInvalid&) { - assert(false && "Undefined behavior"); - } + //Add generated report + output << __output.str() << endl; - VisitorSetDependencyConnection(DFAGraph * const g, SymbolNode s) : graph(g), nodeFrom(s) { - } - DFAGraph * const graph; - SymbolNode nodeFrom; - }; + //Call instances + for(const DFACallInstance& instance: __callInstances){ + instance.print(output); + } - bool - DFAGraph::isConnected(const SymbolPacked& identifierTo, const SymbolPacked& identifierFrom) { - auto range = __outEdges.equal_range(identifierFrom); + output << endl; +} - for (std::multimap::iterator edge = range.first; edge != range.second; ++edge) { - if (__edges[edge->second].second == identifierTo) - return true; - } +void +DFAGraph::printSymbols(TranscendLayer* transcend){ + boost::format formatHint("shint(%1%, \"%2%\")."); - return false; - } + for (const SymbolNode& node : __usedSymbols) { + __output << "v(" << analysis::writeSymbolNode(node) << "). "; - void - DFAGraph::addConnection(const SymbolPacked& nodeTo, const SymbolNode& nodeFrom, DFGConnection link) { - VisitorAddLink visitor(this, nodeTo, link); - boost::apply_visitor(visitor, nodeFrom); + if (const SymbolPacked* symbol = boost::get(&node)){ + __output << formatHint % analysis::writeSymbolNode(node) % transcend->getHintForPackedSymbol(*symbol); } + __output << endl; + } +} + +void +DFAGraph::printOperator(Operator op, std::list&& operands, int dataOpListSize){ + std::string opStr; + switch(op){ + case Operator::MAP: opStr = "map"; break; + case Operator::FOLD: opStr = "fold"; break; + case Operator::LIST: opStr = "list"; break; + case Operator::LIST_RANGE: opStr = "list_range"; break; + case Operator::INDEX: opStr = "index"; break; + default: assert(false); + } - void - DFAGraph::addDependencyConnection(SymbolNode& identifierTo, SymbolNode& identifierFrom) { - VisitorSetDependencyConnection visitor(this, identifierFrom); - boost::apply_visitor(visitor, identifierTo); - } + std::ostringstream bufOperands; + for(const SymbolNode& operand: operands){ + __usedSymbols.insert(operand); + bufOperands << analysis::writeSymbolNode(operand) << ", "; + } - void - DFAGraph::addAnnotation(SymbolNode& node, Expression&& tag) { - VisitorAddTag visitor(this, move(tag)); - boost::apply_visitor(visitor, node); - } + if(op == Operator::LIST){ + bufOperands << dataOpListSize << ", "; + } - SymbolPacked - DFAGraph::createAnonymousSymbol(const ScopePacked& scope) { - return SymbolPacked(__countAnonymousSymbols++, scope, true); - } + boost::format formatOperator("ast_op_%1%(%2%)."); + __output << (formatOperator % opStr % bufOperands.str().substr(0, bufOperands.str().size() - 2)) << endl; +} - } -} \ No newline at end of file +}} //end of namespace xreate::dfa diff --git a/cpp/src/analysis/dfagraph.h b/cpp/src/analysis/dfagraph.h index 374ab14..dfe1859 100644 --- a/cpp/src/analysis/dfagraph.h +++ b/cpp/src/analysis/dfagraph.h @@ -1,57 +1,66 @@ -/* +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * * File: dfa.h - * Author: pgess + * Author: pgess * * Created on June 27, 2016, 1:50 PM */ #ifndef DFA_H #define DFA_H -#include "clasplayer.h" - -namespace xreate {namespace analysis { - - struct SymbolTransient { - std::list tags; - ScopePacked scope; - std::list dependencies; - }; - - struct SymbolInvalid { }; - - typedef boost::variant SymbolNode; - - class DFAGraph: public IAnalysisData{ - friend class VisitorAddTag; - friend class VisitorAddLink; - friend class VisitorGetDependencyConnection; - friend class VisitorSetDependencyConnection; - - - public: - DFAGraph(ClaspLayer* engine): __clasp(engine){} - - SymbolPacked createAnonymousSymbol(const ScopePacked& scope); - void addAnnotation(SymbolNode& identifier, Expression&& tag); - void addConnection(const SymbolPacked& identifierTo, const SymbolNode& identifierFrom, DFGConnection link); - void addDependencyConnection(SymbolNode& identifierTo, SymbolNode& identifierFrom); - bool isConnected(const SymbolPacked& identifierTo, const SymbolPacked& identifierFrom); - - void print(std::ostringstream& output) const; - - private: - typedef unsigned int EdgeId; - std::vector> __edges; - std::multimap __outEdges; - std::vector __data; - std::multimap __tags; - std::multimap __dependencies; - - unsigned int __countAnonymousSymbols=0; - ClaspLayer* __clasp; - }; +#include "transcendlayer.h" +#include + +namespace xreate { namespace latereasoning { + typedef std::pair LateSymbolRecognized; }} -#endif /* DFA_H */ +namespace xreate {namespace dfa { + +enum DFACallInstanceType { + STRONG, WEAK +}; + +class DFACallInstance { +public: + std::string fnName; + std::vector> args; + SymbolNode retActual; + DFACallInstanceType type; + + void print(std::ostringstream& output) const; +}; + +/** \brief Holds DFA Analysis report produced by DFAPass */ +class DFAGraph : public IAnalysisReport { +public: + // DFAGraph(TranscendLayer* engine): __transcend(engine){} + virtual void print(std::ostringstream& output) const override; + void addCallInstance(DFACallInstance && instance); + void addDependency(const SymbolNode& node, const SymbolNode& subnodeBlock); + void printInplaceAnnotation(const SymbolNode& node, const Expression& expression); + void printLateAnnotation(const SymbolNode& node, const Expression& expression, + const std::list& symbols, + const std::list& domains); + void printAlias(const SymbolNode& symbFormal, const SymbolNode& symbActual); + void printWeakAlias(const SymbolNode& symbFormal, const SymbolNode& symbActual); + void printFunctionRet(ManagedFnPtr function, const SymbolNode& symbolRet); + void printDependencies(std::ostringstream& output) const; + void printSymbols(TranscendLayer* transcend); + void printOperator(Operator, std::list&& operands, int dataOpListSize = 0); +private: + mutable std::ostringstream __output; + std::list __callInstances; + std::unordered_multimap __dependencies; + std::unordered_set __usedSymbols; + std::unordered_set __roots; + + void printDependency(std::ostringstream& output, const SymbolNode& nodeCurrent, const SymbolNode& nodeDependent) const; +}; +}} // end of namespace xreate::dfa + +#endif /* DFA_H */ diff --git a/cpp/src/analysis/interpretation.cpp b/cpp/src/analysis/interpretation.cpp new file mode 100644 index 0000000..f46027d --- /dev/null +++ b/cpp/src/analysis/interpretation.cpp @@ -0,0 +1,274 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +/* + * Author: pgess + * Created on June 25, 2018, 3:25 PM + * + * \file interpretation.cpp + * \brief interpretation + */ + +#include "analysis/interpretation.h" + +using namespace std; + +namespace xreate{ +namespace interpretation{ + +typedef vector InstancePacked; + +std::list +generateAllInstancesInDomain2(const ExpandedType& domainT) { + if(!domainT->isValid()) { + return {Expression()}; + } + assert(domainT->__operator == TypeOperator::VARIANT); + std::list results; + int variantId = -1; + + bool flagDomainStateless = std::all_of(domainT->__operands.begin(), domainT->__operands.end(), + [](const TypeAnnotation & subdomainT) { + return !subdomainT.isValid(); + }); + + for(const TypeAnnotation& subdomainT : domainT->__operands) { + ++variantId; + + if(flagDomainStateless) { + Expression result(Operator::VARIANT,{}); + result.setValueDouble(variantId); + results.push_back(result); + continue; + } + + std::list subresults = generateAllInstancesInDomain2(ExpandedType(subdomainT)); + for (const Expression& subresult : subresults) { + Expression result(Operator::VARIANT,{}); + result.setValueDouble(variantId); + result.operands.push_back(subresult); + + results.push_back(result); + } + } + + return results; +} + +TypeAnnotation +collapseFnGroup(const std::list& symbols) { + Gringo::Symbol symbolAny = symbols.front(); + size_t operandsCount = symbolAny.args().size; + + TypeAnnotation resultT; + resultT.__operands.reserve(operandsCount); + + for(size_t operandId = 0; operandId < operandsCount; ++operandId) { + std::list column; + + for(const Gringo::Symbol& row : symbols) { + column.push_back(row.args()[operandId]); + } + + TypeAnnotation operandT = collapseColumn(column); + resultT.__operands.push_back(operandT); + } + + if(resultT.__operands.size() == 1) { + return resultT.__operands.front(); + } + + if(resultT.__operands.size() > 1) { + resultT.__operator = TypeOperator::LIST_NAMED; + return resultT; + } + + return resultT; +} + +TypeAnnotation +collapseColumn(const std::list& symbols) { + TypeAnnotation resultT; + if(!symbols.size()) return resultT; + + Gringo::Symbol symbolAny = symbols.front(); + + switch(symbolAny.type()) { + case Gringo::SymbolType::Num: + { + return TypeAnnotation(TypePrimitive::Num); + } + + case Gringo::SymbolType::Str: + { + return TypeAnnotation(TypePrimitive::String); + } + + case Gringo::SymbolType::Fun: + { + map> fnGroups; + + for(const Gringo::Symbol& row : symbols) { + fnGroups[row.name().c_str()].push_back(row); + } + + TypeAnnotation resultT; + resultT.__operands.reserve(fnGroups.size()); + resultT.bindings.reserve(fnGroups.size()); + + for(const auto& group : fnGroups) { + if(!group.second.size()) continue; + + TypeAnnotation variantT = collapseFnGroup(group.second); + Gringo::Symbol symbolAny = group.second.front(); + string variantName = symbolAny.name().c_str(); + resultT.fields.push_back(variantName); + resultT.__operands.push_back(variantT); + } + + resultT.__operator = TypeOperator::VARIANT; + // if(resultT.__operands.size() == 1) { + // return resultT.__operands.front(); + // } + return resultT; + } + + case Gringo::SymbolType::Inf: + case Gringo::SymbolType::Special: + case Gringo::SymbolType::Sup: + { + break; + } + } + + assert(false); + return TypeAnnotation(); +} + +ExpandedType +dereferenceSlaveType(ExpandedType t, const TranscendLayer* transcend) { + assert(t->__operator == TypeOperator::SLAVE); + const string& domain = t->__valueCustom; + StaticModel model = transcend->query(domain); + if(!model.size()) return ExpandedType(TypeAnnotation()); + + std::list symbols; + for(auto row : model) { + symbols.push_back(row.second); + } + return ExpandedType(collapseFnGroup(symbols)); +} + +Expression +representTransExpression(const Gringo::Symbol& atom, ExpandedType schemaT, TranscendLayer* transcend) { + atom.print(std::cout); std::cout<__operator) { + case TypeOperator::NONE: + { + switch(schemaT->__value) { + case TypePrimitive::I8: + case TypePrimitive::I32: + case TypePrimitive::I64: + case TypePrimitive::Num: + case TypePrimitive::Int: + { + return Expression(Atom(atom.num())); + } + + case TypePrimitive::String: + { + return Expression(Atom(atom.string().c_str())); + } + + case TypePrimitive::Invalid: + case TypePrimitive::Bool: + case TypePrimitive::Float: + { + assert(false); + return Expression(); + } + } + break; + } + + case TypeOperator::SLAVE: + { + ExpandedType contentT = dereferenceSlaveType(schemaT, transcend); + return representTransExpression(atom, contentT, transcend); + } + + case TypeOperator::VARIANT: + { + map dictVariants; + for(size_t variantId = 0; variantId < schemaT->fields.size(); ++variantId) { + dictVariants.emplace(schemaT->fields.at(variantId), variantId); + } + + string predicateName = atom.name().c_str(); + assert(dictVariants.count(predicateName)); + + size_t predicateId = dictVariants.at(predicateName); + Expression result(Operator::VARIANT,{}); + result.op = Operator::VARIANT; + result.setValueDouble(predicateId); + + if(!schemaT->__operands.size()) return result; + ExpandedType contentT = schemaT->__operands.at(predicateId).__operator == TypeOperator::SLAVE + ? dereferenceSlaveType(ExpandedType(schemaT->__operands.at(predicateId)), transcend) + : ExpandedType(schemaT->__operands.at(predicateId)); + + //edge case, content's type is LIST_NAMED: + if (contentT->__operator == TypeOperator::LIST_NAMED) { + result.operands.push_back(representTransExpression(atom, contentT, transcend)); + + } else if(!contentT->isValid()) { + return result; + + } else { + assert(atom.args().size); + result.operands.push_back(representTransExpression(atom.args()[0], contentT, transcend)); + } + + return result; + } + + case TypeOperator::LIST_NAMED: + { + const Gringo::SymSpan& operandsRaw = atom.args(); + size_t opCount = operandsRaw.size; + assert(opCount == schemaT->__operands.size()); + + size_t operandId = 0; + std::vector operands; + operands.reserve(opCount); + for(const TypeAnnotation operandT : schemaT->__operands) { + operands.push_back(representTransExpression(operandsRaw[operandId], ExpandedType(operandT), transcend)); + ++operandId; + } + + Expression result(Operator::LIST_NAMED,{}); + result.operands = operands; + result.type = schemaT; + return result; + } + + case TypeOperator::LIST: + case TypeOperator::CALL: + case TypeOperator::CUSTOM: + case TypeOperator::ACCESS: + case TypeOperator::LINK: + { + assert(false); + return Expression(); + } + } + + assert(false); + return Expression(); +} + +} +} //end of xreate namespace diff --git a/cpp/src/analysis/interpretation.h b/cpp/src/analysis/interpretation.h new file mode 100644 index 0000000..7716eb8 --- /dev/null +++ b/cpp/src/analysis/interpretation.h @@ -0,0 +1,31 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +/* + * Author: pgess + * Created on June 25, 2018, 3:24 PM + * + * \file interpretation.h + * \brief interpretation + */ + +#ifndef INTERPRETATION_H +#define INTERPRETATION_H + +#include "transcendlayer.h" + +namespace xreate{ +namespace interpretation{ + +TypeAnnotation collapseColumn(const std::list& symbols); +ExpandedType dereferenceSlaveType(ExpandedType t, const TranscendLayer* transcend); +Expression representTransExpression(const Gringo::Symbol& atom, ExpandedType schemaT, TranscendLayer* transcend); +std::list generateAllInstancesInDomain2(const ExpandedType& domainT); + +} +} +#endif /* INTERPRETATION_H */ + diff --git a/cpp/src/analysis/typeinference.cpp b/cpp/src/analysis/typeinference.cpp new file mode 100644 index 0000000..3583aca --- /dev/null +++ b/cpp/src/analysis/typeinference.cpp @@ -0,0 +1,87 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * typeinference.cpp + * + * Author: pgess + * Created on April 16, 2017, 10:13 AM + */ + +/** + * \file typeinference.h + * \brief Type inference analysis + */ + +#include "typeinference.h" +#include "llvmlayer.h" +#include "transcendlayer.h" + +#include "llvm/IR/Function.h" +#include "llvm/IR/DerivedTypes.h" + +using namespace std; + +namespace xreate{ +namespace typeinference{ + +//TODO type conversion: +//a) automatically expand types int -> bigger int; int -> floating +//b) detect exact type of `num` based on max used numeral / function type +//c) warning if need to truncate (allow/dissallow based on annotations) + +llvm::Value* +doAutomaticTypeConversion(llvm::Value* source, llvm::Type* tyTarget, llvm::IRBuilder<>& builder) { + if(tyTarget->isIntegerTy() && source->getType()->isIntegerTy()) { + llvm::IntegerType* tyTargetInt = llvm::dyn_cast(tyTarget); + llvm::IntegerType* tySourceInt = llvm::dyn_cast(source->getType()); + + if(tyTargetInt->getBitWidth() < tySourceInt->getBitWidth()) { + return builder.CreateCast(llvm::Instruction::Trunc, source, tyTarget); + } + + if(tyTargetInt->getBitWidth() > tySourceInt->getBitWidth()) { + return builder.CreateCast(llvm::Instruction::SExt, source, tyTarget); + } + } + + if(source->getType()->isIntegerTy() && tyTarget->isFloatingPointTy()) { + return builder.CreateCast(llvm::Instruction::SIToFP, source, tyTarget); + } + + if (source->getType()->isStructTy() && tyTarget->isIntegerTy()){ + llvm::StructType* sourceST = llvm::cast(source->getType()); + if(sourceST->getNumElements() == 1) { + llvm::Value* sourceElRaw = builder.CreateExtractValue(source, llvm::ArrayRef({0})); + return doAutomaticTypeConversion(sourceElRaw, tyTarget, builder); + } + } + + return source; +} + +ExpandedType +getType(const Expression& expression, const AST& ast) { + if(expression.type.isValid()) { + return ast.expandType(expression.type); + } + + if(expression.__state == Expression::IDENT) { + Symbol s = Attachments::get(expression); + return getType(CodeScope::getDefinition(s), ast); + } + + if(Attachments::exists(expression)) { + return Attachments::get(expression); + } + + if(expression.__state == Expression::NUMBER) { + return ExpandedType(TypeAnnotation(TypePrimitive::I32)); + } + + + assert(false && "Type can't be determined for an expression"); +} + +} +} //end of namespace xreate::typeinference diff --git a/cpp/src/analysis/typeinference.h b/cpp/src/analysis/typeinference.h new file mode 100644 index 0000000..df6ce78 --- /dev/null +++ b/cpp/src/analysis/typeinference.h @@ -0,0 +1,31 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * File: typeinference.h + * Author: pgess + * + * Created on April 16, 2017, 10:17 AM + */ + +#ifndef TYPEINFERENCE_H +#define TYPEINFERENCE_H + +#include "ast.h" +#include "llvm/IR/IRBuilder.h" + +namespace llvm{ +class Value; +class Type; +}; + +namespace xreate{ +namespace typeinference{ + +llvm::Value* doAutomaticTypeConversion(llvm::Value* source, llvm::Type* tyTarget, llvm::IRBuilder<>& builder); +ExpandedType getType(const Expression& expression, const AST& ast); +} +}//namespace xreate::typeinference + +#endif /* TYPEINFERENCE_H */ + diff --git a/cpp/src/analysis/aux.cpp b/cpp/src/analysis/utils.cpp similarity index 72% rename from cpp/src/analysis/aux.cpp rename to cpp/src/analysis/utils.cpp index 6d5192c..471e24d 100644 --- a/cpp/src/analysis/aux.cpp +++ b/cpp/src/analysis/utils.cpp @@ -1,136 +1,159 @@ -#include "aux.h" +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * aux.cpp + * + * Author: pgess + */ + +/** + * \file aux.h + * \brief Data representation in ASP format ready for use by reasoner + */ + +#include "utils.h" #include namespace xreate { namespace analysis { using namespace std; 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; } std::list compile(const Expression &e){ list result; switch (e.op) { case Operator::CALL: { - assert(e.__state == Expression::COMPOUND); + if(!e.operands.size()){ + result.push_back(e.getValueString()); + break; + } std::list> operands; std::transform(e.operands.begin(), e.operands.end(), std::inserter(operands, operands.begin()), [](const Expression &e) { return compile(e); }); list &&operands_ = multiplyLists(std::move(operands)); result.push_back(boost::str(boost::format("%1%(%2%)") % (e.getValueString()) % (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: { + case Operator::INVALID: { switch (e.__state) { case Expression::IDENT: result.push_back(e.getValueString()); break; case Expression::NUMBER: result.push_back(to_string(e.getValueDouble())); 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 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; } -boost::format -formatSymbol(const SymbolPacked& s){ - boost::format formatSymbNamed("(%1%, %2%)"); - boost::format formatSymbAnonymous("(anonym(%1%), %2%)"); +//NOTE: Any changes should be reflected in ParseImplAtom, +// ParseImplAtom +class VisitorFormatSymbol: public boost::static_visitor { +public: + + boost::format operator()(const SymbolPacked& node) const { + boost::format formatSymbNamed("s(%1%,%2%,%3%)"); + return formatSymbNamed % node.identifier % node.version % node.scope ; + } - if (!s.categoryTransient){ - return formatSymbNamed % s.identifier % s.scope; - } else { - return formatSymbAnonymous % s.identifier % s.scope; + boost::format operator()(const SymbolAnonymous& node) const { + boost::format formatSymbAnonymous("a(%1%)"); + return formatSymbAnonymous % node.id; } +}; + +boost::format writeSymbolNode(const SymbolNode& symbol){ + return boost::apply_visitor(VisitorFormatSymbol(), symbol); } - -}} \ No newline at end of file + +}} //end of xreate::analysis + + diff --git a/cpp/src/analysis/utils.h b/cpp/src/analysis/utils.h new file mode 100644 index 0000000..70c2dc1 --- /dev/null +++ b/cpp/src/analysis/utils.h @@ -0,0 +1,31 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * File: aux.h + * Author: pgess + * + * Created on June 26, 2016, 6:49 PM + */ + +#ifndef AUX_H +#define AUX_H + +#include "ast.h" +#include "transcendlayer.h" + +#include +#include + +namespace xreate { namespace analysis { + +std::list compile(const Expression &e); +std::list compileNeg(const Expression &e); +std::list multiplyLists(std::list> &&lists); + +boost::format writeSymbolNode(const SymbolNode& symbol); + +}} //end of xreate::analysis + +#endif /* AUX_H */ + diff --git a/cpp/src/ast.cpp b/cpp/src/ast.cpp index 0ae05a9..73dfef3 100644 --- a/cpp/src/ast.cpp +++ b/cpp/src/ast.cpp @@ -1,816 +1,977 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * Author: pgess + * File: ast.cpp + */ + +/** + * \file ast.h + * \brief Syntax Tree and related code + * + * \sa xreate::AST + */ + #include "ast.h" #include "ExternLayer.h" +#include "analysis/typeinference.h" + #include #include -#include + +//TODO BDecl. forbid multiple body declaration (ExprTyped) + +namespace std { + + std::size_t + hash::operator()(xreate::ScopedSymbol const& s) const { + return s.id ^ (s.version << 2); + } + + bool + equal_to::operator()(const xreate::ScopedSymbol& __x, const xreate::ScopedSymbol& __y) const { + return __x.id == __y.id && __x.version == __y.version; + } + + size_t + hash::operator()(xreate::Symbol const& s) const { + return hash()(s.identifier) ^ ((long int) s.scope << 1); + } + + bool + equal_to::operator()(const xreate::Symbol& __x, const xreate::Symbol& __y) const { + return __x == __y; + }; +} using namespace std; -namespace xreate{ -class ExpressionHints{ +namespace xreate { + +Atom::Atom(const std::wstring& value) { + __value = wstring_to_utf8(value); +} + +Atom::Atom(std::string && name) : __value(name) { +} + +const std::string& +Atom::get() const { + return __value; +} + +Atom::Atom(wchar_t* value) { + //DEBT reconsider number literal recognition + __value = wcstol(value, 0, 10); +} + +Atom::Atom(int value) +: __value(value) { +} + +double +Atom::get()const { + return __value; +} + +Atom::Atom(const std::wstring& value) { + assert(value.size() >= 2); + __value = wstring_to_utf8(value.substr(1, value.size() - 2)); +} + +Atom::Atom(std::string && name) : __value(name) {} + +const std::string& +Atom::get() const { + return __value; +} + +class ExpressionHints { public: + static bool - isStringValueValid(const Expression& e){ - switch (e.__state){ + isStringValueValid(const Expression& e) { + switch (e.__state) { case Expression::INVALID: - case Expression::VARIANT: assert(false); case Expression::IDENT: case Expression::STRING: return true; case Expression::NUMBER: case Expression::BINDING: return false; - case Expression::COMPOUND: { - switch (e.op){ + case Expression::COMPOUND: + { + switch (e.op) { case Operator::CALL: - case Operator::INDEX: return true; default: return false; } } } return false; } static bool - isDoubleValueValid(const Expression& e){ - switch (e.__state){ + isDoubleValueValid(const Expression& e) { + switch (e.__state) { case Expression::NUMBER: return true; case Expression::INVALID: - case Expression::VARIANT: assert(false); case Expression::IDENT: case Expression::STRING: - case Expression::COMPOUND: case Expression::BINDING: return false; + + case Expression::COMPOUND: { + switch (e.op) { + case Operator::VARIANT: + return true; + default: return false; + } + } } return false; } }; class TypesResolver { private: - const AST* ast; - std::map scope; - std::map signatures; - + 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); - } + 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; + 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); - }); + pack.reserve(operands.size()); + std::transform(operands.begin(), operands.end(), std::inserter(pack, pack.end()), + [this](const TypeAnnotation & t) { + return expandType(t); + }); - return pack; - } + 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, 0)); - } - - 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); + TypesResolver(const AST* root, const std::map& scopeOuter = std::map(), + std::map signaturesOuter = std::map()) + : ast(root), scope(scopeOuter), signatures(signaturesOuter) { + } + + ExpandedType + operator()(const TypeAnnotation &t, const std::vector &args = std::vector()) { + //assert(args.size() == t.bindings.size()); // invalid number of arguments + for (size_t i = 0; i < args.size(); ++i) { + scope[t.bindings.at(i)] = args.at(i); + } + + switch (t.__operator) { + case TypeOperator::LIST: + { + assert(t.__operands.size() == 1); + + Expanded elTy = expandType(t.__operands.at(0)); + return ExpandedType(TypeAnnotation(tag_array, elTy, 0)); + } + + case TypeOperator::LIST_NAMED: + { + std::vector&& packOperands = expandOperands(t.__operands); + auto typNew = TypeAnnotation(TypeOperator::LIST_NAMED, move(packOperands)); + typNew.fields = t.fields; + + return ExpandedType(move(typNew)); + }; + + case TypeOperator::VARIANT: + { + std::vector&& packOperands = expandOperands(t.__operands); + auto typNew = TypeAnnotation(TypeOperator::VARIANT, move(packOperands)); + typNew.fields = t.fields; + + return ExpandedType(move(typNew)); + }; + + case TypeOperator::CALL: + { + std::string alias = t.__valueCustom; + + //find in local scope: + TypeAnnotation ty; + if (scope.count(alias)) { + ty = scope.at(alias); + + } else if (ast->__indexTypeAliases.count(alias)) { + ty = ast->__indexTypeAliases.at(alias); + + } else { + assert(false && "Undefined or external type"); + } + + std::vector&& operands = expandOperands(t.__operands); + TypeAnnotation signature(TypeOperator::CALL, move(operands)); + signature.__valueCustom = alias; + + if (signatures.count(signature)) { + auto link = TypeAnnotation(TypeOperator::LINK,{}); + link.conjuctionId = signatures.at(signature); + + return ExpandedType(move(link)); + } + + int cid = signatures.size(); + signatures[signature] = cid; + TypeAnnotation tyResult = expandType(ty, operands); + tyResult.conjuctionId = cid; + + return ExpandedType(move(tyResult)); + }; + + case TypeOperator::CUSTOM: + { + if (signatures.count(t)) { + return ExpandedType(TypeAnnotation(TypeOperator::LINK, {t})); + } + signatures.emplace(t, signatures.size()); + + std::string alias = t.__valueCustom; + + //find in local scope: + if (scope.count(alias)) { + return expandType(scope.at(alias)); + } - } 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 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 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"); - } + //Find in global scope: + } else if ((ast->__indexTypeAliases.count(alias))) { + tyAlias = expandType(ast->__indexTypeAliases.at(alias)); - 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"); + } else { + assert(false && "Undefined or external type"); + } + + assert(tyAlias->__operator == TypeOperator::LIST_NAMED); - int fieldId = fieldIt - tyAlias->fields.begin(); - tyAlias = expandType(tyAlias->__operands.at(fieldId)); - } + for (const string& field : t.fields) { + auto fieldIt = std::find(tyAlias->fields.begin(), tyAlias->fields.end(), field); + assert(fieldIt != tyAlias->fields.end() && "unknown field"); - return tyAlias; - } + int fieldId = fieldIt - tyAlias->fields.begin(); + tyAlias = expandType(tyAlias->__operands.at(fieldId)); + } - case TypeOperator::TUPLE: { - assert(t.__operands.size()); + return tyAlias; + } - std::vector pack; - pack.reserve(t.__operands.size()); + case TypeOperator::NONE: + { + return ExpandedType(TypeAnnotation(t)); + } - std::transform(t.__operands.begin(), t.__operands.end(), std::inserter(pack, pack.end()), - [this](const TypeAnnotation& t){ - return expandType(t); - }); + case TypeOperator::SLAVE: + { + return ExpandedType(t); + } - return ExpandedType(TypeAnnotation(TypeOperator::TUPLE, move(pack))); - } - - case TypeOperator::VARIANT: { - return ExpandedType(TypeAnnotation(t)); - } + default: + assert(false); + } - case TypeOperator::NONE: { - return ExpandedType(TypeAnnotation(t)); - } - - default: - assert(false); - } - - assert(false); - return ExpandedType(TypeAnnotation()); - } + assert(false); + return ExpandedType(TypeAnnotation()); + } }; TypeAnnotation::TypeAnnotation() -{ +: __operator(TypeOperator::NONE), __value(TypePrimitive::Invalid) { } -TypeAnnotation::TypeAnnotation(const Atom &typ) - : __value(typ.get()) -{ - ; +TypeAnnotation::TypeAnnotation(TypePrimitive typ) +: __value(typ) { } -TypeAnnotation::TypeAnnotation (TypePrimitive typ) - : __value(typ) -{} - TypeAnnotation::TypeAnnotation(TypeOperator op, std::initializer_list operands) - : __operator(op), __operands(operands) -{ +: __operator(op), __operands(operands) { } -TypeAnnotation::TypeAnnotation (TypeOperator op, std::vector&& operands) - : __operator(op), __operands(operands) -{} +TypeAnnotation::TypeAnnotation(TypeOperator op, std::vector&& operands) +: __operator(op), __operands(operands) { +} +TypeAnnotation::TypeAnnotation(llvm_array_tag, TypeAnnotation typ, int size) +: TypeAnnotation(TypeOperator::LIST,{typ}) { + __size = size; +} -TypeAnnotation::TypeAnnotation (llvm_array_tag, TypeAnnotation typ, int size) - :TypeAnnotation(TypeOperator::ARRAY, {typ}) -{ - __size=size; +bool +TypeAnnotation::isValid() const { + return !(__value == TypePrimitive::Invalid && __operator == TypeOperator::NONE); } bool -TypeAnnotation::operator< (const TypeAnnotation& t) const{ - if (__operator != t.__operator) return __operator < t.__operator; +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::NONE) + return __value < t.__value; - if (__operator == TypeOperator::CALL || __operator == TypeOperator::CUSTOM || __operator == TypeOperator::ACCESS){ - if (__valueCustom != t.__valueCustom) - return __valueCustom < t.__valueCustom; - } + if (__operator == TypeOperator::CALL || __operator == TypeOperator::CUSTOM || __operator == TypeOperator::ACCESS) { + if (__valueCustom != t.__valueCustom) + return __valueCustom < t.__valueCustom; + } - return __operands < t.__operands; + return __operands < t.__operands; } /* TypeAnnotation (struct_tag, std::initializer_list) {} -*/ + */ void -TypeAnnotation::addBindings(std::vector>&& params) -{ - bindings.reserve(bindings.size() + params.size()); +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(); }); + [](const Atom& ident) { + return ident.get(); }); } void -TypeAnnotation::addFields(std::vector>&& listFields) -{ +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(); }); + [](const Atom& ident) { + return ident.get(); }); } +unsigned int Expression::nextVacantId = 0; + Expression::Expression(const Atom& number) -: __state(NUMBER), op(Operator::NONE), __valueD(number.get()) -{ +: Expression() { + __state = NUMBER; + op = Operator::INVALID; + __valueD = number.get(); } Expression::Expression(const Atom& a) - : __state(STRING), op(Operator::NONE), __valueS(a.get()) -{ +: Expression() { + __state = STRING; + op = Operator::INVALID; + __valueS = a.get(); } Expression::Expression(const Atom &ident) - : __state(IDENT), op(Operator::NONE), __valueS(ident.get()) -{ +: Expression() { + __state = IDENT; + op = Operator::INVALID; + __valueS = ident.get(); } Expression::Expression(const Operator &oprt, std::initializer_list params) - : __state(COMPOUND), op(oprt) -{ - if (op == Operator::CALL) - { +: Expression() { + __state = COMPOUND; + op = oprt; + + if (op == Operator::CALL) { assert(params.size() > 0); Expression arg = *params.begin(); assert(arg.__state == Expression::IDENT); __valueS = std::move(arg.__valueS); - operands.insert(operands.end(), params.begin()+1, params.end()); + operands.insert(operands.end(), params.begin() + 1, params.end()); return; } operands.insert(operands.end(), params.begin(), params.end()); } void -Expression::setOp(Operator oprt) -{ +Expression::setOp(Operator oprt) { op = oprt; - switch (op) - { - case Operator::NONE: + switch (op) { + case Operator::INVALID: __state = INVALID; break; default: __state = COMPOUND; break; } } void -Expression::addArg(Expression &&arg) -{ +Expression::addArg(Expression &&arg) { operands.push_back(arg); } void -Expression::addBindings(std::initializer_list> params) -{ +Expression::addTags(const std::list tags) const { + std::transform(tags.begin(), tags.end(), std::inserter(this->tags, this->tags.end()), + [](const Expression & tag) { + return make_pair(tag.getValueString(), tag); + }); +} + +void +Expression::addBindings(std::initializer_list> params) { addBindings(params.begin(), params.end()); } void -Expression::bindType(TypeAnnotation t) -{ +Expression::bindType(TypeAnnotation t) { type = move(t); } void -Expression::addBlock(ManagedScpPtr scope) -{ - blocks.push_back(scope.operator ->()); +Expression::addBlock(ManagedScpPtr scope) { + blocks.push_back(scope.operator->()); } const std::vector& -Expression::getOperands() const -{ +Expression::getOperands() const { return operands; } double -Expression::getValueDouble() const -{ +Expression::getValueDouble() const { return __valueD; } const std::string& -Expression::getValueString() const -{ +Expression::getValueString() const { return __valueS; } void -Expression::setValue(const Atom&& v){ +Expression::setValue(const Atom&& v) { __valueS = v.get(); } -void Expression::setValueDouble(double value){ - __valueD = value; +void Expression::setValueDouble(double value) { + __valueD = value; } bool -Expression::isValid() const{ +Expression::isValid() const { return (__state != INVALID); } bool -Expression::isDefined() const{ - return (__state != BINDING); +Expression::isDefined() const { + return (__state != BINDING && __state != INVALID); } Expression::Expression() - : __state(INVALID), op(Operator::NONE) -{} - -bool -Expression::operator==(const Expression& other) const{ - assert(!this->blocks.size()); - assert(!other.blocks.size()); - - if (this->__state != other.__state) return false; - - if (ExpressionHints::isStringValueValid(*this)){ - if (this->__valueS != other.__valueS) return false; - } - - if (ExpressionHints::isDoubleValueValid(*this)){ - if (this->__valueD != other.__valueD) return false; - } - - if (this->__state != Expression::COMPOUND){ - return true; - } - - if (this->operands.size() != other.operands.size()){ - return false; - } - - for (size_t i=0; ioperands.size(); ++i){ - if (!(this->operands[i]==other.operands[i])) return false; - } - - return true; +: __state(INVALID), op(Operator::INVALID), id(nextVacantId++) { } +namespace details { namespace inconsistent { -AST::AST() -{ +AST::AST() { + Attachments::init(); + Attachments::init(); + Attachments::init(); + Attachments::init(); } - void -AST::addInterfaceData(const ASTInterface& interface, Expression&& data ) { - __interfacesData.emplace(interface, move(data)); +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) -{ +AST::add(Function* f) { __functions.push_back(f); - __indexFunctions.emplace(f->getName(), __functions.size()-1); + __indexFunctions.emplace(f->getName(), __functions.size() - 1); } void -AST::add(MetaRuleAbstract *r) -{ +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)); - } - } +AST::add(TypeAnnotation t, Atom alias) { + if (t.__operator == TypeOperator::VARIANT) { + for (int i = 0, size = t.fields.size(); i < size; ++i) { + __dictVariants.emplace(t.fields[i], make_pair(t, i)); + } + } __indexTypeAliases.emplace(alias.get(), move(t)); } ManagedScpPtr -AST::add(CodeScope* scope) -{ +AST::add(CodeScope* scope) { this->__scopes.push_back(scope); - return ManagedScpPtr(this->__scopes.size()-1, &this->__scopes); + return ManagedScpPtr(this->__scopes.size() - 1, &this->__scopes); } std::string -AST::getModuleName() -{ +AST::getModuleName() { const std::string name = "moduleTest"; return name; } ManagedPtr -AST::findFunction(const std::string& name) -{ +AST::findFunction(const std::string& name) { int count = __indexFunctions.count(name); if (!count) { - return ManagedFnPtr::Invalid(); + return ManagedFnPtr::Invalid(); } - assert(count ==1); + assert(count == 1); auto range = __indexFunctions.equal_range(name); return ManagedPtr(range.first->second, &this->__functions); } std::list -AST::getAllFunctions() const{ - const size_t size = __functions.size(); +AST::getAllFunctions() const { + const size_t size = __functions.size(); - std::list result; - for (size_t i=0; i__functions)); - } + std::list result; + for (size_t i = 0; i < size; ++i) { + result.push_back(ManagedFnPtr(i, &this->__functions)); + } - return result; + return result; } //TASK select default specializations std::list -AST::getFunctionVariants(const std::string& name) const{ - auto functions = __indexFunctions.equal_range(name); +AST::getFunctionSpecializations(const std::string& fnName) const { + auto functions = __indexFunctions.equal_range(fnName); - std::list result; - std::transform(functions.first, functions.second, inserter(result, result.end()), - [this](auto f){return ManagedFnPtr(f.second, &this->__functions);}); + std::list result; + std::transform(functions.first, functions.second, inserter(result, result.end()), + [this](auto f) { + return ManagedFnPtr(f.second, &this->__functions); + }); - return result; + return result; } - template<> +template<> ManagedPtr -AST::begin() -{return ManagedPtr(0, &this->__functions);} +AST::begin() { + return ManagedPtr(0, &this->__functions); +} template<> ManagedPtr -AST::begin() -{return ManagedPtr(0, &this->__scopes);} +AST::begin() { + return ManagedPtr(0, &this->__scopes); +} template<> ManagedPtr -AST::begin() -{return ManagedPtr(0, &this->__rules);} +AST::begin() { + return ManagedPtr(0, &this->__rules); +} +void +AST::recognizeVariantConstructor(Expression& function) { + assert(function.op == Operator::CALL); -Expanded -AST::expandType(const TypeAnnotation &t) const -{ - return TypesResolver(this)(t); + std::string variant = function.getValueString(); + if (!__dictVariants.count(variant)) { + return; + } + + auto record = __dictVariants.at(variant); + const TypeAnnotation& typ = record.first; + + function.op = Operator::VARIANT; + function.setValueDouble(record.second); + function.type = typ; } -Expanded -AST::findType(const std::string& name){ - // find in general scope: - if(__indexTypeAliases.count(name)) - return expandType(__indexTypeAliases.at(name)); +Atom +AST::recognizeVariantConstructor(Atom ident) { + std::string variant = ident.get(); + assert(__dictVariants.count(variant) && "Can't recognize variant constructor"); + auto record = __dictVariants.at(variant); - //if type is unknown keep it as is. - TypeAnnotation t(TypeOperator::CUSTOM, {}); - t.__valueCustom = name; - return ExpandedType(move(t)); + return Atom(record.second); +} + +void +AST::postponeIdentifier(CodeScope* scope, const Expression& id) { + bucketUnrecognizedIdentifiers.emplace(scope, id); } void -AST::recognizeVariantIdentifier(Expression& identifier){ +AST::recognizePostponedIdentifiers() { + for (const auto& identifier : bucketUnrecognizedIdentifiers) { + if (!identifier.first->recognizeIdentifier(identifier.second)) { + //exception: Ident not found + std::cout << "Unknown symbol: " << identifier.second.getValueString() << std::endl; + assert(false && "Symbol not found"); + } + } +} + +xreate::AST* +AST::finalize() { + //all finalization steps: + recognizePostponedIdentifiers(); -// TODO get rid of findSymbol. Determine symbol while AST parsing. Re-find symbols not found while first pass. -// * move to codescope -// * use findSymbol to find Symbol -// * register var as alias to -// * ident __doubleValue holds VID of an alias + return reinterpret_cast (this); +} + +} } //namespace details::incomplete + +Expanded +AST::findType(const std::string& name) { + // find in general scope: + if (__indexTypeAliases.count(name)) + return expandType(__indexTypeAliases.at(name)); - assert(identifier.__state == Expression::IDENT); + //if type is unknown keep it as is. + TypeAnnotation t(TypeOperator::CUSTOM,{}); + t.__valueCustom = name; + return ExpandedType(move(t)); +} - std::string name = identifier.getValueString(); - if (__dictVariants.count(name)){ - auto record = __dictVariants.at(name); - const TypeAnnotation& typ = record.first; +Expanded +AST::expandType(const TypeAnnotation &t) const { + return TypesResolver(this)(t); +} - identifier.__state = Expression::VARIANT; - identifier.setValueDouble(record.second); - identifier.type = typ; - } +ExpandedType +AST::getType(const Expression& expression) { + return typeinference::getType(expression, *this); } Function::Function(const Atom& name) - : __entry(new CodeScope(0)) -{ +: __entry(new CodeScope(0)) { __name = name.get(); } void -Function::addTag(Expression&& tag, const TagModifier mod) -{ +Function::addTag(Expression&& tag, const TagModifier mod) { string name = tag.getValueString(); __tags.emplace(move(name), move(tag)); } const std::map& -Function::getTags() const -{ +Function::getTags() const { return __tags; } CodeScope* -Function::getEntryScope() const -{ +Function::getEntryScope() const { return __entry; } void -Function::addBinding(Atom && name, Expression&& argument) -{ - __entry->addBinding(move(name), move(argument)); +Function::addBinding(Atom && name, Expression&& argument, const VNameId hintBindingId) { + __entry->addBinding(move(name), move(argument), hintBindingId); } -void -Function::setReturnType(const TypeAnnotation &rtyp) -{ +const std::string& +Function::getName() const { + return __name; +} + +ScopedSymbol +CodeScope::registerIdentifier(const Expression& identifier, const VNameId hintBindingId) { + versions::VariableVersion version = Attachments::get(identifier, versions::VERSION_NONE); - __entry->__declarations[0].type = rtyp; + auto result = __identifiers.emplace(identifier.getValueString(), hintBindingId? hintBindingId: __identifiers.size() + 1); + return { result.first->second, version }; } -const std::string& -Function::getName() const -{ - return __name; +bool +CodeScope::recognizeIdentifier(const Expression& identifier) const { + versions::VariableVersion version = Attachments::get(identifier, versions::VERSION_NONE); + const std::string& name = identifier.getValueString(); + + //search identifier in the current block + if (__identifiers.count(name)) { + VNameId id = __identifiers.at(name); + + Symbol s; + s.identifier = ScopedSymbol{id, version}; + s.scope = const_cast (this); + Attachments::put(identifier, s); + + return true; + } + + //search in the parent scope + if (__parent) { + return __parent->recognizeIdentifier(identifier); + } + + return false; } -Symbol -CodeScope::registerIdentifier(Atom &&name) -{ - __identifiers.emplace(name.get(), ++__vCounter); - return {__vCounter, this}; +ScopedSymbol +CodeScope::getSymbol(const std::string& alias) { + assert(__identifiers.count(alias)); + VNameId id = __identifiers.at(alias); + + return {id, versions::VERSION_NONE }; } void -CodeScope::addBinding(Atom && name, Expression&& argument) -{ - __bindings.push_back(name.get()); - Symbol binding = registerIdentifier(move(name)); +CodeScope::addBinding(Expression&& var, Expression&& argument, const VNameId hintBindingId) { argument.__state = Expression::BINDING; - __declarations[binding.identifier] = move(argument); + + __bindings.push_back(var.getValueString()); + ScopedSymbol binding = registerIdentifier(var, hintBindingId); + __declarations[binding] = move(argument); } -void -CodeScope::addDeclaration(Atom && name, Expression&& body) -{ - Symbol s = registerIdentifier(move(name)); - __declarations[s.identifier] = move(body); +Symbol +CodeScope::addDefinition(Expression&& var, Expression&& body) { + ScopedSymbol s = registerIdentifier(var); + __declarations[s] = move(body); + + return Symbol{s, this}; } CodeScope::CodeScope(CodeScope* parent) - :__parent(parent) -{} +: __parent(parent) { +} -CodeScope::~CodeScope() -{} +CodeScope::~CodeScope() { +} void -CodeScope::setBody(const Expression &body) -{ - __declarations[0] = body; +CodeScope::setBody(const Expression &body) { + assert(__declarations.count(ScopedSymbol::RetSymbol)==0 && "Attempt to reassign scope body"); + __declarations[ScopedSymbol::RetSymbol] = body; } -Expression& -CodeScope::getBody(){ - return __declarations[0]; +const Expression& +CodeScope::getBody() const{ + return __declarations.at(ScopedSymbol::RetSymbol); } -Symbol -CodeScope::findSymbol(const std::string &name) -{ - //search identifier in the current block - if (__identifiers.count(name)) - { - VID vId = __identifiers.at(name); - Symbol result{vId, this}; - return result; - } - - //search in the parent scope - if (__parent) - { - return __parent->findSymbol(name); - } - - //exception: Ident not found - std::cout << "Unknown symbol: "<< name << std::endl; - assert(false && "Symbol not found"); +const Expression& +CodeScope::getDefinition(const Symbol& symbol, bool flagAllowUndefined){ + const CodeScope* self = symbol.scope; + return self->getDefinition(symbol.identifier, flagAllowUndefined); } const Expression& -CodeScope::findDeclaration(const Symbol& symbol) -{ - CodeScope* self = symbol.scope; - return self->__declarations[symbol.identifier]; -} +CodeScope::getDefinition(const ScopedSymbol& symbol, bool flagAllowUndefined) const{ + static Expression expressionInvalid; + if (!__declarations.count(symbol)){ + if (flagAllowUndefined) return expressionInvalid; + assert(false && "Symbol's declaration not found"); + } + return __declarations.at(symbol); +} void -RuleArguments::add(const Atom &arg, DomainAnnotation typ) -{ +RuleArguments::add(const Atom &arg, DomainAnnotation typ) { emplace_back(arg.get(), typ); } void -RuleGuards::add(Expression&& e) -{ +RuleGuards::add(Expression&& e) { push_back(e); } MetaRuleAbstract:: MetaRuleAbstract(RuleArguments&& args, RuleGuards&& guards) - : __args(std::move(args)), __guards(std::move(guards)) -{} +: __args(std::move(args)), __guards(std::move(guards)) { +} -MetaRuleAbstract::~MetaRuleAbstract(){} +MetaRuleAbstract::~MetaRuleAbstract() { +} RuleWarning:: RuleWarning(RuleArguments&& args, RuleGuards&& guards, Expression&& condition, Atom&& message) - : MetaRuleAbstract(std::move(args), std::move(guards)), __message(message.get()), __condition(condition) -{} +: MetaRuleAbstract(std::move(args), std::move(guards)), __message(message.get()), __condition(condition) { +} -RuleWarning::~RuleWarning(){} +RuleWarning::~RuleWarning() { +} void -RuleWarning::compile(ClaspLayer& layer) -{ - //TODO restore addRuleWarning +RuleWarning::compile(TranscendLayer& layer) { + //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__state != other.__state) return false; + + if (ExpressionHints::isStringValueValid(*this)) { + if (this->__valueS != other.__valueS) return false; + } + + if (ExpressionHints::isDoubleValueValid(*this)) { + if (this->__valueD != other.__valueD) return false; + } + if (this->__state != Expression::COMPOUND) { + return true; + } + + if (this->op != other.op) { + return false; + } + + if (this->operands.size() != other.operands.size()) { + return false; + } + + for (size_t i = 0; ioperands.size(); ++i) { + if (!(this->operands[i] == other.operands[i])) return false; + } + + assert(!this->blocks.size()); + assert(!other.blocks.size()); + + return true; } +const ScopedSymbol +ScopedSymbol::RetSymbol = ScopedSymbol{0, versions::VERSION_NONE}; + +} //end of namespace xreate + + + diff --git a/cpp/src/ast.h b/cpp/src/ast.h index cd070ab..768092f 100644 --- a/cpp/src/ast.h +++ b/cpp/src/ast.h @@ -1,562 +1,740 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * Author: pgess + * File: ast.h + */ + #ifndef AST_H #define AST_H #include "attachments.h" #include #include #include #include #include #include #include #include "utils.h" #include namespace llvm { class Value; } namespace xreate { + struct ScopedSymbol; + struct Symbol; +} - 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, Num, Int, I32, I8, Float, String, - }; - - 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 == "num") { - __value = TypePrimitive::Num; - } else if (buffer == "int") { - __value = TypePrimitive::Int; - } else if (buffer == "i8") { - __value = TypePrimitive::I8; - } else if (buffer == "i32") { - __value = TypePrimitive::I32; - } else if (buffer == "float") { - __value = TypePrimitive::Float; - - } 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 { +namespace std { + template<> + struct hash { + std::size_t operator()(xreate::ScopedSymbol const& s) const; }; - struct struct_tag { + template<> + struct equal_to { + bool operator()(const xreate::ScopedSymbol& __x, const xreate::ScopedSymbol& __y) const; }; - 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: + template<> + struct hash { + size_t operator()(xreate::Symbol const& s) const; }; - enum class Operator { - ADD, SUB, MUL, DIV, EQU, NE, NEG, LSS, LSE, GTR, GTE, LIST, LIST_RANGE, LIST_NAMED, CALL, NONE, IMPL/* implication */, MAP, FOLD, FOLD_INF, LOOP_CONTEXT, INDEX, IF, SWITCH, SWITCH_ADHOC, CASE, CASE_DEFAULT, LOGIC_AND, ADHOC, CONTEXT_RULE, SEQUENCE + template<> + struct equal_to { + bool operator()(const xreate::Symbol& __x, const xreate::Symbol& __y) const; }; +} - 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; - }; +namespace xreate { - typedef ManagedPtr ManagedFnPtr; - typedef ManagedPtr ManagedScpPtr; - typedef ManagedPtr ManagedRulePtr; - const ManagedScpPtr NO_SCOPE = ManagedScpPtr(UINT_MAX, 0); - - //To update ExpressionHints in case of any changes - struct Expression { - friend class CodeScope; - friend class ClaspLayer; - friend class CFAPass; - friend class ExpressionHints; - - Expression(const Operator &oprt, std::initializer_list params); - Expression(const Atom& ident); - Expression(const Atom& number); - Expression(const Atom& a); - Expression(); - - void setOp(Operator oprt); - void addArg(Expression&& arg); - void addBindings(std::initializer_list> params); - void bindType(TypeAnnotation t); - - template - void addBindings(InputIt paramsBegin, InputIt paramsEnd); - - void addBlock(ManagedScpPtr scope); - - const std::vector& getOperands() const; - double getValueDouble() const; - void setValueDouble(double value); - const std::string& getValueString() const; - void setValue(const Atom&& v); - bool isValid() const; - bool isDefined() const; - - - bool operator==(const Expression& other) const; - - enum { - INVALID, COMPOUND, IDENT, NUMBER, STRING, VARIANT, BINDING - } __state = INVALID; - Operator op; - std::vector bindings; - std::map __indexBindings; - std::vector operands; - TypeAnnotation type; - - mutable std::map tags; - mutable Attachments tagsInternal; - std::list blocks; - - private: - std::string __valueS; - double __valueD; - }; - - bool operator< (const Expression&, const Expression&); +struct String_t { +}; + +struct Identifier_t { +}; + +struct Number_t { +}; + +struct Type_t { +}; + +template +class Atom { +}; + +//DEBT store line:col for all atoms/identifiers +template<> class +Atom { +public: + Atom(const std::wstring& value); + Atom(std::string && name); + const std::string& get() const; + +private: + std::string __value; +}; + +template<> +class Atom { +public: + Atom(wchar_t* value); + Atom(int value); + double get()const; + +private: + double __value; +}; + +template<> +class Atom { +public: + Atom(const std::wstring& value); + Atom(std::string && name); + const std::string& get() const; + +private: + std::string __value; +}; + +enum class TypePrimitive { + Invalid, Bool, I8, I32, I64, Num, Int, Float, String +}; + +enum class TypeOperator { + NONE, CALL, CUSTOM, VARIANT, LIST, LIST_NAMED, ACCESS, LINK, SLAVE +}; + +struct llvm_array_tag { +}; + +struct struct_tag { +}; +const llvm_array_tag tag_array = llvm_array_tag(); +const struct_tag tag_struct = struct_tag(); + +/** + * \brief Represents type to support type system + * + * This class represents type in denormalized form, i.e. without arguments and aliases substitution + * \sa AST::expandType() + */ +class TypeAnnotation { +public: + TypeAnnotation(); + TypeAnnotation(const Atom& typ); + TypeAnnotation(TypePrimitive typ); + TypeAnnotation(llvm_array_tag, TypeAnnotation typ, int size); + + TypeAnnotation(TypeOperator op, std::initializer_list operands); + TypeAnnotation(TypeOperator op, std::vector&& operands); + void addBindings(std::vector>&& params); + void addFields(std::vector>&& listFields); + bool operator<(const TypeAnnotation& t) const; + // TypeAnnotation (struct_tag, std::initializer_list); + + bool isValid() const; + + TypeOperator __operator = TypeOperator::NONE; + + std::vector __operands; + TypePrimitive __value; + std::string __valueCustom; + int conjuctionId = -1; //conjunction point id (relevant for recursive types) + + uint64_t __size = 0; + std::vector fields; + std::vector bindings; +private: +}; + +enum class Operator { + INVALID, UNDEF, ADD, SUB, MUL, DIV, + EQU, NE, NEG, LSS, + LSE, GTR, GTE, LIST, + LIST_RANGE, LIST_NAMED, + CALL, CALL_INTRINSIC, QUERY, QUERY_LATE, + IMPL/* implication */, MAP, + FOLD, FOLD_INF, INDEX, + IF, SWITCH, SWITCH_VARIANT, SWITCH_LATE, + CASE, CASE_DEFAULT, LOGIC_AND, + CONTEXT_RULE, VARIANT, SEQUENCE +}; + +class Function; +class AST; +class CodeScope; +class MetaRuleAbstract; + +typedef ManagedPtr ManagedFnPtr; +typedef ManagedPtr ManagedScpPtr; +typedef ManagedPtr ManagedRulePtr; +const ManagedScpPtr NO_SCOPE = ManagedScpPtr(UINT_MAX, 0); + +/** + * \brief Represents every instruction in Xreate's syntax tree + * \attention In case of any changes update xreate::ExpressionHints auxiliary helper as well + * + * Expression is generic building block of syntax tree able to hold node data + * as well as child nodes as operands. Not only instructions use expression for representation in syntax tree + * but annotation as well. + * + * Additionally, `types` as a special kind of annotations use Expression-like data structure TypeAnnotation + * \sa xreate::AST, xreate::TypeAnnotation + */ +// +struct Expression { + friend class CodeScope; + friend class TranscendLayer; + friend class CFAPass; + friend class ExpressionHints; + + Expression(const Operator &oprt, std::initializer_list params); + Expression(const Atom& ident); + Expression(const Atom& number); + Expression(const Atom& a); + + Expression(); + + void setOp(Operator oprt); + void addArg(Expression&& arg); + void addBindings(std::initializer_list> params); + void bindType(TypeAnnotation t); template - void 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; - }); - } + void addBindings(InputIt paramsBegin, InputIt paramsEnd); + void addTags(const std::list tags) const; + void addBlock(ManagedScpPtr scope); - typedef std::list ExpressionList; + const std::vector& getOperands() const; + double getValueDouble() const; + void setValueDouble(double value); + const std::string& getValueString() const; + void setValue(const Atom&& v); + bool isValid() const; + bool isDefined() const; - 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; + bool operator==(const Expression& other) const; + /** + * \brief is it string, number, compound operation and so on + */ + enum { + INVALID, COMPOUND, IDENT, NUMBER, STRING, BINDING + } __state = INVALID; - /* - class Expression: ExpressionAbstract - { - friend class CFGPass; + /** + * \brief Valid for compound State. Holds type of compound operator + */ + Operator op; + + /** + * \brief Unique id to identify expression within syntax tree + */ + unsigned int id; + + /** + * \brief Exact meaning depends on particular instruction + * \details As an example, named lists/structs hold field names in bindings + */ + std::vector bindings; + std::map __indexBindings; + + /** + * \brief Holds child instructions as arguments + */ + std::vector operands; + + /** + * \brief Holds type of instruction's result + */ + TypeAnnotation type; - public: - llvm::Value* compile(LLVMLayer& l, Function* f, std::string* hintRetVar=0) const; - }; + /** + * \brief Holds additional annotations + */ + mutable std::map tags; + + /** + * \brief Child code blocks + * \details For example, If statement holds TRUE-branch as first and FALSE-branch as second block here */ + std::list blocks; +private: + std::string __valueS; + double __valueD; + static unsigned int nextVacantId; +}; - typedef std::pair Tag; +bool operator<(const Expression&, const Expression&); - struct Symbol { - VID identifier; - CodeScope * scope; - }; +template +void Expression::addBindings(InputIt paramsBegin, InputIt paramsEnd) { + size_t index = bindings.size(); - bool operator<(const Symbol& s1, const Symbol& s2); - bool operator==(const Symbol& s1, const Symbol& s2); + 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; + }); +} - class CodeScope { - friend class Function; - friend class PassManager; +typedef std::list ExpressionList; - public: - CodeScope(CodeScope* parent = 0); - void setBody(const Expression& body); - Expression& getBody(); - void addDeclaration(Atom && name, Expression&& body); - void addBinding(Atom && name, Expression&& argument); - Symbol findSymbol(const std::string &name); - static const Expression& findDeclaration(const Symbol& symbol); - - ~CodeScope(); - - std::vector __bindings; - std::map __identifiers; - /** - * definition of return type has variable index Zero(0) - */ - //TODO move __definitions to SymbolsAttachments data - std::unordered_map __declarations; - std::vector tags; - std::vector contextRules; - - private: - VID __vCounter = 0; - CodeScope* __parent; - - Symbol registerIdentifier(Atom && name); - }; +enum class TagModifier { + NONE, ASSERT, REQUIRE +}; - class Function { - friend class Expression; - friend class CodeScope; - friend class AST; +enum class DomainAnnotation { + FUNCTION, VARIABLE +}; +class RuleArguments : public std::vector> +{ public: - Function(const Atom& name); - - void addBinding(Atom && name, Expression&& argument); - void addTag(Expression&& tag, const TagModifier mod); - - void setReturnType(const TypeAnnotation& rtyp); - - const std::string& getName() const; - const std::map& getTags() const; - CodeScope* getEntryScope() const; - CodeScope* __entry; - std::string __name; - bool isPrefunction = false; //SECTIONTAG adhoc Function::isPrefunction flag - - Expression guardContext; - private: + void add(const Atom& name, DomainAnnotation typ); +}; + +class RuleGuards : public std::vector { +public: + void add(Expression&& e); +}; + + +class TranscendLayer; +class LLVMLayer; + +class MetaRuleAbstract { +public: + MetaRuleAbstract(RuleArguments&& args, RuleGuards&& guards); + virtual ~MetaRuleAbstract(); + virtual void compile(TranscendLayer& layer) = 0; +protected: + RuleArguments __args; + RuleGuards __guards; +}; + +class RuleWarning : public MetaRuleAbstract { + friend class TranscendLayer; +public: + RuleWarning(RuleArguments&& args, RuleGuards&& guards, Expression&& condition, Atom&& message); + virtual void compile(TranscendLayer& layer); + ~RuleWarning(); + +private: + std::string __message; + Expression __condition; +}; + +typedef unsigned int VNameId; + +namespace versions { + typedef int VariableVersion; + const VariableVersion VERSION_NONE = -2; + const VariableVersion VERSION_INIT = 0; +} - std::map __tags; - }; +template<> +struct AttachmentsDict { + typedef versions::VariableVersion Data; + static const unsigned int key = 6; +}; + +struct ScopedSymbol { + VNameId id; + versions::VariableVersion version; + + static const ScopedSymbol RetSymbol; +}; + +struct Symbol { + ScopedSymbol identifier; + const CodeScope * scope; +}; + +struct IdentifierSymbol{}; +struct SymbolAlias{}; + +template<> +struct AttachmentsDict { + typedef Symbol Data; + static const unsigned int key = 7; +}; + +template<> +struct AttachmentsDict { + typedef Symbol Data; + static const unsigned int key = 9; +}; + +typedef std::pair Tag; + +bool operator<(const ScopedSymbol& s1, const ScopedSymbol& s2); +bool operator==(const ScopedSymbol& s1, const ScopedSymbol& s2); +bool operator<(const Symbol& s1, const Symbol& s2); +bool operator==(const Symbol& s1, const Symbol& s2); + +/** + * \brief Represents code block and single scope of visibility + * + * Holds single expression as a *body* and set of variable assignments(declarations) used in body's expression + * \sa xreate::AST + */ +class CodeScope { + friend class Function; + friend class PassManager; + +public: + CodeScope(CodeScope* parent = 0); + ~CodeScope(); + + /** \brief Set expression as a body */ + void setBody(const Expression& body); + + /** \brief Returns current code scope body */ + const Expression& getBody() const; + + /** \brief Adds variable definition to be used in body as well as in other declarations */ + Symbol addDefinition(Expression&& var, Expression&& body); + /** \brief Returns symbols' definition */ + static const Expression& getDefinition(const Symbol& symbol, bool flagAllowUndefined = false); + const Expression& getDefinition(const ScopedSymbol& symbol, bool flagAllowUndefined = false) const; + + /** \brief Adds variable defined elsewhere */ + void addBinding(Expression&& var, Expression&& argument, const VNameId hintBindingId = 0); + + std::vector __bindings; + std::map __identifiers; + CodeScope* __parent; + + //TODO move __definitions to SymbolsAttachments data + //NOTE: definition of return type has index 0 + std::unordered_map __declarations; + std::vector tags; + std::vector contextRules; + +private: + ScopedSymbol registerIdentifier(const Expression& identifier, const VNameId hintBindingId = 0); + +public: + bool recognizeIdentifier(const Expression& identifier) const; + ScopedSymbol getSymbol(const std::string& alias); +}; + +/** + * \brief Represents single function in Xreate's syntax tree + * + * Holds an entry code scope and `guardContext` required for function to operate + * \sa xreate::AST + */ +class Function { + friend class Expression; + friend class CodeScope; + friend class AST; + +public: + Function(const Atom& name); + + /** + * \brief Adds function arguments + */ + void addBinding(Atom && name, Expression&& argument, const VNameId hintBindingId=0); + + /** + * \brief Adds additional function annotations + */ + void addTag(Expression&& tag, const TagModifier mod); - class ExternData; + const std::string& getName() const; + const std::map& getTags() const; + CodeScope* getEntryScope() const; + CodeScope* __entry; + std::string __name; + bool isPrefunction = false; //SECTIONTAG adhoc Function::isPrefunction flag - struct ExternEntry { - std::string package; - std::vector headers; - }; + Expression guard; +private: - typedef Expanded ExpandedType; + std::map __tags; +}; - enum ASTInterface { - CFA, DFA, Extern, Adhoc - }; - struct FunctionSpecialization { - std::string guard; - size_t id; - }; +class ExternData; - struct FunctionSpecializationQuery { - std::unordered_set context; - }; +struct ExternEntry { + std::string package; + std::vector headers; +}; - template<> - struct AttachmentsStorage { +typedef Expanded ExpandedType; - static Attachments* - get(const Symbol& s) { - return &s.scope->findDeclaration(s).tagsInternal; - } - }; +struct TypeInferred{}; +template<> +struct AttachmentsDict { + typedef ExpandedType Data; + static const unsigned int key = 11; +}; - template<> - struct AttachmentsStorage { +enum ASTInterface { + CFA, DFA, Extern, Adhoc +}; - static Attachments* - get(const Expression& e) { - return &e.tagsInternal; - } - }; +struct FunctionSpecialization { + std::string guard; + size_t id; +}; - class AST { - public: - AST(); +struct FunctionSpecializationQuery { + std::unordered_set context; +}; - //TASK extern and DFA interfaces move into addInterfaceData - /** - * DFA Interface - */ - void addDFAData(Expression&& data); +template<> +struct AttachmentsId{ + static unsigned int getId(const Expression& expression){ + return expression.id; + } +}; - /** - * Extern Interface - */ - void addExternData(ExternData&& data); +template<> +struct AttachmentsId{ + static unsigned int getId(const Symbol& s){ + return s.scope->__declarations.at(s.identifier).id; + } +}; - void addInterfaceData(const ASTInterface& interface, Expression&& data); - void add(Function* f); +template<> +struct AttachmentsId{ + static unsigned int getId(const ManagedFnPtr& f){ + const Symbol symbolFunction{ScopedSymbol::RetSymbol, f->getEntryScope()}; - void add(MetaRuleAbstract* r); - ManagedScpPtr add(CodeScope* scope); + return AttachmentsId::getId(symbolFunction); + } +}; - std::string getModuleName(); - ManagedPtr findFunction(const std::string& name); +template<> +struct AttachmentsId{ + static unsigned int getId(const CodeScope* scope){ + const Symbol symbolScope{ScopedSymbol::RetSymbol, scope}; + return AttachmentsId::getId(symbolScope); + } +}; - typedef std::multimap FUNCTIONS_REGISTRY; - std::list getAllFunctions() const; - std::list getFunctionVariants(const std::string& name) const; +template<> +struct AttachmentsId{ + static unsigned int getId(const unsigned int id){ + return id; + } +}; +class TypesResolver; +namespace details { namespace inconsistent { + + /** + * \brief Syntax tree under construction in inconsistent form + * + * Represents Syntax Tree under construction(**inconsistent state**). + * \attention Clients should use rather xreate::AST unless client's code explicitly works with Syntax Tree during construction. + * + * Typically instance only created by xreate::XreateManager and filled in by Parser + * \sa xreate::XreateManager::prepare(std::string&&) + */ +class AST { + friend class xreate::TypesResolver; +public: + AST(); + + /** + * \brief Adds new function to AST + * \param f Function to register + */ + void add(Function* f); - template - ManagedPtr begin(); + /** + * \brief Adds new declarative rule to AST + * \param r Declarative Rule + */ + void add(MetaRuleAbstract* r); + + /** \brief Registers new code block */ + ManagedScpPtr add(CodeScope* scope); + + /** + * \brief Add new type to AST + * @param t Type definition + * @param alias Typer name + */ + void add(TypeAnnotation t, Atom alias); - 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. + /** \brief Current module's name */ + std::string getModuleName(); + + /** + * \brief Looks for function with given name + * \param name Function name to find + * \note Requires that only one function exists under given name + * \return Found function + */ + ManagedPtr findFunction(const std::string& name); - private: - std::vector __rules; - std::vector __functions; - std::vector __scopes; + /** \brief Returns all function in AST */ + std::list getAllFunctions() const; + + /** + * \brief Returns all specializations of a function with a given name + * \param fnName function to find + * \return list of found function specializations + */ + std::list getFunctionSpecializations(const std::string& fnName) const; - FUNCTIONS_REGISTRY __indexFunctions; + /** + * \return First element in Functions/Scopes/Rules list depending on template parameter + * \tparam Target either Function or CodeScope or MetaRuleAbstract + */ + template + ManagedPtr begin(); + + /** + * \brief Performs all necessary steps after AST is built + * + * Performs all finzalisation steps and move AST into consistent state represented by xreate::AST + * \sa xreate::AST + * \return AST in consistent state + */ + xreate::AST* finalize(); + typedef std::multimap FUNCTIONS_REGISTRY; + + std::vector __externdata; + std::list __dfadata; //TODO move to more appropriate place + std::list __rawImports; //TODO move to more appropriate place + std::multimap __interfacesData; //TODO CFA data here. - // ***** 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::vector __rules; + std::vector __functions; + std::vector __scopes; + FUNCTIONS_REGISTRY __indexFunctions; + +protected: + std::map __indexTypeAliases; + +public: + /** + * \brief Stores DFA scheme for later use by DFA Pass + * + * Treats expression as a DFA scheme and feeds to a DFA Pass later + * \paramn Expression DFA Scheme + * \sa xreate::DFAPass + */ + void addDFAData(Expression&& data); + + /** \brief Stores data for later use by xreate::ExternLayer */ + void addExternData(ExternData&& data); - private: - std::map> __dictVariants; - ExpandedType expandType(const TypeAnnotation &t, std::map scope, - const std::vector &args = std::vector()) const; + /** + * \brief Generalized function to store particular data for later use by particular pass + * \param interface Particular Interface + * \param data Particular data + */ + void addInterfaceData(const ASTInterface& interface, Expression&& data); + - // ***** TYPES SECTION END ***** - }; + /**\name Symbols Recognition */ +///@{ +public: + //TODO revisit enums/variants, move to codescope + /** + * \brief Tries to find out whether expression is Variant constructor + */ + void recognizeVariantConstructor(Expression& function); + Atom recognizeVariantConstructor(Atom ident); - template<> - ManagedPtr - AST::begin(); +private: + std::map> __dictVariants; - template<> - ManagedPtr - AST::begin(); +public: + std::set> bucketUnrecognizedIdentifiers; - template<> - ManagedPtr - AST::begin(); +public: + /** + * \brief Postpones unrecognized identifier for future second round of recognition + * \param scope Code block identifier is encountered + * \param id Identifier + */ + void postponeIdentifier(CodeScope* scope, const Expression& id); + + /** \brief Second round of identifiers recognition done right after AST is fully constructed */ + void recognizePostponedIdentifiers(); +///@} +}; + +template<> +ManagedPtr +AST::begin(); + +template<> +ManagedPtr +AST::begin(); + +template<> +ManagedPtr +AST::begin(); + +} } // namespace details::incomplete + +/** + * \brief Xreate's Syntax Tree in consistent state + * + * Syntax Tree has two mutually exclusive possible states: + * - inconsistent state while AST is under construction. Represented by xreate::details::inconsistent::AST + * - consistent state when AST is built and finalize() is done. + * + * This class represents consistent state and should be used everywhere unless client's code explicitly works with AST under construction. + * Consistent AST enables access to additional functions(currently related to type management). + * \sa xreate::details::inconsistent::AST + */ +class AST : public details::inconsistent::AST { +public: + + AST() : details::inconsistent::AST() {} + + /** + * \brief Computes fully expanded form of type by substituting all arguments and aliases + * \param t Type to expand + * \return Expdanded or normal form of type + * \sa TypeAnnotation + */ + ExpandedType expandType(const TypeAnnotation &t) const; + + /** + * Searches type by given name + * \param name Typename to search + * \return Expanded or normal form of desired type + * \note if type name is not found returns new undefined type with this name + */ + ExpandedType findType(const std::string& name); + + /** + * Invokes Type Inference Analysis to find out expanded(normal) form expressions's type + * \sa typeinference.h + * \param expression + * \return Type of expression + */ + ExpandedType getType(const Expression& expression); +}; } #endif // AST_H diff --git a/cpp/src/attachments.cpp b/cpp/src/attachments.cpp index 83a54d1..a9f19f3 100644 --- a/cpp/src/attachments.cpp +++ b/cpp/src/attachments.cpp @@ -1,30 +1,20 @@ -// -// Created by pgess on 3/15/15. -// +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * Author: pgess + * File: attachments.cpp + * Date: 3/15/15 + */ -#include "attachments.h" +/** + * \file attachments.h + * \brief Attachments support: mechanism to attach additional data to AST nodes + */ -namespace xreate { - void* xreate::Attachments::put(unsigned int key, void *data) { - auto result = __data.emplace(key, data); - - void* ptrOld = nullptr; - if (!result.second){ - ptrOld = result.first->second; - result.first->second = data; - } - - return ptrOld; - } +#include "attachments.h" - void *xreate::Attachments::get(unsigned int key) { - assert(__data.count(key)); - return __data.at(key); - } +using namespace xreate; - bool - xreate::Attachments::exists(unsigned int key) - { - return __data.count(key)>0; - } -} \ No newline at end of file +std::vector +Attachments::__storage = std::vector(); diff --git a/cpp/src/attachments.h b/cpp/src/attachments.h index 03b8711..a9bc42b 100644 --- a/cpp/src/attachments.h +++ b/cpp/src/attachments.h @@ -1,124 +1,179 @@ -// -// Created by pgess on 3/15/15. -// +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * Author: pgess + * File: attachments.h + * Date: 3/15/15 + */ #ifndef _XREATE_ATTACHMENTS_H_ #define _XREATE_ATTACHMENTS_H_ -#include +#include +#include #include #include namespace xreate { //Attachments dictionary template struct AttachmentsDict { // typedef void Data; - // static const unsigned int key (current unreserved - 6); + // static const unsigned int key (next vacant id - 12); + +// Defined attachments: +//----------------------------------------------------- +// 1 containers::Implementation +// 3 interpretation::InterpretationData +// 5 interpretation::FunctionInterpretationData +// 6 VariableVersion +// 7 IdentifierSymbol +// 8 versions::VersionImposedDependency +// 9 SymbolAlias +// 11 TypeInferred }; - template - struct AttachmentsStorage - { - //static Attachments* get(const T&); + template + struct AttachmentsId{ + //static unsigned int getId(const Object& object); }; - namespace detail { + +template +class IAttachmentsContainer{ + protected: + virtual bool __exists(const unsigned int object)=0; + virtual Data& __get(const unsigned int object)=0; + virtual void __put(const unsigned int object, Data data)=0; - template - typename std::enable_if::value, void*>::type - __wrap(const Typ& value){ - return value; - } - - template - typename std::enable_if::value, Typ>::type - __unwrap(void* value){ - return reinterpret_cast(value); + public: + template + bool exists(const Id& object){ + unsigned int id = AttachmentsId::getId(object); + + return __exists(id); } - - template - typename std::enable_if::value, void*>::type - __wrap(const Typ& value){ - Typ* holder = new Typ(value); - return holder; + + template + Data& get(const Id& object){ + unsigned int id = AttachmentsId::getId(object); + + return __get(id); } - - template - typename std::enable_if::value, Typ&>::type - __unwrap(void* value){ - return *reinterpret_cast(value); + + template + Data get(const Id& object, const Data& dataDefault){ + unsigned int id = AttachmentsId::getId(object); + + if (! __exists(id)){ + return dataDefault; + } + + return __get(id); } - template - typename std::enable_if::value, void>::type - __delete(void* value){ - delete reinterpret_cast(value); + template + void put(const Id& object, Data data){ + unsigned int id = AttachmentsId::getId(object); + + __put(id, data); } - template - typename std::enable_if::value, void>::type - __delete(void* value){ - delete reinterpret_cast(value); - } + virtual ~IAttachmentsContainer(){}; +}; + +template +class AttachmentsContainerDefault: public IAttachmentsContainer{ +private: + std::unordered_map __data; + + virtual bool __exists(const unsigned int id){ + return __data.count(id); + } + + virtual Data& __get(const unsigned int id){ + return __data.at(id); + } + + virtual void __put(const unsigned int id, Data data){ + auto result = __data.emplace(id, data); + assert(result.second); } - //TODO copy whole data from symbol to symbol: copy(sTo, sFrom); - class Attachments - { - public: - //TODO add specialization for pointers - template - using Data = typename AttachmentsDict::Data; - - template - static void put(const Holder& holder, const Data& data) - { - const unsigned int key = AttachmentsDict::key; - Attachments* self = AttachmentsStorage::get(holder); - - void* dataWaste = self->put(key, detail::__wrap(data)); - detail::__delete>(dataWaste); - } +public: + std::unordered_map& getRawStorage() { + return __data; + } +}; - template - static Data& get(const Holder& holder) - { - const unsigned int key = AttachmentsDict::key; - Attachments* self = AttachmentsStorage::get(holder); - return detail::__unwrap>(self->get(key)); - } - - template - static Data get(const Holder& holder, Data&& dataDefault) - { - if (! exists(holder)){ - return dataDefault; - } - - const unsigned int key = AttachmentsDict::key; - Attachments* self = AttachmentsStorage::get(holder); +class Attachments{ +private: + static std::vector __storage; + + template + using Data = typename AttachmentsDict::Data; + +public: + template + static bool exists(const Id& object) { + assert(AttachmentsDict::key < __storage.size()); + assert(__storage.at(AttachmentsDict::key)); + + IAttachmentsContainer>* self = reinterpret_cast>*>(__storage.at(AttachmentsDict::key)); + return self->exists(object); + } + + template + static Data& get(const Id& object){ + assert(AttachmentsDict::key < __storage.size()); + assert(__storage.at(AttachmentsDict::key)); + + IAttachmentsContainer>* self = reinterpret_cast>*>(__storage.at(AttachmentsDict::key)); + return self->get(object); + } + + template + static Data get(const Id& object, const Data& dataDefault){ + assert(AttachmentsDict::key < __storage.size()); + assert(__storage.at(AttachmentsDict::key)); + + IAttachmentsContainer>* self = reinterpret_cast>*>(__storage.at(AttachmentsDict::key)); + return self->get(object, dataDefault); + } - return detail::__unwrap>(self->get(key)); + template + static void put(const Id& object, Data data){ + assert(AttachmentsDict::key < __storage.size()); + assert(__storage.at(AttachmentsDict::key)); + + IAttachmentsContainer>* self = reinterpret_cast>*>(__storage.at(AttachmentsDict::key)); + self->put(object, data); + } + + template + static void init(){ + unsigned int keyStorage = AttachmentsDict::key; + if (keyStorage+1 > __storage.size()){ + __storage.resize(keyStorage + 1, nullptr); } - template - static bool exists(const Holder& holder) - { - const unsigned int key = AttachmentsDict::key; - Attachments* self = AttachmentsStorage::get(holder); - return self->exists(key); + __storage[keyStorage] = new AttachmentsContainerDefault>(); + } + + template + static void init(IAttachmentsContainer>* container){ + unsigned int keyStorage = AttachmentsDict::key; + if (keyStorage+1 > __storage.size()){ + __storage.resize(keyStorage + 1, nullptr); } - private: - std::map __data; + __storage[keyStorage] = container; + } +}; - void* put(unsigned int key, void *data); - void* get(unsigned int key); - bool exists(unsigned int key); - }; } #endif //_XREATE_ATTACHMENTS_H_ diff --git a/cpp/src/aux/latereasoning.cpp b/cpp/src/aux/latereasoning.cpp new file mode 100644 index 0000000..c70ef88 --- /dev/null +++ b/cpp/src/aux/latereasoning.cpp @@ -0,0 +1,57 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * Author: pgess + * Created on June 7, 2018, 6:01 PM + * + * \file latereasoning.cpp + * \brief Late reasoninf support + */ + +#include "aux/latereasoning.h" +#include "analysis/interpretation.h" +#include "ast.h" + +using namespace std; + +namespace xreate{ +namespace latereasoning{ + +LateAnnotation::LateAnnotation(const Gringo::Symbol& symbolStatic) { + guardedContent.push_back(pair, Gringo::Symbol>({}, symbolStatic)); +} + +boost::optional +LateAnnotation::select(const std::list& keys, AST* root, TranscendLayer* transcend) const { + for(const auto& entry : guardedContent) { + const std::list& guardsExpected = entry.first; + auto keyPSIt = guardKeys.begin(); + auto keyActualIt = keys.begin(); + bool result = true; + for(const Gringo::Symbol& guardExpectedGS : guardsExpected) { + auto keyS = transcend->unpack(*keyPSIt); + const ExpandedType& keyT = root->getType(CodeScope::getDefinition(keyS)); + const ExpandedType& keyTPlain = keyT->__operator == TypeOperator::SLAVE ? + interpretation::dereferenceSlaveType(keyT, transcend) + : keyT; + Expression guardExpectedE = interpretation::representTransExpression( + guardExpectedGS, keyTPlain, transcend); + if(!(guardExpectedE == *keyActualIt)) { + result = false; + break; + } + ++keyActualIt; + ++keyPSIt; + } + if(!result) continue; + return entry.second; + } + + return boost::none; +} + +} +} + diff --git a/cpp/src/aux/latereasoning.h b/cpp/src/aux/latereasoning.h new file mode 100644 index 0000000..a20dbe1 --- /dev/null +++ b/cpp/src/aux/latereasoning.h @@ -0,0 +1,84 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * \file latereasoning.h + * \brief Late reasoning support + * + * Author: pgess + * + * Created on June 2, 2018, 1:08 PM + */ + +#ifndef LATEREASONING_H +#define LATEREASONING_H + +#include "transcendlayer.h" + +namespace xreate{ namespace latereasoning{ + +struct LateAnnotation{ + LateAnnotation(){} + LateAnnotation(const Gringo::Symbol& symbolStatic); + std::list, Gringo::Symbol>> guardedContent; + std::list guardKeys; + boost::optional select(const std::list& keys, AST* root, TranscendLayer* transcend) const; +}; + +struct LateAnnotationsGroup{ + std::unordered_map annotations; +}; + +typedef std::map LateModel; + +template +class LateReasoningTranscendDecorator: public Parent{ +public: + const LateAnnotationsGroup& queryLate(const std::string& alias) const{ + static LateAnnotationsGroup groupInvalid; + if(!__modelLate.count(alias)) return groupInvalid; + + return __modelLate.at(alias); + } + +protected: + virtual bool processSolution(Gringo::Model const &model) override{ + const std::string& atomLateStatement = "late"; + + for(const Gringo::Symbol& atom: model.atoms(clingo_show_type_atoms)){ + std::string atomName(atom.name().c_str()); + + if(atomName == atomLateStatement){ + //late atom's format: (Target, (tuple of keys), (tuple of values), late-annotation) + auto atomLate = TranscendLayer::parse, std::list, Gringo::Symbol>(atom); + const std::string& atomAlias = std::get<3>(atomLate).name().c_str(); + addLateAtom(atomAlias, std::get<0>(atomLate), + std::get<3>(atomLate), std::get<1>(atomLate), + std::get<2>(atomLate)); + } + } + + return Parent::processSolution(model); + } + +private: + std::map __modelLate; + + void addLateAtom(const std::string& alias, const Gringo::Symbol& annId, + const Gringo::Symbol& content, const std::list& guardKeys, + const std::list& guardValues){ + LateAnnotationsGroup& group = __modelLate[alias]; + + LateAnnotation& annotation = group.annotations[annId]; + if (annotation.guardedContent.empty()){ + annotation.guardKeys = guardKeys; + } + annotation.guardedContent.push_back(std::make_pair(guardValues, content)); + } +}; + +}} // end of xreate::latereasoning + +#endif /* LATEREASONING_H */ + diff --git a/cpp/src/serialization/expressionserializer.cpp b/cpp/src/aux/serialization/expressionserializer.cpp similarity index 95% rename from cpp/src/serialization/expressionserializer.cpp rename to cpp/src/aux/serialization/expressionserializer.cpp index 53d6ee5..e450529 100644 --- a/cpp/src/serialization/expressionserializer.cpp +++ b/cpp/src/aux/serialization/expressionserializer.cpp @@ -1,316 +1,321 @@ -/* +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * * expressionserializer.cpp * * Created on: Jan 4, 2016 - * Author: pgess + * Author: pgess */ -#include "serialization/expressionserializer.h" +#include "aux/serialization/expressionserializer.h" #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; 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: { + case Operator::INVALID: { switch (e.__state) { case Expression::NUMBER: case Expression::STRING: case Expression::IDENT : { Index index; if ((e.__state == Expression::NUMBER)) index = {std::to_string(e.getValueDouble()), 0, level}; else 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)){ 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: { + case Operator::INVALID: { Index index; switch (e.__state) { case Expression::STRING: case Expression::IDENT: { index = {e.getValueString(), 0, level}; if (__registry.left.insert(make_pair(index, __range[level])).second){ __range[level]++; } return; } case Expression::NUMBER: { index = {std::to_string(e.getValueDouble()), 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::getId(const Expression& e){ OptionalPackedExpression result(boost::in_place()); //move(PackedExpression()) strategy->pack(e, 0, result); assert(result); return move(*result); } OptionalPackedExpression ExpressionSerializer::getIdOptional(const Expression& e) const{ OptionalPackedExpression result(boost::in_place()); //move(PackedExpression()) strategy->pack(e, 0, result); return result; } ExpressionSerializerIntegral::ExpressionSerializerIntegral():serializer(*this){} 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 OptionalPackedExpression exprPacked = serializer.getIdOptional(e); assert(exprPacked); return __registry.at(*exprPacked); } boost::optional ExpressionSerializerIntegral::getIdOptional(const Expression& e) const{ const OptionalPackedExpression 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"); } #if BOOST_VERSION <= 105500 PackedExpression::PackedExpression(const PackedExpression& other){ __storage = other.__storage; size = other.size; countRemainedBits = other.countRemainedBits; } #endif 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 */ \ No newline at end of file +} /* namespace xreate */ diff --git a/cpp/src/serialization/expressionserializer.h b/cpp/src/aux/serialization/expressionserializer.h similarity index 91% rename from cpp/src/serialization/expressionserializer.h rename to cpp/src/aux/serialization/expressionserializer.h index 52daba8..11b07f5 100644 --- a/cpp/src/serialization/expressionserializer.h +++ b/cpp/src/aux/serialization/expressionserializer.h @@ -1,111 +1,114 @@ -/* +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * * expressionserializer.h * * Created on: Jan 4, 2016 - * Author: pgess + * Author: pgess */ #ifndef SRC_EXPRESSIONSERIALIZER_H_ #define SRC_EXPRESSIONSERIALIZER_H_ #include "ast.h" #include #include #include namespace xreate { struct PackedExpression{ PackedExpression(){}; PackedExpression(PackedExpression&& other); #if BOOST_VERSION <= 105500 PackedExpression (const PackedExpression&); #else PackedExpression (const PackedExpression&)=delete; #endif ~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& 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(); 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_ */ \ No newline at end of file +#endif /* SRC_EXPRESSIONSERIALIZER_H_ */ diff --git a/cpp/src/aux/transcend-decorators.h b/cpp/src/aux/transcend-decorators.h new file mode 100644 index 0000000..321b66c --- /dev/null +++ b/cpp/src/aux/transcend-decorators.h @@ -0,0 +1,34 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +/* + * Author: pgess + * Created on June 7, 2018, 6:47 PM + * + * \file transcend-decorators.h + * \brief TranscendLevel decorators management + */ + +#include "transcendlayer.h" +#include "aux/latereasoning.h" + +#ifndef TRANSCEND_DECORATORS_H +#define TRANSCEND_DECORATORS_H + +namespace xreate { + typedef latereasoning::LateReasoningTranscendDecorator + DefaultTranscendLayerImpl; + + struct LateReasoningTranscendDecoratorTag; + + template<> + struct DecoratorsDict{ + typedef latereasoning::LateReasoningTranscendDecorator result; +}; +} + +#endif /* TRANSCEND_DECORATORS_H */ + diff --git a/cpp/src/aux/xreatemanager-decorators.cpp b/cpp/src/aux/xreatemanager-decorators.cpp new file mode 100644 index 0000000..40bf519 --- /dev/null +++ b/cpp/src/aux/xreatemanager-decorators.cpp @@ -0,0 +1,74 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * xreatemanager-decorators.cpp + * + * Author: pgess + * Created on July 16, 2017, 4:40 PM + */ + +/** + * \file xreatemanager-decorators.h + * \brief \ref xreate::XreateManager decorators to provide various functionality + */ + +#include "aux/xreatemanager-decorators.h" +#include "main/Parser.h" +#include "pass/compilepass.h" +#include "pass/cfapass.h" +#include "pass/dfapass.h" +#include "pass/interpretationpass.h" +#include "pass/versionspass.h" +namespace xreate{ + +void +XreateManagerDecoratorBase::initPasses() { } + +void +XreateManagerDecoratorBase::prepareCode(std::string&& code) { + grammar::main::Scanner scanner(reinterpret_cast (code.c_str()), code.size()); + grammar::main::Parser parser(&scanner); + parser.Parse(); + assert(!parser.errors->count && "Parser errors"); + + PassManager::prepare(parser.root->finalize()); +} + +void +XreateManagerDecoratorBase::prepareCode(FILE* code) { + grammar::main::Scanner scanner(code); + grammar::main::Parser parser(&scanner); + parser.Parse(); + assert(!parser.errors->count && "Parser errors"); + + PassManager::prepare(parser.root->finalize()); +} + +void +XreateManagerDecoratorBase::analyse() { + CompilePass::prepareQueries(transcend); + transcend->run(); +} + +void +XreateManagerDecoratorFull::initPasses() { + cfa::CFAPass* passCFG = new cfa::CFAPass(this); + + registerPass(new dfa::DFAPass(this), PassId::DFAPass); + registerPass(passCFG, PassId::CFAPass); + registerPass(new interpretation::InterpretationPass(this), PassId::InterpretationPass); + registerPass(new versions::VersionsPass(this), PassId::VersionsPass); +} + +void* +XreateManagerDecoratorFull::run() { + std::unique_ptr compiler(new compilation::CompilePassCustomDecorators<>(this)); + compiler->run(); + + llvm->print(); + llvm->initJit(); + return llvm->getFunctionPointer(compiler->getEntryFunction()); +} + +} //namespace xreate diff --git a/cpp/src/aux/xreatemanager-decorators.h b/cpp/src/aux/xreatemanager-decorators.h new file mode 100644 index 0000000..d1cfe71 --- /dev/null +++ b/cpp/src/aux/xreatemanager-decorators.h @@ -0,0 +1,38 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * File: xreatemanager-decorators.h + * Author: pgess + * + * Created on July 16, 2017, 4:37 PM + */ + +#ifndef XREATEMANAGER_DECORATORS_H +#define XREATEMANAGER_DECORATORS_H + +#include "xreatemanager.h" + +namespace xreate{ + +class XreateManagerDecoratorBase: public details::tier2::XreateManager{ +public: + virtual void initPasses() override; + virtual void analyse(); + virtual void* run(){}; + +public: + virtual void prepareCode(std::string&& code); + virtual void prepareCode(FILE* code); +}; + +class XreateManagerDecoratorFull: public XreateManagerDecoratorBase{ +public: + virtual void initPasses() override; + void* run(); +}; + +} + +#endif /* XREATEMANAGER_DECORATORS_H */ + diff --git a/cpp/src/aux/xreatemanager-modules.h b/cpp/src/aux/xreatemanager-modules.h new file mode 100644 index 0000000..5629527 --- /dev/null +++ b/cpp/src/aux/xreatemanager-modules.h @@ -0,0 +1,126 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * File: PassManagerModular.h + * Author: pgess + * + * Created on June 22, 2017, 5:32 PM + */ + +/** + * \file xreatemanager-modules.h + * \brief XreateManager's decorator to support [Modules](/w/concepts/modules/). + */ + +#ifndef PASSMANAGERMODULAR_H +#define PASSMANAGERMODULAR_H + +#include "ast.h" +#include "modules.h" +#include "modules/Parser.h" +#include "main/Parser.h" + +namespace xreate{namespace modules { + +template +/** \brief PassManager decorator to add [Modules Concept](/w/concepts/modules/) support + * + * Scanning of source file looking for other modules requirements. + * Finds and connects other modules to satisfy module's requirements + * + * \sa ModulesSolver, ModulesRegistry, ModuleRecord + */ + +class XreateManagerDecoratorModules: public Parent{ +public: + XreateManagerDecoratorModules(): __registry(new ModulesRegistry()){} + + void prepareCode(std::string&& code) override { + Scanner scannerModules(reinterpret_cast(code.c_str()), code.size()); + std::list listIncludedFiles; + parseModulesGrammar(scannerModules, listIncludedFiles); + + grammar::main::Scanner scannerMain(reinterpret_cast(code.c_str()), code.size()); + parseMainGrammar(scannerMain, listIncludedFiles); + } + + void prepareCode(FILE* code) override { + Scanner scannerModules(code); + std::list listIncludedFiles; + parseModulesGrammar(scannerModules, listIncludedFiles); + + grammar::main::Scanner scannerMain(code); + parseMainGrammar(scannerMain, listIncludedFiles); + } + +private: + ModulesRegistry* __registry; + + void parseModulesGrammar(Scanner& scanner, std::list& listIncludedFiles){ + ModulesSolver solver(__registry); + + Parser parser(&scanner); + parser.Parse(); + parser.module.__path = ""; + + solver.init("", parser.module); + + std::list modulesExternal = solver.run(parser.module); + std::string programBase = solver.__program.str(); + + for (const std::string module: modulesExternal){ + parseModulesGrammar(module, programBase, listIncludedFiles); + } + } + + void parseModulesGrammar(const std::string& path, std::string base, std::list& listIncludedFiles){ + FILE* input = fopen(path.c_str(), "r"); + assert(input != nullptr); + Scanner scanner(input); + Parser parser(&scanner); + parser.Parse(); + parser.module.__path = path; + fclose(input); + + ModulesSolver solver(__registry); + solver.init(base, parser.module); + + std::list&& modulesExternal = solver.run(parser.module); + std::string programBase = solver.__program.str(); + + for (const std::string module: modulesExternal){ + parseModulesGrammar(module, programBase, listIncludedFiles); + } + + listIncludedFiles.push_back(path); + } + + void parseMainGrammar(grammar::main::Scanner& scanner, std::list& listIncludedFiles){ + details::inconsistent::AST* ast = new AST; + + grammar::main::Parser parser(&scanner); + parser.root = ast; + parser.Parse(); + assert(!parser.errors->count && "Parser errors"); + + for (auto file: listIncludedFiles){ + FILE* fileContent = fopen(file.c_str(), "r"); + grammar::main::Scanner scanner(fileContent); + grammar::main::Parser parser(&scanner); + parser.root = ast; + parser.Parse(); + fclose(fileContent); + + assert(!parser.errors->count && "Parser errors"); + } + + PassManager::prepare(ast->finalize()); + } +}; + +}} //end namespace xreate::modules + + +#endif /* PASSMANAGERMODULAR_H */ + diff --git a/cpp/src/clasplayer.cpp b/cpp/src/clasplayer.cpp deleted file mode 100644 index 6434235..0000000 --- a/cpp/src/clasplayer.cpp +++ /dev/null @@ -1,275 +0,0 @@ -#include "clasplayer.h" - -#include -#include "utils.h" -#include -#include -#include - -#include "analysis/aux.h" -#include "analysis/DominatorsTreeAnalysisProvider.h" -#include "analysis/cfagraph.h" -#include "analysis/dfagraph.h" - -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::Symbol 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::Symbol atom : model.atoms(clingo_show_type_atoms)) { - atom.print(cout); - cout <<" | "<< endl; - - string atomName(atom.name().c_str()); - if (atomName == atomBindVar || atomName == atomBindFunc || atomName == atomBindScope){ - string name = std::get<1>(parse(atom)).name().c_str(); - __model.emplace(move(name), move(atom)); - } - - __model.emplace(atomName, move(atom)); - } - - return true; - } - - void - ClaspLayer::setCFAData(xreate::analysis::CFAGraph* graph) { - dataCFA.reset(graph); - } - - void - ClaspLayer::setDFAData(xreate::analysis::DFAGraph* graph){ - dataDFA.reset(graph); - } - - 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 xreate::analysis::compile(guard); - }); - - const list& guards = xreate::analysis::multiplyLists(std::move(guardsRaw)); - list &&branches = xreate::analysis::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, ", ")) - <__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(); - - if (this->dataDFA){ - this->dataDFA->print(__partGeneral); - } - - if (this->dataCFA){ - this->dataCFA->print(__partGeneral); - } - - DominatorsTreeAnalysisProvider providerDominators; - providerDominators.run(this); - providerDominators.print(__partGeneral); - - 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(), {}, 0); - - ctl.add("base", {}, program.str()); - ctl.ground({{"base", {}}}, nullptr); - -// solve - Gringo::SolveResult result = ctl.solve([this](Gringo::Model const &model) { - this->handleSolution(model); - return true; - }, {}); - - if (result.satisfiable() == Gringo::SolveResult::Satisfiable) { - 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* const scope) { - auto pos = __indexScopes.emplace(scope, __indexScopes.size()); - if (pos.second) - __registryScopes.push_back(scope); - - return pos.first->second; - } - - size_t - ClaspLayer::getScopesCount() const{ - return __registryScopes.size(); - } - - SymbolPacked - ClaspLayer::pack(const Symbol& symbol, std::string hintSymbolName) - { - SymbolPacked result(symbol.identifier, pack(symbol.scope)); - __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){ - if (!symbol.categoryTransient) { - auto result = __indexSymbolNameHints.find(symbol); - return (result == __indexSymbolNameHints.end())? "" : result->second; - - } else { - return "anonym(" + to_string(symbol.identifier) + ")"; - } - } - - 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); - } -} \ No newline at end of file diff --git a/cpp/src/clasplayer.h b/cpp/src/clasplayer.h deleted file mode 100644 index 6961026..0000000 --- a/cpp/src/clasplayer.h +++ /dev/null @@ -1,230 +0,0 @@ -#ifndef CLASPLAYER_H -#define CLASPLAYER_H - -#include "ast.h" -#include "contextrule.h" - -#include -#include -#include -#include -#include -#include -#include -#include - -namespace xreate { - - typedef unsigned int ScopePacked; - - struct SymbolPacked { - VID identifier; - ScopePacked scope; - bool categoryTransient; - - SymbolPacked(): categoryTransient(false){} - SymbolPacked(VID i, ScopePacked s, bool isTransient = false): identifier(i), scope(s), categoryTransient(isTransient){} - }; - - bool operator==(const SymbolPacked& s1, const SymbolPacked& s2); - bool operator<(const SymbolPacked& s1, const SymbolPacked& s2); - - enum class DFGConnection { - STRONG, WEAK, PROTOTYPE - }; - - class IAnalysisData { - public: - void print(std::ostringstream& output) const; - virtual ~IAnalysisData(){}; - }; - - class IQuery { - public: - virtual void init(ClaspLayer* clasp) = 0; - virtual ~IQuery() {} - }; - - enum class QueryId { - ContainersQuery, - ContextQuery, - PtrvalidQuery - }; - - namespace analysis{ - class DFAGraph; - class CFAGraph; - } - - class ClaspLayer { - friend class ContextRule; - - //PROVIDERS: - public: - boost::scoped_ptr dataDFA; - void setDFAData(xreate::analysis::DFAGraph* graph); - - boost::scoped_ptr dataCFA; - void setCFAData(xreate::analysis::CFAGraph* graph); - - void addRawScript(std::string&& script); - - private: - void involveImports(); - - //QUERIES - public: - IQuery* registerQuery(IQuery* query, const QueryId& id); - IQuery* getQuery(const QueryId& id); - - template - static std::tuple parse(const Gringo::Symbol& atom); - - typedef std::multimap::const_iterator ModelIterator; - typedef boost::optional> ModelFragment; - ModelFragment query(const std::string& atom); - - size_t getScopesCount() const; - SymbolPacked pack(const Symbol& symbol, std::string hintSymbolName = ""); - ScopePacked pack(CodeScope * const scope); - Symbol unpack(const SymbolPacked& symbol); - std::string getHintForPackedSymbol(const SymbolPacked& symbol); - - private: - std::map __queries; - std::multimap __model; - std::map __indexSymbolNameHints; - std::unordered_map __indexScopes; - std::vector __registryScopes; - - //WARNINGS - //TODO move to separate provider/query - public: - void addRuleWarning(const RuleWarning &rule); - unsigned int registerWarning(std::string &&message); - - private: - std::map __warnings; - void printWarnings(std::ostream& out); - - //DEFAULT - public: - AST *ast; - - ClaspLayer(); - void run(); - - private: - std::ostringstream __partTags; - std::ostringstream __partGeneral; - - bool handleSolution(Gringo::Model const &model); - }; - - template - struct ParseImplAtom { - - static typ get(const Gringo::Symbol& atom) { - return atom.num(); - } - }; - - template<> - struct ParseImplAtom { - static std::string get(const Gringo::Symbol& atom) { - switch (atom.type()) { - case Gringo::SymbolType::Str: return atom.string().c_str(); - case Gringo::SymbolType::Fun: return atom.name().c_str(); - - default: break; - } - - assert(false && "Inappropriate symbol type"); - } - }; - - template<> - struct ParseImplAtom { - - static SymbolPacked get(const Gringo::Symbol& atom) { - auto result = ClaspLayer::parse(atom); - return SymbolPacked(std::get<0>(result), std::get<1>(result)); - } - }; - - template<> - struct ParseImplAtom { - - static Gringo::Symbol get(const Gringo::Symbol& atom) { - return atom; - } - }; - - template<> - struct ParseImplAtom { - - static Expression get(const Gringo::Symbol& atom) { - switch (atom.type()) { - case Gringo::SymbolType::Num: return Expression(atom.num()); - case Gringo::SymbolType::Str: return Expression(std::string(atom.string().c_str())); - - case Gringo::SymbolType::Fun: - { - //ID - if (!atom.args().size){ - return Expression(std::string(atom.name().c_str())); - } - - //FUNC - Expression result(Operator::CALL,{Expression(std::string(atom.name().c_str()))}); - for (const Gringo::Symbol& arg : atom.args()) { - result.addArg(ParseImplAtom::get(arg)); - } - - return result; - } - - default: - { - assert(false); - } - } - } - }; - - template - struct Parse_Impl { - - static void parse(Tuple& tup, Gringo::SymSpan::iterator arg) { - const size_t tupleSize = std::tuple_size::value; - typedef typename std::tuple_element < tupleSize - index, Tuple>::type ElType; - - ElType& el = std::get < tupleSize - index > (tup); - - Gringo::Symbol atom = *arg; - el = ParseImplAtom::get(atom); - - Parse_Impl ::parse(tup, ++arg); - } - }; - - template - struct Parse_Impl { - - static void parse(Tuple& tup, Gringo::SymSpan::iterator arg) { - } - }; - - template - std::tuple - ClaspLayer::parse(const Gringo::Symbol& atom) { - typedef std::tuple < Types...> Tuple; - Tuple tup; - Parse_Impl::value>::parse(tup, atom.args().first); - - return tup; - } - - -} -#endif \ No newline at end of file diff --git a/cpp/src/compilation/advanced.cpp b/cpp/src/compilation/advanced.cpp deleted file mode 100644 index d49ede8..0000000 --- a/cpp/src/compilation/advanced.cpp +++ /dev/null @@ -1,432 +0,0 @@ -/* - * File: InstructionsAdvanced.cpp - * Author: pgess - * - * Created on June 26, 2016, 6:00 PM - */ - -#include -#include "compilation/advanced.h" -#include "compilation/containers.h" - -#include "query/context.h" -#include "query/containers.h" -#include "llvmlayer.h" -#include "ast.h" - -using namespace std; -using namespace llvm; -using namespace xreate; -using namespace xreate::containers; -using namespace xreate::compilation; - -#define NAME(x) (hintRetVar.empty()? x : hintRetVar) -#define UNUSED(x) (void)(x) -#define EXPAND_CONTEXT \ - LLVMLayer* llvm = context.pass->man->llvm; \ - compilation::CodeScopeUnit* scope = context.scope; \ - compilation::FunctionUnit* function = context.function; - -Advanced::Advanced(compilation::Context ctx) -: context(ctx), tyNum(static_cast (ctx.pass->man->llvm->toLLVMType(ExpandedType(TypeAnnotation(TypePrimitive::Num))))) { -} - -llvm::Value* -Advanced::compileMapSolidOutput(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->__bindings[0]; - - Iterator* it = Iterator::create(context, symbolIn); - llvm::Value *rangeFrom = it->begin(); - llvm::Value *rangeTo = it->end(); - - //definitions - ArrayType* tyNumArray = (ArrayType*) (llvm->toLLVMType(ExpandedType(TypeAnnotation(tag_array, TypePrimitive::Num, size)))); - llvm::IRBuilder<> &builder = llvm->builder; - - llvm::BasicBlock *blockLoop = llvm::BasicBlock::Create(llvm::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); - 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* -Advanced::compileArrayIndex(llvm::Value* aggregate, std::vector indexes, std::string hintRetVar) { - EXPAND_CONTEXT - UNUSED(function); - - indexes.insert(indexes.begin(), llvm::ConstantInt::get(tyNum, 0)); - llvm::Value *pEl = llvm->builder.CreateGEP(aggregate, llvm::ArrayRef(indexes)); - return llvm->builder.CreateLoad(pEl, NAME("el")); -} - -Value* -Advanced::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 < size; ++i) { - if (fields.at(i) == idx) { - - std::vector 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); - - - // TODO review safety check: validPtr for `aggregate` - // SECTIONTAG validptr exception - 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"); - return nullptr; -} - -llvm::Value* -Advanced::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* rangeBegin = it->begin(); - llvm::Value* rangeEnd = it->end(); - llvm::Value* accumInit = scope->process(fold.getOperands()[1]); - std::string varIn = fold.getOperands()[0].getValueString(); - std::string varAccum = fold.bindings[1]; - std::string varEl = fold.bindings[0]; - TransformerSaturation* transformerSaturation = context.pass->transformations->get(); - - llvm::BasicBlock *blockBeforeLoop = llvm->builder.GetInsertBlock(); - llvm::BasicBlock *blockLoop = llvm::BasicBlock::Create(llvm::getGlobalContext(), "fold", function->raw); - llvm::BasicBlock *blockBody = llvm::BasicBlock::Create(llvm::getGlobalContext(), "body", function->raw); - llvm::BasicBlock *blockAfterLoop = llvm::BasicBlock::Create(llvm::getGlobalContext(), "postfold", function->raw); - - llvm->builder.CreateBr(blockLoop); - - // * create phi - llvm->builder.SetInsertPoint(blockLoop); - llvm::PHINode *accum = llvm->builder.CreatePHI(accumInit->getType(), 2, NAME("accum")); - accum->addIncoming(accumInit, blockBeforeLoop); - llvm::PHINode *itLoop = llvm->builder.CreatePHI(rangeBegin->getType(), 2, "foldIt"); - itLoop->addIncoming(rangeBegin, blockBeforeLoop); - - // * loop body - llvm->builder.SetInsertPoint(blockBody); - CodeScope* scopeLoop = fold.blocks.front(); - compilation::CodeScopeUnit* loopUnit = function->getScopeUnit(scopeLoop); - Value* elIn = it->get(itLoop); - loopUnit->bindArg(accum, move(varAccum)); - loopUnit->bindArg(elIn, move(varEl)); - Value* accumNext = loopUnit->compile(); - - // * computing next iteration state - Value *itLoopNext = it->advance(itLoop); - accum->addIncoming(accumNext, llvm->builder.GetInsertBlock()); - itLoop->addIncoming(itLoopNext, llvm->builder.GetInsertBlock()); - llvm->builder.CreateBr(blockLoop); - - // * break checks, continue checks - //!! only after compiled Loop Body in order to fetch saturation expression - llvm->builder.SetInsertPoint(blockLoop); - if (transformerSaturation->exists()) { - transformerSaturation->inject(blockBeforeLoop, blockAfterLoop, context); - } - - // * next iteration checks - Value* condRange = llvm->builder.CreateICmpNE(itLoop, rangeEnd); - llvm->builder.CreateCondBr(condRange, blockBody, blockAfterLoop); - - // finalization: - llvm->builder.SetInsertPoint(blockAfterLoop); - - return accum; -} - -llvm::Value* -Advanced::compileFoldInf(const Expression& fold, const std::string& hintRetVar) { - EXPAND_CONTEXT - assert(fold.op == Operator::FOLD_INF); - - std::string accumName = fold.bindings[0]; - llvm::Value* accumInit = scope->process(fold.getOperands()[0]); - - llvm::BasicBlock *blockBeforeLoop = llvm->builder.GetInsertBlock(); - llvm::BasicBlock *blockLoop = llvm::BasicBlock::Create(llvm::getGlobalContext(), "fold", function->raw); - llvm::BasicBlock *blockBody = llvm::BasicBlock::Create(llvm::getGlobalContext(), "body", function->raw); - llvm::BasicBlock *blockAfterLoop = llvm::BasicBlock::Create(llvm::getGlobalContext(), "postfold", function->raw); - TransformerSaturation* transformerSaturation = context.pass->transformations->get(); - - llvm->builder.CreateBr(blockLoop); - - // * create phi - llvm->builder.SetInsertPoint(blockLoop); - llvm::PHINode *accum = llvm->builder.CreatePHI(accumInit->getType(), 2, NAME("accum")); - accum->addIncoming(accumInit, blockBeforeLoop); - - // * loop body - llvm->builder.SetInsertPoint(blockBody); - CodeScope* scopeLoop = fold.blocks.front(); - compilation::CodeScopeUnit* unitLoop = function->getScopeUnit(scopeLoop); - unitLoop->bindArg(accum, move(accumName)); - Value* accumNext = unitLoop->compile(); - - // * computing next iteration state - accum->addIncoming(accumNext, llvm->builder.GetInsertBlock()); - llvm->builder.CreateBr(blockLoop); - - // * break checks, continue checks - assert(transformerSaturation->exists()); - llvm->builder.SetInsertPoint(blockLoop); - transformerSaturation->inject(blockBeforeLoop, blockAfterLoop, context); - llvm->builder.CreateBr(blockBody); - - // finalization: - llvm->builder.SetInsertPoint(blockAfterLoop); - return accum; -} - -llvm::Value* -Advanced::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); - const Domain& 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(); - 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* -Advanced::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(tyResultType, 2, NAME("if")); - ret->addIncoming(resultTrue, blockTrue); - ret->addIncoming(resultFalse, blockFalse); - - return ret; -} - -//TODO Switch: default variant no needed when all possible conditions are considered - -llvm::Value* -Advanced::compileSwitch(const Expression& exprSwitch, const std::string& hintRetVar) { - EXPAND_CONTEXT - UNUSED(function); - - assert(exprSwitch.operands.size() >= 2); - assert(exprSwitch.operands[1].op == Operator::CASE_DEFAULT && "No default case in Switch Statement"); - int countCases = exprSwitch.operands.size() - 1; - llvm::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; i < size; ++i) { - llvm::BasicBlock *blockCase = llvm::BasicBlock::Create(llvm::getGlobalContext(), "case" + std::to_string(i), function->raw); - - llvm::Value* condCase = function->getScopeUnit(exprSwitch.operands[i].blocks.front())->compile(); - builder.SetInsertPoint(blockCase); - llvm::Value* resultCase = function->getScopeUnit(exprSwitch.operands[i].blocks.back())->compile(); - builder.CreateBr(blockEpilog); - - ret->addIncoming(resultCase, builder.GetInsertBlock()); - builder.SetInsertPoint(blockProlog); - instructionSwitch->addCase(dyn_cast(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; -} - -//TODO recognize cases to make const arrays/stored in global mem/stack alloced. -llvm::Value* -Advanced::compileListAsSolidArray(const Expression &expr, const std::string& hintRetVar) { - EXPAND_CONTEXT - UNUSED(scope); - UNUSED(function); - - AST* root = context.pass->man->root; - const size_t& length = expr.getOperands().size(); - const Expression& expression = expr; - llvm::Value* zero = ConstantInt::get(tyNum, 0); - llvm::Value* one = ConstantInt::get(tyNum, 1); - - ExpandedType typAggrExpanded = root->expandType(expression.type); - assert(typAggrExpanded->__operator == TypeOperator::ARRAY); - llvm::Type* typEl = llvm->toLLVMType(ExpandedType(typAggrExpanded->__operands[0])); - ArrayType* typAggr = (ArrayType*) llvm::ArrayType::get(typEl, length); - llvm::Value* list = llvm->builder.CreateAlloca(typAggr, ConstantInt::get(Type::getInt32Ty(llvm::getGlobalContext()), length, false), hintRetVar); - - const std::vector& operands = expression.getOperands(); - llvm::Value* addrOperand = llvm->builder.CreateGEP(typAggr, list, ArrayRef(std::vector{zero, zero})); - llvm->builder.CreateStore(scope->process(operands.front()), addrOperand) ; - for (auto i=++operands.begin(); i!=operands.end(); ++i){ - addrOperand = llvm->builder.CreateGEP(typEl, addrOperand, ArrayRef(std::vector{one})); - llvm->builder.CreateStore(scope->process(*i), addrOperand) ; - } - - return list; -// Value* listDest = l.builder.CreateAlloca(typList, ConstantInt::get(typI32, __size), *hintRetVar); -// l.buil1der.CreateMemCpy(listDest, listSource, __size, 16); -} - -llvm::Value* - Advanced::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); -} diff --git a/cpp/src/compilation/advancedinstructions.cpp b/cpp/src/compilation/advancedinstructions.cpp new file mode 100644 index 0000000..1409e5e --- /dev/null +++ b/cpp/src/compilation/advancedinstructions.cpp @@ -0,0 +1,470 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * File: InstructionsAdvanced.cpp + * Author: pgess + * + * Created on June 26, 2016, 6:00 PM + */ + +/** + * \file advanced.h + * \brief Compilation of statements that require more than one LLVM instruction + */ + +#include "analysis/typeinference.h" +#include "compilation/advancedinstructions.h" +#include "compilation/containers.h" +#include "compilation/transformersaturation.h" + +#include "query/containers.h" +#include "llvmlayer.h" +#include "ast.h" + +using namespace std; +using namespace llvm; +using namespace xreate; +using namespace xreate::containers; +using namespace xreate::compilation; + +#define NAME(x) (hintRetVar.empty()? x : hintRetVar) +#define UNUSED(x) (void)(x) +#define EXPAND_CONTEXT \ + LLVMLayer* llvm = context.pass->man->llvm; \ + compilation::ICodeScopeUnit* scope = context.scope; \ + compilation::IFunctionUnit* function = context.function; + +AdvancedInstructions::AdvancedInstructions(compilation::Context ctx) +: context(ctx), tyNum(static_cast (ctx.pass->man->llvm->toLLVMType(ExpandedType(TypeAnnotation(TypePrimitive::Num))))) { +} + +llvm::Value* +AdvancedInstructions::compileMapSolidOutput(const Expression &expr, const std::string hintRetVar) { + EXPAND_CONTEXT UNUSED(scope); + + //initialization + Symbol symbolIn = Attachments::get(expr.getOperands()[0]); + + ImplementationRec implIn = containers::Query::queryImplementation(symbolIn).extract(); // impl of input list + size_t size = implIn.size; + CodeScope* scopeLoop = expr.blocks.front(); + std::string varEl = scopeLoop->__bindings[0]; + + Iterator* it = Iterator::create(context, symbolIn); + llvm::Value *rangeFrom = it->begin(); + llvm::Value *rangeTo = it->end(); + + //definitions + ArrayType* tyNumArray = (ArrayType*) (llvm->toLLVMType(ExpandedType(TypeAnnotation(tag_array, TypePrimitive::Num, size)))); + llvm::IRBuilder<> &builder = llvm->builder; + + llvm::BasicBlock *blockLoop = llvm::BasicBlock::Create(llvm->llvmContext, "loop", function->raw); + llvm::BasicBlock *blockBeforeLoop = builder.GetInsertBlock(); + llvm::BasicBlock *blockAfterLoop = llvm::BasicBlock::Create(llvm->llvmContext, "postloop", function->raw); + Value* dataOut = llvm->builder.CreateAlloca(tyNumArray, ConstantInt::get(tyNum, size), NAME("map")); + + // * initial check + Value* condBefore = builder.CreateICmpSLE(rangeFrom, rangeTo); + builder.CreateCondBr(condBefore, blockLoop, blockAfterLoop); + + // create PHI: + builder.SetInsertPoint(blockLoop); + llvm::PHINode *stateLoop = builder.CreatePHI(tyNum, 2, "mapIt"); + stateLoop->addIncoming(rangeFrom, blockBeforeLoop); + + // loop body: + Value* elIn = it->get(stateLoop, varEl); + compilation::ICodeScopeUnit* scopeLoopUnit = function->getScopeUnit(scopeLoop); + scopeLoopUnit->bindArg(elIn, move(varEl)); + Value* elOut = scopeLoopUnit->compile(); + Value *pElOut = builder.CreateGEP(dataOut, ArrayRef(std::vector{ConstantInt::get(tyNum, 0), stateLoop})); + builder.CreateStore(elOut, pElOut); + + //next iteration preparing + Value *stateLoopNext = builder.CreateAdd(stateLoop, llvm::ConstantInt::get(tyNum, 1)); + stateLoop->addIncoming(stateLoopNext, builder.GetInsertBlock()); + + //next iteration checks: + Value* condAfter = builder.CreateICmpSLE(stateLoopNext, rangeTo); + builder.CreateCondBr(condAfter, blockLoop, blockAfterLoop); + + //finalization: + builder.SetInsertPoint(blockAfterLoop); + + return dataOut; +} + +Value* +AdvancedInstructions::compileArrayIndex(llvm::Value* aggregate, std::vector indexes, std::string hintRetVar) { + EXPAND_CONTEXT UNUSED(function); UNUSED(scope); + + indexes.insert(indexes.begin(), llvm::ConstantInt::get(tyNum, 0)); + llvm::Value *pEl = llvm->builder.CreateGEP(aggregate, llvm::ArrayRef(indexes)); + return llvm->builder.CreateLoad(pEl, NAME("el")); +} + +Value* +AdvancedInstructions::compileStructIndex(llvm::Value* aggregate, const ExpandedType& t, const std::string& idx) { + EXPAND_CONTEXT UNUSED(scope); UNUSED(function); + + TypeUtils types(llvm); + std::vector&& fields = types.getStructFields(t); + + for (unsigned i = 0, size = fields.size(); i < size; ++i) { + if (fields.at(i) == idx) { + //dereference pointer + if (types.isPointer(t)) { + llvm::Value* addr = llvm->builder.CreateConstGEP2_32(nullptr, aggregate, 0, i); + return llvm->builder.CreateLoad(addr); + } + + return llvm->builder.CreateExtractValue(aggregate, llvm::ArrayRef{i}); + } + } + + assert(false && "not found required struct field"); + return nullptr; +} + +llvm::Value* +AdvancedInstructions::compileFold(const Expression& fold, const std::string& hintRetVar) { + EXPAND_CONTEXT + assert(fold.op == Operator::FOLD); + + //initialization: + Symbol varInSymbol = Attachments::get(fold.getOperands()[0]); + Implementation info = Query::queryImplementation(varInSymbol); + + Iterator* it = Iterator::create(context, varInSymbol); + llvm::Value* rangeBegin = it->begin(); + llvm::Value* rangeEnd = it->end(); + llvm::Value* accumInit = scope->process(fold.getOperands()[1]); + std::string varIn = fold.getOperands()[0].getValueString(); + std::string varAccum = fold.bindings[1]; + std::string varEl = fold.bindings[0]; + + llvm::BasicBlock *blockBeforeLoop = llvm->builder.GetInsertBlock(); + std::unique_ptr transformerSaturation(new TransformerSaturation(blockBeforeLoop, context.pass->managerTransformations)); + + + llvm::BasicBlock *blockLoop = llvm::BasicBlock::Create(llvm->llvmContext, "fold", function->raw); + llvm::BasicBlock *blockLoopBody = llvm::BasicBlock::Create(llvm->llvmContext, "fold_body", function->raw); + llvm::BasicBlock *blockAfterLoop = llvm::BasicBlock::Create(llvm->llvmContext, "fold_after", function->raw); + llvm::BasicBlock *blockNext = llvm::BasicBlock::Create(llvm->llvmContext, "fold_next", function->raw); + + llvm->builder.CreateBr(blockLoop); + + // * create phi + llvm->builder.SetInsertPoint(blockLoop); + llvm::PHINode *accum = llvm->builder.CreatePHI(accumInit->getType(), 2, varAccum); + accum->addIncoming(accumInit, blockBeforeLoop); + llvm::PHINode *itLoop = llvm->builder.CreatePHI(rangeBegin->getType(), 2, "foldIt"); + itLoop->addIncoming(rangeBegin, blockBeforeLoop); + + // * loop checks + Value* condRange = llvm->builder.CreateICmpNE(itLoop, rangeEnd); + llvm->builder.CreateCondBr(condRange, blockLoopBody, blockAfterLoop); + + // * loop body + llvm->builder.SetInsertPoint(blockLoopBody); + CodeScope* scopeLoop = fold.blocks.front(); + compilation::ICodeScopeUnit* loopUnit = function->getScopeUnit(scopeLoop); + Value* elIn = it->get(itLoop); + loopUnit->bindArg(accum, move(varAccum)); + loopUnit->bindArg(elIn, move(varEl)); + Value* accumNext = loopUnit->compile(); + + // * Loop saturation checks + bool flagSaturationTriggered = transformerSaturation->insertSaturationChecks(blockNext, blockAfterLoop, context); + llvm::BasicBlock* blockSaturation = llvm->builder.GetInsertBlock(); + if (!flagSaturationTriggered){ + llvm->builder.CreateBr(blockNext); + } + + // * computing next iteration state + llvm->builder.SetInsertPoint(blockNext); + Value *itLoopNext = it->advance(itLoop); + accum->addIncoming(accumNext, llvm->builder.GetInsertBlock()); + itLoop->addIncoming(itLoopNext, llvm->builder.GetInsertBlock()); + llvm->builder.CreateBr(blockLoop); + + // * finalization: + llvm->builder.SetInsertPoint(blockAfterLoop); + if (!flagSaturationTriggered){ + return accum; + } + + llvm::PHINode* result = llvm->builder.CreatePHI(accumInit->getType(), 2); + result->addIncoming(accum, blockLoop); + result->addIncoming(accumNext, blockSaturation); + return result; +} + +llvm::Value* +AdvancedInstructions::compileFoldInf(const Expression& fold, const std::string& hintRetVar) { + EXPAND_CONTEXT + assert(fold.op == Operator::FOLD_INF); + + std::string accumName = fold.bindings[0]; + llvm::Value* accumInit = scope->process(fold.getOperands()[0]); + + llvm::BasicBlock *blockBeforeLoop = llvm->builder.GetInsertBlock(); + llvm::BasicBlock *blockLoop = llvm::BasicBlock::Create(llvm->llvmContext, "foldinf", function->raw); + llvm::BasicBlock *blockNext = llvm::BasicBlock::Create(llvm->llvmContext, "foldinf_next", function->raw); + llvm::BasicBlock *blockAfterLoop = llvm::BasicBlock::Create(llvm->llvmContext, "foldinf_post", function->raw); + std::unique_ptr transformerSaturation(new TransformerSaturation(blockBeforeLoop, context.pass->managerTransformations)); + + llvm->builder.CreateBr(blockLoop); + + // * create phi + llvm->builder.SetInsertPoint(blockLoop); + llvm::PHINode *accum = llvm->builder.CreatePHI(accumInit->getType(), 2, accumName); + accum->addIncoming(accumInit, blockBeforeLoop); + + // * loop body + CodeScope* scopeLoop = fold.blocks.front(); + compilation::ICodeScopeUnit* unitLoop = function->getScopeUnit(scopeLoop); + unitLoop->bindArg(accum, move(accumName)); + Value* accumNext = unitLoop->compile(); + + // * Loop saturation checks + bool flagSaturationTriggered = transformerSaturation->insertSaturationChecks(blockNext, blockAfterLoop, context); + assert(flagSaturationTriggered); + + // * computing next iteration state + llvm->builder.SetInsertPoint(blockNext); + accum->addIncoming(accumNext, llvm->builder.GetInsertBlock()); + llvm->builder.CreateBr(blockLoop); + + // finalization: + llvm->builder.SetInsertPoint(blockAfterLoop); + return accumNext; +} + +llvm::Value* +AdvancedInstructions::compileIf(const Expression& exprIf, const std::string& hintRetVar) { + EXPAND_CONTEXT + + const Expression& condExpr = exprIf.getOperands()[0]; + llvm::IRBuilder<>& builder = llvm->builder; + assert(builder.GetInsertBlock() == scope->currentBlockRaw); + + //initialization: + llvm::BasicBlock *blockEpilog = llvm::BasicBlock::Create(llvm->llvmContext, "ifAfter", function->raw); + llvm::BasicBlock *blockTrue = llvm::BasicBlock::Create(llvm->llvmContext, "ifTrue", function->raw); + llvm::BasicBlock *blockFalse = llvm::BasicBlock::Create(llvm->llvmContext, "ifFalse", function->raw); + + llvm::Value* cond = scope->process(condExpr); + + builder.SetInsertPoint(blockTrue); + CodeScope* scopeTrue = exprIf.blocks.front(); + llvm::Value* resultTrue = function->getScopeUnit(scopeTrue)->compile(); + llvm::BasicBlock * blockTrueEnd = builder.GetInsertBlock(); + builder.CreateBr(blockEpilog); + + builder.SetInsertPoint(blockFalse); + CodeScope* scopeFalse = exprIf.blocks.back(); + llvm::Value* resultFalse = function->getScopeUnit(scopeFalse)->compile(); + llvm::BasicBlock * blockFalseEnd = builder.GetInsertBlock(); + builder.CreateBr(blockEpilog); + + builder.SetInsertPoint(scope->currentBlockRaw); + llvm->builder.CreateCondBr(cond, blockTrue, blockFalse); + + builder.SetInsertPoint(blockEpilog); + llvm::PHINode *ret = builder.CreatePHI(resultTrue->getType(), 2, NAME("if")); + + ret->addIncoming(resultTrue, blockTrueEnd); + ret->addIncoming(resultFalse, blockFalseEnd); + + return ret; +} + +//TODO Switch: default variant no needed when all possible conditions are considered +llvm::Value* +AdvancedInstructions::compileSwitch(const Expression& exprSwitch, const std::string& hintRetVar) { + EXPAND_CONTEXT UNUSED(function); + AST* root = context.pass->man->root; + llvm::IRBuilder<>& builder = llvm->builder; + assert(exprSwitch.operands.size() >= 2); + assert(exprSwitch.operands[1].op == Operator::CASE_DEFAULT && "No default case in Switch Statement"); + + int countCases = exprSwitch.operands.size() - 1; + llvm::BasicBlock* blockProlog = builder.GetInsertBlock(); + llvm::BasicBlock *blockEpilog = llvm::BasicBlock::Create(llvm->llvmContext, "switchAfter", function->raw); + builder.SetInsertPoint(blockEpilog); + llvm::Type* exprSwitchType = llvm->toLLVMType(root->getType(exprSwitch)); + llvm::PHINode *ret = builder.CreatePHI(exprSwitchType, countCases, NAME("switch")); + llvm::Type* typI8 = llvm::Type::getInt8Ty(llvm->llvmContext); + + builder.SetInsertPoint(blockProlog); + llvm::Value * conditionSwitch = scope->process(exprSwitch.operands[0]); + llvm::BasicBlock *blockDefault = llvm::BasicBlock::Create(llvm->llvmContext, "caseDefault", function->raw); + llvm::SwitchInst * instructionSwitch = builder.CreateSwitch( + typeinference::doAutomaticTypeConversion(conditionSwitch, typI8, builder), + blockDefault, + countCases); + + for (int size = exprSwitch.operands.size(), i = 2; i < size; ++i) { + llvm::BasicBlock *blockCase = llvm::BasicBlock::Create(llvm->llvmContext, "case" + std::to_string(i), function->raw); + + llvm::Value* condCase = function->getScopeUnit(exprSwitch.operands[i].blocks.front())->compile(); + builder.SetInsertPoint(blockCase); + llvm::Value* resultCase = function->getScopeUnit(exprSwitch.operands[i].blocks.back())->compile(); + builder.CreateBr(blockEpilog); + + ret->addIncoming(resultCase, builder.GetInsertBlock()); + builder.SetInsertPoint(blockProlog); + instructionSwitch->addCase( + dyn_cast( + typeinference::doAutomaticTypeConversion(condCase, typI8, builder)), + blockCase); + } + + //compile default block: + builder.SetInsertPoint(blockDefault); + CodeScope* scopeDefault = exprSwitch.operands[1].blocks.front(); + llvm::Value* resultDefault = function->getScopeUnit(scopeDefault)->compile(); + builder.CreateBr(blockEpilog); + ret->addIncoming(resultDefault, builder.GetInsertBlock()); + builder.SetInsertPoint(blockEpilog); + + return ret; +} + +llvm::Value* +AdvancedInstructions::compileSwitchVariant(const Expression& exprSwitch, const std::string& hintRetVar) { + EXPAND_CONTEXT UNUSED(function); + AST* root = context.pass->man->root; + llvm::IRBuilder<>& builder = llvm->builder; + llvm::Type* typI8= llvm::Type::getInt8Ty(llvm->llvmContext); + const ExpandedType& typVariant = root->getType(exprSwitch.operands.at(0)); + llvm::Type* typVariantRaw = llvm->toLLVMType(typVariant); + + assert(typVariant->__operands.size() == exprSwitch.operands.size() - 1 && "Ill-formed Switch Variant"); + + int casesCount = exprSwitch.operands.size(); + llvm::BasicBlock* blockProlog = builder.GetInsertBlock(); + llvm::BasicBlock *blockEpilog = llvm::BasicBlock::Create(llvm->llvmContext, "switchAfter", function->raw); + builder.SetInsertPoint(blockEpilog); + llvm::Type* resultType = llvm->toLLVMType(root->getType(exprSwitch)); + llvm::PHINode *ret = builder.CreatePHI(resultType, casesCount, NAME("switch")); + + builder.SetInsertPoint(blockProlog); + llvm::Value * conditionSwitchRaw = scope->process(exprSwitch.operands.at(0)); + llvm::Value* idRaw = builder.CreateExtractValue(conditionSwitchRaw, llvm::ArrayRef({0})); + + //Dereference preparation + const bool flagPrepareDerefence = std::any_of(typVariant->__operands.begin(), typVariant->__operands.end(), [](const TypeAnnotation& op){ + return op.isValid(); + }); + + llvm::Value* addrAsStorage = nullptr; + if (flagPrepareDerefence){ + assert(exprSwitch.bindings.size() && "Switch condition alias not found"); + llvm::Type* typStorageRaw = llvm::cast(typVariantRaw)->getElementType(1); + llvm::Value* storageRaw = builder.CreateExtractValue(conditionSwitchRaw, llvm::ArrayRef({1})); + addrAsStorage = llvm->builder.CreateAlloca(typStorageRaw); + llvm->builder.CreateStore(storageRaw, addrAsStorage); + } + + llvm::SwitchInst * instructionSwitch = builder.CreateSwitch(idRaw, nullptr, casesCount); + llvm::BasicBlock* blockDefaultUndefined; + std::list::const_iterator scopeCaseIt = exprSwitch.blocks.begin(); + for (int instancesSize = exprSwitch.operands.size()-1, instId = 0; instId < instancesSize; ++instId) { + llvm::BasicBlock *blockCase = llvm::BasicBlock::Create(llvm->llvmContext, "case" + std::to_string(instId), function->raw); + builder.SetInsertPoint(blockCase); + ICodeScopeUnit* unitCase = function->getScopeUnit(*scopeCaseIt); + const ExpandedType& instType = ExpandedType(typVariant->__operands.at(instId)); + + //Actual variant derefence + if (instType->isValid()) { + string identCondition = exprSwitch.bindings.front(); + llvm::Type* instTypeRaw = llvm->toLLVMType(instType); + llvm::Value* addrAsInst = llvm->builder.CreateBitOrPointerCast(addrAsStorage, instTypeRaw->getPointerTo()); + llvm::Value* instRaw = llvm->builder.CreateLoad(instTypeRaw, addrAsInst); + const Symbol& identSymb = unitCase->bindArg(instRaw, move(identCondition)); + Attachments::put(identSymb, instType); + } + + llvm::Value* resultCase = function->getScopeUnit(*scopeCaseIt)->compile(); + builder.CreateBr(blockEpilog); + + ret->addIncoming(resultCase, blockDefaultUndefined = builder.GetInsertBlock()); + builder.SetInsertPoint(blockProlog); + instructionSwitch->addCase(dyn_cast(llvm::ConstantInt::get(typI8, exprSwitch.operands.at(instId+1).getValueDouble())), blockCase); + ++scopeCaseIt; + } + + instructionSwitch->setDefaultDest(blockDefaultUndefined); + builder.SetInsertPoint(blockEpilog); + return ret; +} + +//TODO recognize cases to make const arrays/stored in global mem/stack alloced. +llvm::Value* +AdvancedInstructions::compileListAsSolidArray(const Expression &expr, const std::string& hintRetVar) { + EXPAND_CONTEXT UNUSED(scope); UNUSED(function); + + AST* root = context.pass->man->root; + const size_t& length = expr.getOperands().size(); + const Expression& expression = expr; + llvm::Value* zero = ConstantInt::get(tyNum, 0); + llvm::Value* one = ConstantInt::get(tyNum, 1); + + ExpandedType typAggrExpanded = root->getType(expression); + assert(typAggrExpanded->__operator == TypeOperator::LIST); + llvm::Type* typEl = llvm->toLLVMType(ExpandedType(typAggrExpanded->__operands[0])); + ArrayType* typAggr = (ArrayType*) llvm::ArrayType::get(typEl, length); + llvm::Value* list = llvm->builder.CreateAlloca(typAggr, ConstantInt::get(Type::getInt32Ty(llvm->llvmContext), length, false), hintRetVar); + + const std::vector& operands = expression.getOperands(); + llvm::Value* addrOperand = llvm->builder.CreateGEP(typAggr, list, ArrayRef(std::vector{zero, zero})); + llvm->builder.CreateStore(scope->process(operands.front()), addrOperand) ; + for (auto i=++operands.begin(); i!=operands.end(); ++i){ + addrOperand = llvm->builder.CreateGEP(typEl, addrOperand, ArrayRef(std::vector{one})); + llvm->builder.CreateStore(scope->process(*i), addrOperand) ; + } + + return list; +// Value* listDest = l.builder.CreateAlloca(typList, ConstantInt::get(typI32, __size), *hintRetVar); +// l.buil1der.CreateMemCpy(listDest, listSource, __size, 16); +} + +llvm::Value* +AdvancedInstructions::compileConstantStringAsPChar(const string& data, const std::string& hintRetVar) { + EXPAND_CONTEXT UNUSED(function); UNUSED(scope); + + Type* typPchar = PointerType::getUnqual(Type::getInt8Ty(llvm->llvmContext)); + //ArrayType* typStr = (ArrayType*) (llvm->toLLVMType(ExpandedType(TypeAnnotation(tag_array, TypePrimitive::I8, size+1)))); + + /* + std::vector chars; + chars.reserve(size+1); + + for (size_t i=0; i< size; ++i){ + chars[i] = ConstantInt::get(typI8, (unsigned char) data[i]); + } + chars[size] = ConstantInt::get(typI8, 0); + */ + + Value* rawData = ConstantDataArray::getString(llvm->llvmContext, data); + Value* rawPtrData = llvm->builder.CreateAlloca(rawData->getType(), ConstantInt::get(Type::getInt32Ty(llvm->llvmContext), 1, false)); + llvm->builder.CreateStore(rawData, rawPtrData); + return llvm->builder.CreateCast(llvm::Instruction::BitCast, rawPtrData, typPchar, hintRetVar); +} + +llvm::Value* +AdvancedInstructions::compileSequence(const Expression &expr){ + EXPAND_CONTEXT UNUSED(scope); UNUSED(llvm); + + llvm::Value* result; + for(CodeScope* scope: expr.blocks){ + result = function->getScopeUnit(scope)->compile(); + } + + return result; +} + + diff --git a/cpp/src/compilation/advanced.h b/cpp/src/compilation/advancedinstructions.h similarity index 72% rename from cpp/src/compilation/advanced.h rename to cpp/src/compilation/advancedinstructions.h index 373e825..7b0fbfb 100644 --- a/cpp/src/compilation/advanced.h +++ b/cpp/src/compilation/advancedinstructions.h @@ -1,47 +1,52 @@ -/* - * File: InstructionsAdvanced.h - * Author: pgess +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * File: AdvancedInstructions.h + * Author: pgess * * Created on June 26, 2016, 6:00 PM */ #ifndef INSTRUCTIONSADVANCED_H #define INSTRUCTIONSADVANCED_H #include "ast.h" #include "llvmlayer.h" #include "pass/compilepass.h" #include namespace xreate { namespace compilation { -class Advanced { +class AdvancedInstructions { public: - Advanced(compilation::Context ctx); + AdvancedInstructions(compilation::Context ctx); llvm::Value* compileArrayIndex(llvm::Value* aggregate, 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* compileMapSolidOutput(const Expression &expr, const std::string hintRetVar = ""); llvm::Value* compileFold(const Expression& fold, const std::string& ident=""); llvm::Value* compileFoldInf(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* compileSwitchVariant(const Expression& exprSwitch, const std::string& hintRetVar); llvm::Value* compileConstantStringAsPChar(const std::string &data, const std::string& hintRetVar); - llvm::Value* compileListAsSolidArray(const Expression &expr, const std::string& hintRetVar=""); + llvm::Value* compileListAsSolidArray(const Expression &expr, const std::string& hintRetVar); + llvm::Value* compileSequence(const Expression &expr); private: compilation::Context context; llvm::IntegerType* const tyNum; }; }} #endif /* INSTRUCTIONSADVANCED_H */ diff --git a/cpp/src/compilation/containers.cpp b/cpp/src/compilation/containers.cpp index df7c9e3..f8d36fc 100644 --- a/cpp/src/compilation/containers.cpp +++ b/cpp/src/compilation/containers.cpp @@ -1,195 +1,206 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * File: containers.cpp + * Author: pgess + * + * \file compilation/containers.h + * \brief Containers compilation support. See more [details on Containers](/w/concepts/containers) + */ + #include "compilation/containers.h" using namespace std; using namespace llvm; using namespace xreate; using namespace xreate::containers; Iterator* Iterator::create(xreate::compilation::Context context, const xreate::Symbol& var){ const Implementation& data = Query::queryImplementation(var); switch(data.impl){ case ON_THE_FLY: return new IteratorForward(context, var, data.extract()); case SOLID: return new IteratorForward(context, var, data.extract()); default: assert(true); } assert(false && "Unknown declaration"); return nullptr; } llvm::Value* IteratorForward::begin() { switch(sourceDecl.op) { case xreate::Operator::LIST: { - sourceRawType = llvm::Type::getInt32Ty(llvm::getGlobalContext()); - return llvm::ConstantInt::get(Type::getInt32Ty(llvm::getGlobalContext()), 0); + sourceRawType = llvm::Type::getInt32Ty(llvm->llvmContext); + return llvm::ConstantInt::get(Type::getInt32Ty(llvm->llvmContext), 0); }; case xreate::Operator::LIST_RANGE:{ assert(sourceDecl.operands.size()==2); llvm::Value* result = sourceUnit->process(sourceDecl.operands.at(0)); sourceRawType = result->getType(); return result; }; default: break; } if (linkedlist){ llvm::Value* result = sourceUnit->process(sourceDecl); sourceRawType = result->getType(); return result; } assert(false); } llvm::Value* IteratorForward::end(){ switch(sourceDecl.op) { case xreate::Operator::LIST: { size_t idLast = sourceDecl.operands.size() - 1; return ConstantInt::get(sourceRawType, idLast); } case xreate::Operator::LIST_RANGE: { assert(sourceDecl.operands.size() == 2); llvm::Value* valueEndOfRange = sourceUnit->process(sourceDecl.operands.at(1)); - llvm::Value* valueConstOne = llvm::ConstantInt::get(llvm::Type::getInt32Ty(llvm::getGlobalContext()), 1); + llvm::Value* valueConstOne = llvm::ConstantInt::get(llvm::Type::getInt32Ty(llvm->llvmContext), 1); return llvm->builder.CreateAdd(valueEndOfRange, valueConstOne); }; default: break; } //return null pointer if (linkedlist){ return ConstantPointerNull::getNullValue(sourceRawType); } assert(false && "Unknown declaration"); return nullptr; } llvm::Value* IteratorForward::get(Value* index,const std::string& hintRetVar){ - const Expression& currentDecl = CodeScope::findDeclaration(current); + const Expression& currentDecl = CodeScope::getDefinition(current); switch (currentDecl.op) { case xreate::Operator::LIST: { //TODO re check is it right scope(source) to compile currentDecl. Provide unittests. - llvm::Value* currentValue = sourceUnit->compileSymbol(current); - return xreate::compilation::Advanced(context).compileArrayIndex(currentValue, std::vector{index}); + llvm::Value* currentValue = sourceUnit->processSymbol(current); + return xreate::compilation::AdvancedInstructions(context).compileArrayIndex(currentValue, std::vector{index}); }; case xreate::Operator::LIST_RANGE: { return index; }; case xreate::Operator::MAP: { assert(currentDecl.getOperands().size()==1); assert(currentDecl.bindings.size()); assert(currentDecl.blocks.size()); CodeScope* scopeLoop = currentDecl.blocks.front(); - const std::string& varIn = currentDecl.getOperands()[0].getValueString(); std::string varEl = currentDecl.bindings[0]; - const Symbol& symbIn = current.scope->findSymbol(varIn); + const Symbol& symbIn = Attachments::get(currentDecl.getOperands()[0]); auto it = std::unique_ptr(Iterator::create(context, symbIn)); Value* elIn = it->get(index, varEl); - compilation::CodeScopeUnit* unitLoop = function->getScopeUnit(scopeLoop); + compilation::ICodeScopeUnit* unitLoop = function->getScopeUnit(scopeLoop); unitLoop->bindArg(elIn, std::move(varEl)); return unitLoop->compile(); } - case xreate::Operator::NONE: { + case xreate::Operator::INVALID: { //TODO review iterator determination strategy for case of Expression::BINDING assert(currentDecl.__state==Expression::IDENT); - const Symbol& symbIn = current.scope->findSymbol(currentDecl.getValueString()); + + const Symbol& symbIn = Attachments::get(currentDecl); auto it = std::unique_ptr(Iterator::create(context, symbIn)); return it->get(index); }; default: break; } if (linkedlist){ return index; } assert(false && "Unknown declaration"); return nullptr; } llvm::Value* IteratorForward::advance(Value* index, const std::string& hintRetVar){ switch(sourceDecl.op) { case xreate::Operator::LIST: case xreate::Operator::LIST_RANGE: - return llvm->builder.CreateAdd(index, llvm::ConstantInt::get(llvm::Type::getInt32Ty(llvm::getGlobalContext()), 1), hintRetVar); + return llvm->builder.CreateAdd(index, llvm::ConstantInt::get(llvm::Type::getInt32Ty(llvm->llvmContext), 1), hintRetVar); default: break; } if (linkedlist){ - ExpandedType tySource = llvm->ast->expandType(CodeScope::findDeclaration(source).type); - assert(tySource->__operator == TypeOperator::ARRAY && "Linked list implementation has to have ARRAY type"); + ExpandedType tySource = llvm->ast->getType(CodeScope::getDefinition(source)); + assert(tySource->__operator == TypeOperator::LIST && "Linked list implementation has to have ARRAY type"); assert(tySource->__operands.size()); - return xreate::compilation::Advanced(context).compileStructIndex(index, ExpandedType(TypeAnnotation(tySource->__operands.at(0))), linkedlist.fieldPointer); + return xreate::compilation::AdvancedInstructions(context).compileStructIndex(index, ExpandedType(TypeAnnotation(tySource->__operands.at(0))), linkedlist.fieldPointer); } assert(false && "Unknown declaration"); return nullptr; } //const ImplementationRec& implementation IteratorForward::IteratorForward(const compilation::Context& ctx, const xreate::Symbol& symbolContainer, const ImplementationRec& implementation) - : Iterator(), llvm(ctx.pass->man->llvm), __length(implementation.size) + : Iterator(), __length(implementation.size), llvm(ctx.pass->man->llvm) { - __container = ctx.function->getScopeUnit(symbolContainer.scope)->compileSymbol(symbolContainer); + __container = ctx.function->getScopeUnit(symbolContainer.scope)->processSymbol(symbolContainer); } llvm::Value* IteratorForward::begin(){ //0 - return llvm::ConstantInt::get(llvm::Type::getInt32Ty(llvm::getGlobalContext()), 0); + return llvm::ConstantInt::get(llvm::Type::getInt32Ty(llvm->llvmContext), 0); } llvm::Value* IteratorForward::end(){ //length - return llvm::ConstantInt::get(llvm::Type::getInt32Ty(llvm::getGlobalContext()), __length); + return llvm::ConstantInt::get(llvm::Type::getInt32Ty(llvm->llvmContext), __length); } llvm::Value* IteratorForward::get(llvm::Value* index,const std::string& hintRetVar){ //GEP[index]] - llvm::Type* tyNum = llvm::Type::getInt32Ty(llvm::getGlobalContext()); + llvm::Type* tyNum = llvm::Type::getInt32Ty(llvm->llvmContext); llvm::Value* pResult = llvm->builder.CreateGEP(__container, ArrayRef(std::vector{ConstantInt::get(tyNum, 0), index})); return llvm->builder.CreateLoad(pResult, hintRetVar); } llvm::Value* IteratorForward::advance(llvm::Value* index, const std::string& hintRetVar){ //index + 1 - llvm::Type* tyNum = llvm::Type::getInt32Ty(llvm::getGlobalContext()); + llvm::Type* tyNum = llvm::Type::getInt32Ty(llvm->llvmContext); return llvm->builder.CreateAdd(index, llvm::ConstantInt::get(tyNum, 1), hintRetVar); } diff --git a/cpp/src/compilation/containers.h b/cpp/src/compilation/containers.h index 222be75..bd8a4fc 100644 --- a/cpp/src/compilation/containers.h +++ b/cpp/src/compilation/containers.h @@ -1,80 +1,96 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * File: containers.h + * Author: pgess + */ + #ifndef CODEINSTRUCTIONS_H #define CODEINSTRUCTIONS_H #include "ast.h" #include "llvmlayer.h" #include "pass/compilepass.h" -#include "compilation/advanced.h" - -#include "query/context.h" +#include "compilation/advancedinstructions.h" #include "query/containers.h" namespace xreate { namespace containers { using namespace llvm; +/** \brief Factory to create relevant iterator based on solution + * provided by xreate::containers::Query + * \sa xreate::containers::Query + */ 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* advance(llvm::Value* index, const std::string& hintRetVar="")=0; virtual ~Iterator(){}; static Iterator* create(xreate::compilation::Context context, const xreate::Symbol& var); }; template class IteratorForward; +/** \brief Possible container implementation. Represents computation on the fly + * \sa xreate::containers::Iterator, \sa xreate::containers::Query + */ template<> class IteratorForward : public Iterator { private: LLVMLayer* llvm; const xreate::Symbol current; const Symbol source; const ImplementationLinkedList linkedlist; - CodeScope* const sourceScope; + const CodeScope* const sourceScope; //TODO initialize and mark as const (three fields) - compilation::CodeScopeUnit* sourceUnit; - compilation::FunctionUnit* function; //TODO is used somewhere? + compilation::ICodeScopeUnit* sourceUnit; + compilation::IFunctionUnit* function; //TODO is used somewhere? const Expression& sourceDecl; compilation::Context context; llvm::Type* sourceRawType =nullptr; public: IteratorForward(const 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)), + sourceUnit(ctx.function->getScopeUnit(source.scope)), + sourceDecl(CodeScope::getDefinition(source)), context(ctx) {} llvm::Value* begin() override; llvm::Value* end() override; llvm::Value* get(llvm::Value* index,const std::string& hintRetVar="") override; llvm::Value* advance(llvm::Value* index, const std::string& hintRetVar="") override; }; +/** \brief Possible container implementation. Represents contiguous in memory(array) implementation + * \sa xreate::containers::Iterator, \sa xreate::containers::Query + */ template<> class IteratorForward: public Iterator{ size_t __length; llvm::Value* __container; LLVMLayer* llvm; public: IteratorForward(const compilation::Context& ctx, const xreate::Symbol& symbolContainer, const ImplementationRec& implementation); llvm::Value* begin() override; llvm::Value* end() override; llvm::Value* get(llvm::Value* index,const std::string& hintRetVar="") override; llvm::Value* advance(llvm::Value* index, const std::string& hintRetVar="") override; }; }} #endif //CODEINSTRUCTIONS_H diff --git a/cpp/src/compilation/interpretation-instructions.cpp b/cpp/src/compilation/interpretation-instructions.cpp new file mode 100644 index 0000000..7c4845f --- /dev/null +++ b/cpp/src/compilation/interpretation-instructions.cpp @@ -0,0 +1,116 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +/* + * Author: pgess + * Created on June 15, 2018, 5:32 PM + * + */ + +#include "compilation/interpretation-instructions.h" +#include "analysis/interpretation.h" +#include "transcendlayer.h" +#include "targets.h" +#include "aux/latereasoning.h" +#include "latereasoning.h" +#include "aux/transcend-decorators.h" +#include "compilation/targetinterpretation.h" + +using namespace std; +using namespace xreate::latereasoning; + +namespace xreate{ +namespace interpretation{ + +Expression +IntrinsicQueryInstruction::process(const Expression& expression) { + AST* ast = static_cast (__fnI12n->man)->ast; + TranscendLayer* transcend = static_cast (__fnI12n->man)->pass->man->transcend; + + ExpandedType targetT = ast->getType(expression); + assert(expression.operands.size() == 1); + assert(expression.operands.front().__state == Expression::STRING); + assert(targetT->__operator == TypeOperator::LIST); + + std::string namePredicate = expression.operands.front().getValueString(); + StaticModel model = (static_cast (__fnI12n->man))->pass->man->transcend->query(namePredicate); + + Expression result(Operator::LIST,{}); + result.operands.reserve(model.size()); + + ExpandedType elementT = targetT->__operands.at(0).__operator == TypeOperator::SLAVE + ? dereferenceSlaveType(ExpandedType(targetT->__operands.at(0)), transcend) + : ExpandedType(targetT->__operands.at(0)); + + if(model.size()) { + if (elementT->__operator == TypeOperator::LIST_NAMED) { + //edge case, content's type is LIST_NAMED: + for(const auto& row : model) { + result.operands.push_back(representTransExpression(row.second, elementT, transcend)); + } + } else { + for (const auto& row : model) { + assert(row.second.args().size); + result.operands.push_back(representTransExpression(row.second.args()[0], elementT, transcend)); + } + } + } + + return result; +} + +llvm::Value* +IntrinsicQueryInstruction::processLate(const Expression& expression, const compilation::Context& context) { + assert(expression.blocks.size()); + CodeScope* body = expression.blocks.front(); + PassManager* man = static_cast (__fnI12n->man)->pass->man; + compilation::ICodeScopeUnit* bodyBrute = context.function->getScopeUnit(body); + + llvm::Type* instructionT = man->llvm->toLLVMType(man->root->getType(expression)); + Expression atomNameE = __fnI12n->getScope(context.scope->scope)->process(expression.operands.front()); + assert(atomNameE.__state == Expression::STRING); + string atomName = atomNameE.getValueString(); + std::string argName = expression.bindings.front(); + ExpandedType argT = man->root->getType(body->getDefinition(body->getSymbol(argName))); + if (argT->__operator == TypeOperator::SLAVE){ + argT = dereferenceSlaveType(argT, man->transcend); + } + + auto transcend = + Decorators::getInterface(man->transcend); + LateReasoningCompiler* compiler = + new latereasoning::LateReasoningCompiler(__fnI12n, context); + SymbolPacked targetSP = transcend->pack(Attachments::get(expression)); + + LateAnnotationsGroup feedbackAG = transcend->queryLate(atomName); + for(const auto& feedback : feedbackAG.annotations) { + SymbolPacked targetExpectedSP = ParseImplAtom::get(feedback.first); + if (targetExpectedSP == targetSP) { + const LateAnnotation& annotation = feedback.second; + return compiler->compileAutoExpand(annotation, instructionT, "", + [transcend, &argT, this, body, bodyBrute, &argName](const Gringo::Symbol & atomRaw) { + InterpretationScope* bodyI12n = __fnI12n->getScope(body); + Expression argValue; + if (argT->__operator == TypeOperator::LIST_NAMED) { + argValue = representTransExpression(atomRaw, argT, transcend); + } else { + argValue = representTransExpression(atomRaw.args()[0], argT, transcend); + } + + bodyI12n->overrideBindings({ + {argValue, argName}}); + bodyBrute->reset(); + return bodyBrute->compile(); + }); + } + } + + assert(false && "No appropriate late annotation"); + return nullptr; //should not be ever reachable +} + +} +} //end of xreate::interpretation \ No newline at end of file diff --git a/cpp/src/compilation/interpretation-instructions.h b/cpp/src/compilation/interpretation-instructions.h new file mode 100644 index 0000000..284b094 --- /dev/null +++ b/cpp/src/compilation/interpretation-instructions.h @@ -0,0 +1,46 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +/* + * Author: pgess + * Created on June 15, 2018, 5:28 PM + * + * \file interpretation-instructions.h + * \brief Additional intepretation statements + */ + +#ifndef INTERPRETATION_INSTRUCTIONS_H +#define INTERPRETATION_INSTRUCTIONS_H + +#include "ast.h" + +namespace xreate{ +namespace compilation{ + class Context; +} +} + +namespace xreate{ +namespace interpretation{ + +class InterpretationFunction; + +class IntrinsicQueryInstruction{ +public: + + IntrinsicQueryInstruction(InterpretationFunction* fn): __fnI12n(fn){ } + Expression process(const Expression& expression); + llvm::Value* processLate(const Expression& expression, const compilation::Context& context); + +private: + InterpretationFunction* __fnI12n; +}; + +} +} //end of xreate::interpretation + +#endif /* INTERPRETATION_INSTRUCTIONS_H */ + diff --git a/cpp/src/compilation/latecontextcompiler2.cpp b/cpp/src/compilation/latecontextcompiler2.cpp deleted file mode 100644 index 7008044..0000000 --- a/cpp/src/compilation/latecontextcompiler2.cpp +++ /dev/null @@ -1,193 +0,0 @@ -/* - * LateContextCompiler2.cpp - * - * Created on: 10 февр. 2016 - * Author: pgess - */ - -//TOTEST default variants - do not enable specialization context in order to check default variant invocation - -#include "latecontextcompiler2.h" -#include "llvmlayer.h" -#include "pass/compilepass.h" -#include "query/context.h" -#include - -using namespace std; - -namespace xreate { - -const string topicSpecializationAtom = "specialization"; -const string topicDependencyAtom = "dependency"; - -typedef ExpressionSerialization::Code DomainId; -typedef ExpressionSerialization::Serializer Domain; - -//TODO implement variantDefault; -llvm::Value* compileDecisionSelector(llvm::IRBuilder<>& builder, llvm::Value* selector, std::vector vectorVariants, llvm::Value* variantDefault=nullptr){ - assert(vectorVariants.size()>0); - llvm::IntegerType* ty32 = llvm::Type::getInt32Ty(llvm::getGlobalContext()); - - llvm::Type* tyElement = vectorVariants[0]->getType(); - llvm::Type* tyVariants = llvm::VectorType::get(tyElement, vectorVariants.size()); - llvm::Value* vectorRaw = llvm::ConstantVector::getNullValue(tyVariants); - - - for(DomainId i=0; iqueryContext; - __sizeOfDemand = context->getFunctionDemand(function->function->getName()).size(); -} - -llvm::Value* -LateContextCompiler2::findFunction(const std::string& calleeName, llvm::Function* specializationDefault, ScopePacked scopeCaller){ - const string& functionName = function->function->getName(); - ContextQuery* context = pass->queryContext; - llvm::IRBuilder<>& builder = pass->man->llvm->builder; - - const FunctionDemand& demand = context->getFunctionDemand(functionName); - const std::list& specializations = pass->man->root->getFunctionVariants(calleeName); - - //independent decision: - Expression topic(Operator::CALL, {(Atom(string(topicSpecializationAtom))), (Atom(string(calleeName))), (Atom(scopeCaller))}); - assert(demand.right.count(topic) && "Can't determine specialization for the function"); - size_t topicId = demand.right.at(topic); - llvm::Value* topicDecisionRaw = builder.CreateExtractValue(this->rawContextArgument, llvm::ArrayRef{(unsigned) topicId}); - - const Domain& specializationsDomain= context->getTopicDomain(topic); - - std::vector vectorVariants; - vectorVariants.reserve(specializationsDomain.size()); - for (const ManagedFnPtr& f: specializations){ - if (!f->guardContext.isValid()) continue; - const auto& variantId = specializationsDomain.getIdOptional(f->guardContext); - if (variantId){ - if (vectorVariants.size() < *variantId + 1) { - vectorVariants.resize(*variantId + 1); - } - - vectorVariants[*variantId] = pass->getFunctionUnit(f)->compile(); - } - } - - return compileDecisionSelectorAsSwitch(topicDecisionRaw, vectorVariants, specializationDefault); -} - -llvm::Value* -LateContextCompiler2::compileContextArgument(const std::string& callee, ScopePacked scopeCaller){ - const std::string& atomDependentDecision = Config::get("clasp.context.decisions.dependent"); - llvm::IRBuilder<>& builder = pass->man->llvm->builder; - ContextQuery* context = pass->queryContext; - - const string& functionName = function->function->getName(); - const Decisions& dictStaticDecisions = context->getFinalDecisions(scopeCaller); - - const FunctionDemand& demandCallee = context->getFunctionDemand(callee); - const FunctionDemand& demandSelf = context->getFunctionDemand(functionName); - - llvm::IntegerType* ty32 = llvm::Type::getInt32Ty(llvm::getGlobalContext()); - llvm::Type* tyDemand = llvm::ArrayType::get(ty32, demandCallee.size()); - - //builder.CreateAlloca(tyDemand, llvm::ConstantInt::get(ty32, 1)); - llvm::Value* res = llvm::ConstantArray::getNullValue(tyDemand); - - for (size_t i=0, size = demandCallee.size(); irawContextArgument, llvm::ArrayRef{(unsigned) topicId}); - - } else if (dictStaticDecisions.count(topic)){ - //static final decision: - const Expression& decision = dictStaticDecisions.at(topic); - const Domain& domainOfTopic = context->getTopicDomain(topic); - const DomainId& decisionCode = domainOfTopic.getId(decision); - decisionRaw = llvm::ConstantInt::get(ty32, decisionCode); - - } else { - //dependent decision - decisionRaw = compileDependentDecision(topic, scopeCaller); - } - - res = builder.CreateInsertValue(res, decisionRaw, llvm::ArrayRef{(unsigned) i}); - } - - return res; -} - -llvm::Value* -LateContextCompiler2::compileDependentDecision(const Expression& topic, ScopePacked scopeCaller){ - const string& functionName = function->function->getName(); - ContextQuery* context = pass->queryContext; - llvm::IRBuilder<>& builder = pass->man->llvm->builder; - llvm::IntegerType* ty32 = llvm::Type::getInt32Ty(llvm::getGlobalContext()); - - const FunctionDemand& demandSelf = context->getFunctionDemand(functionName); - const Expression topicDependency = Expression(Operator::CALL, {Atom(string(topicDependencyAtom)), topic, Atom(scopeCaller)}); - - const Domain& demandOfTopic = context->getTopicDomain(topic); - const Domain& domainOfTopicDependency = context->getTopicDomain(topicDependency); - - //dependent decision - vector vectorDecisions(domainOfTopicDependency.size(), llvm::UndefValue::get(ty32)); - for (const std::pair& entry: context->getDependentDecision(scopeCaller,topic)){ - vectorDecisions[domainOfTopicDependency.getId(entry.first)]= llvm::ConstantInt::get(ty32, demandOfTopic.getId(entry.second)); - } - - size_t topicDependencyId = demandSelf.right.at(topicDependency); - llvm::Value* decisionRaw = builder.CreateExtractValue(this->rawContextArgument, llvm::ArrayRef{(unsigned) topicDependencyId}); - - auto result = compileDecisionSelector(pass->man->llvm->builder, decisionRaw, vectorDecisions); - - return result; -} - - - -llvm::Value* -LateContextCompiler2::compileDecisionSelectorAsSwitch(llvm::Value* selector, std::vector vectorVariants, llvm::Function* variantDefault){ - llvm::IRBuilder<>& builder = pass->man->llvm->builder; - llvm::IntegerType* ty32 = llvm::Type::getInt32Ty(llvm::getGlobalContext()); - - llvm::BasicBlock* blockDefault = llvm::BasicBlock::Create(llvm::getGlobalContext(), "caseDefault", this->function->raw); - llvm::BasicBlock *blockEpilog = llvm::BasicBlock::Create(llvm::getGlobalContext(), "VariantDeterminationEnd", this->function->raw); - - llvm::SwitchInst* instrSwitch = builder.CreateSwitch(selector, blockDefault, vectorVariants.size()); - - builder.SetInsertPoint(blockEpilog); - llvm::PHINode *result = builder.CreatePHI(variantDefault->getType(), vectorVariants.size(), "callee"); - - for (size_t i=0; ifunction->raw); - builder.SetInsertPoint(blockCase); - builder.CreateBr(blockEpilog); - result->addIncoming(vectorVariants[i], blockCase); - instrSwitch->addCase(llvm::ConstantInt::get(ty32, i), blockCase); - } - - builder.SetInsertPoint(blockDefault); - builder.CreateBr(blockEpilog); - result->addIncoming(variantDefault, blockDefault); - - builder.SetInsertPoint(blockEpilog); - return result; -} - -size_t -LateContextCompiler2::getFunctionDemandSize() const { - return __sizeOfDemand; -} - -} /* namespace xreate */ diff --git a/cpp/src/compilation/latecontextcompiler2.h b/cpp/src/compilation/latecontextcompiler2.h deleted file mode 100644 index abb12e1..0000000 --- a/cpp/src/compilation/latecontextcompiler2.h +++ /dev/null @@ -1,51 +0,0 @@ -/* - * LateContextCompiler2.h - * - * Created on: 10 февр. 2016 - * Author: pgess - */ - -//TOTEST compile several context arguments -#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* rawContextArgument = nullptr; - - LateContextCompiler2(compilation::FunctionUnit* f, CompilePass* p); - llvm::Value* findFunction(const std::string& calleeName, llvm::Function* specializationDefault, ScopePacked scopeCaller); - llvm::Value* compileContextArgument(const std::string& callee, ScopePacked scopeCaller); - size_t getFunctionDemandSize() const; - -private: - //boost::bimap __decisions; - //std::vector __scheme; - - compilation::FunctionUnit* function; - CompilePass* pass; - size_t __sizeOfDemand; - - llvm::Value* compileDependentDecision(const Expression& topic, ScopePacked scopeCaller); - llvm::Value* compileDecisionSelectorAsSwitch(llvm::Value* selector, std::vector vectorVariants, llvm::Function* variantDefault); -}; -} /* namespace xreate */ - -#endif /* LATECONTEXTCOMPILER2_H_ */ \ No newline at end of file diff --git a/cpp/src/compilation/latereasoning.cpp b/cpp/src/compilation/latereasoning.cpp new file mode 100644 index 0000000..4b32156 --- /dev/null +++ b/cpp/src/compilation/latereasoning.cpp @@ -0,0 +1,179 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * latereasoning.cpp + * + * Author: pgess + * Created on May 26, 2018, 3:54 PM + */ + +#include "compilation/latereasoning.h" +//#include "aux/latereasoning.h" +#include "compilation/scopedecorators.h" +#include "analysis/interpretation.h" +#include "compilation/targetinterpretation.h" + +#include + +using namespace xreate::interpretation; +using namespace xreate::compilation; +using namespace std; + +namespace xreate{ +namespace latereasoning{ + +#define HINT(x) (hint.empty()? x : hint) + +std::map LateReasoningCompiler:: __dictGuardDefinitions = std::map(); + +llvm::Value* +LateReasoningCompiler::processSwitchLateStatement(const Expression& expr, const std::string& hint) { + AST* root = __context.pass->man->root; + LLVMLayer* llvm = __context.pass->man->llvm; + + CodeScope* scopeBody = expr.blocks.front(); + Symbol guardS = Symbol{scopeBody->getSymbol(expr.bindings.front()), scopeBody}; + const ExpandedType& guardT = root->getType(expr.operands.at(0)); + const ExpandedType& guardTPlain = guardT->__operator == TypeOperator::SLAVE? + interpretation::dereferenceSlaveType(guardT, __context.pass->man->transcend) + : guardT; + + llvm::Value * guardRaw = __context.scope->process(expr.operands.at(0)); + llvm::Type* instructionT = llvm->toLLVMType(root->getType(expr)); + + return compileExpand(guardS, guardRaw, guardTPlain, instructionT, hint, [this, scopeBody]() { + ICodeScopeUnit* bodyUnit = this->__context.function->getScopeUnit(scopeBody); + bodyUnit->reset(); + return this->__context.function->getScopeUnit(scopeBody)->compile(); + }); +} + +llvm::Value* +LateReasoningCompiler::compileAutoExpand(const LateAnnotation& annotation, + llvm::Type* resultT, + const std::string& hint, + Handler handler) { + TranscendLayer* transcend = __context.pass->man->transcend; + AST* root = __context.pass->man->root; + + const std::list& guardKeys = annotation.guardKeys; + std::list guardsToExpand; + for(const SymbolPacked key : guardKeys) { + if(!__dictGuardDefinitions.count(key)) { + const Symbol& keyS = transcend->unpack(key); + InterpretationScope* keyScope = __fnI12n->getScope(keyS.scope); + if (!keyScope->isBindingDefined(keyS.identifier)) { + guardsToExpand.push_back(keyS); + } + } + } + + typedef std::function < llvm::Value * () > Compiler; + Compiler programInit([handler, annotation, this]() { + std::list&& values = findKeys(annotation.guardKeys); + auto answer = annotation.select(values, __context.pass->man->root, __context.pass->man->transcend); + assert(answer); + return handler(*answer); + }); + + Compiler aggregate = std::accumulate(guardsToExpand.begin(), guardsToExpand.end(), + programInit, + [this, root, transcend, &resultT, hint](Compiler program, const Symbol & key) { + const ExpandedType& keyT = root->getType(CodeScope::getDefinition(key)); + const ExpandedType& keyTPlain = keyT->__operator == TypeOperator::SLAVE? + interpretation::dereferenceSlaveType(keyT, transcend) + : keyT; + + return Compiler([this, key, keyTPlain, resultT, hint, program](){ + llvm::Value * keyRaw = __context.scope->processSymbol(key); + return compileExpand(key, keyRaw, keyTPlain, resultT, hint, program); + }); + } + ); + + return aggregate(); +} + +llvm::Value* +LateReasoningCompiler::compileExpand(const Symbol& keyS, + llvm::Value* keyRaw, + const ExpandedType& domainT, + llvm::Type* resultT, + const std::string& hint, + CompilerHandler compilerBody) { + + assert(domainT->__operator == TypeOperator::VARIANT); + std::list domInstancesList = generateAllInstancesInDomain2(domainT); + std::vector domInstances(domInstancesList.begin(), domInstancesList.end()); + const int countInstances = domInstances.size(); + assert(countInstances); + TranscendLayer* transcend = __context.pass->man->transcend; + SymbolPacked keyP = transcend->pack(keyS); + + LLVMLayer* llvm = __context.pass->man->llvm; + llvm::IRBuilder<>& builder = llvm->builder; + compilation::IFunctionUnit* function = __context.function; + llvm::Type* typI8 = llvm::Type::getInt8Ty(llvm->llvmContext); + + llvm::Value* keyVariantRaw = builder.CreateExtractValue(keyRaw, llvm::ArrayRef({0})); + llvm::SwitchInst* instructionSwitch = builder.CreateSwitch(keyVariantRaw, nullptr, countInstances); + + llvm::BasicBlock *blockEpilog = llvm::BasicBlock::Create( + llvm->llvmContext, "epilog", function->raw); + + builder.SetInsertPoint(blockEpilog); + llvm::PHINode *ret = builder.CreatePHI(resultT, countInstances, HINT("reverse")); + llvm::BasicBlock* blockDefault = nullptr; + + for (int instanceId = 0; instanceId < countInstances; ++instanceId) { + llvm::BasicBlock *blockCase = llvm::BasicBlock::Create( + llvm->llvmContext, + "case" + std::to_string(instanceId), + function->raw); + if(instanceId == 0) blockDefault = blockCase; + builder.SetInsertPoint(blockCase); + + //assign guard values + const Expression& instanceE = domInstances.at(instanceId); + __dictGuardDefinitions[keyP] = instanceE; + +// __fnI12n->getScope(keyS.scope)->overrideBindings({ +// {instanceE, keyS.identifier} +// }); + + //invoke further compilation handler + llvm::Value* resultCase = compilerBody(); + + ret->addIncoming(resultCase, builder.GetInsertBlock()); + instructionSwitch->addCase(llvm::dyn_cast(llvm::ConstantInt::get(typI8, instanceId)), blockCase); + builder.CreateBr(blockEpilog); + } + + //erase guard assignment + __dictGuardDefinitions.erase(keyP); + + instructionSwitch->setDefaultDest(blockDefault); + builder.SetInsertPoint(blockEpilog); + return ret; +} + +std::list +LateReasoningCompiler::findKeys(const std::list& keys) { + TranscendLayer* transcend = __context.pass->man->transcend; + std::list result; + InterpretationScope* scopeI12n = __fnI12n->getScope(__context.scope->scope); + + std::transform(keys.begin(), keys.end(), std::inserter(result, result.end()), + [this, scopeI12n, transcend](const SymbolPacked & key) { + if (__dictGuardDefinitions.count(key)){ + return __dictGuardDefinitions.at(key); + } + return scopeI12n->processSymbol(transcend->unpack(key)); + }); + + return result; +} +} +} diff --git a/cpp/src/compilation/latereasoning.h b/cpp/src/compilation/latereasoning.h new file mode 100644 index 0000000..7dc6d59 --- /dev/null +++ b/cpp/src/compilation/latereasoning.h @@ -0,0 +1,72 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * File: latereasoning.h + * Author: pgess + * + * Created on May 26, 2018, 3:44 PM + */ + +#ifndef CMPLLATEREASONING_H +#define CMPLLATEREASONING_H + +#include "ast.h" +#include "aux/latereasoning.h" +#include "pass/compilepass.h" +#include "llvmlayer.h" +#include "transcendlayer.h" +#include "targets.h" + +namespace xreate{ +namespace interpretation{ +class InterpretationFunction; +} +} + +namespace llvm{ +class Value; +} + +namespace xreate{ +namespace latereasoning{ + +typedef std::function CompilerHandler; +typedef std::function Handler; + +class LateReasoningCompiler{ +public: + + LateReasoningCompiler(interpretation::InterpretationFunction* fn, + compilation::Context ctx) + : __context(ctx), __fnI12n(fn){ } + + llvm::Value* processSwitchLateStatement(const Expression& expr, + const std::string& identHint); + llvm::Value* compileAutoExpand(const LateAnnotation& annotation, + llvm::Type* resultT, + const std::string& hint, + Handler handler); + +private: + compilation::Context __context; + interpretation::InterpretationFunction* __fnI12n; + static std::map __dictGuardDefinitions; + + llvm::Value* compileExpand(const Symbol& keyS, + llvm::Value* keyRaw, + const ExpandedType& domainT, + llvm::Type* resultT, + const std::string& hint, + CompilerHandler compilerBody); + + std::list findKeys(const std::list& keys); + +}; + +} +} + +#endif /* CMPLLATEREASONING_H */ + diff --git a/cpp/src/compilation/latex.cpp b/cpp/src/compilation/latex.cpp new file mode 100644 index 0000000..b853fd8 --- /dev/null +++ b/cpp/src/compilation/latex.cpp @@ -0,0 +1,36 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +/* + * Author: pgess + * Created on June 23, 2018, 4:33 PM + * + * \file latex.cpp + * \brief latex + */ + +#include "compilation/latex.h" +#include "analysis/interpretation.h" +#include "llvmlayer.h" + +namespace xreate{ +namespace latex{ + +ExpandedType +getSubjectDomain(const std::string& subject, LatexQuery* query){ + std::list&& column = query->getSubjectDomain(subject); + return ExpandedType(interpretation::collapseColumn(column)); +} + +llvm::Value* +ExtraArgsFnInvocation::operator() (std::vector&& args, const std::string& hintDecl) { + args.insert(args.end(), __argsLatex.begin(), __argsLatex.end()); + + return __parent->operator ()(std::move(args), hintDecl); +} + +} +} \ No newline at end of file diff --git a/cpp/src/compilation/latex.h b/cpp/src/compilation/latex.h new file mode 100644 index 0000000..339b82e --- /dev/null +++ b/cpp/src/compilation/latex.h @@ -0,0 +1,140 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +/* + * Author: pgess + * Created on June 23, 2018, 2:51 PM + * + * \file latex.h + * \brief latex + */ + +#ifndef LATEX_H +#define LATEX_H + +#include "compilation/latereasoning.h" +#include "compilation/interpretation-instructions.h" +#include "query/latex.h" +#include "pass/compilepass.h" +#include "analysis/interpretation.h" +#include "compilation/targetinterpretation.h" + +namespace xreate{ +namespace latex{ + +ExpandedType +getSubjectDomain(const std::string& subject, LatexQuery* query); + +/** \brief Latex(Late Context)-enabled decorator for IFunctionUnit + * \extends IFunctionUnit + */ +template +class LatexBruteFunctionDecorator: public Parent{ +public: + + LatexBruteFunctionDecorator(ManagedFnPtr f, CompilePass* p) + : Parent(f, p){ + __query = reinterpret_cast (Parent::pass->man->transcend->getQuery(QueryId::LatexQuery)); + } + +protected: + + std::vector + prepareSignature(){ + std::vector&& signature = Parent::prepareSignature(); + + const Demand& demand = __query->getFnDemand(Parent::function->getName()); + signature.reserve(signature.size() + demand.size()); + + int subjectId = __query->LatexParametersOffset; + for(const std::string& subject: demand){ + const ExpandedType& subjectT = getSubjectDomain(subject, __query); + Expression bindingE; + bindingE.type = subjectT; + std::string argCaption = std::string("latex_") + subject; + Parent::function->addBinding( + Atom(std::string(argCaption)), + std::move(bindingE), + subjectId++); + + llvm::Type* subjectTRaw = Parent::pass->man->llvm->toLLVMType(subjectT); + signature.push_back(subjectTRaw); + } + + return signature; + } + +public: + LatexQuery* __query; +}; + +class ExtraArgsFnInvocation: public compilation::IFnInvocation{ +public: + + ExtraArgsFnInvocation(std::vector argsLatex, compilation::IFnInvocation* parent) + : __argsLatex(argsLatex), __parent(parent){ } + + llvm::Value* operator()(std::vector&& args, const std::string& hintDecl = ""); + +private: + std::vector __argsLatex; + compilation::IFnInvocation* __parent; +}; + +template +class LatexBruteScopeDecorator: public Parent{ +public: + + LatexBruteScopeDecorator(const CodeScope * const codeScope, compilation::IFunctionUnit* f, CompilePass* compilePass) + : Parent(codeScope, f, compilePass){ } + + compilation::IFnInvocation* + findFunction(const Expression& opCall){ + compilation::IFnInvocation* invocDefault = Parent::findFunction(opCall); + const std::string& calleeName = opCall.getValueString(); + LatexQuery* query = reinterpret_cast (Parent::pass->man->transcend->getQuery(QueryId::LatexQuery)); + + const Demand& fnCalleeDemand = query->getFnDemand(calleeName); + if(!fnCalleeDemand.size()) return invocDefault; + + //prepare latex arguments + std::vector argsLatex; + argsLatex.reserve(fnCalleeDemand.size()); + + for(const std::string& subject: fnCalleeDemand){ + ExpandedType subjectT = getSubjectDomain(subject, query); + llvm::Type* subjectTRaw = Parent::pass->man->llvm->toLLVMType(subjectT); + const latereasoning::LateAnnotation& decision = query->getDecision(subject, Parent::scope); + + compilation::Context ctx{this, Parent::function, Parent::pass}; + interpretation::InterpretationScope* scopeIntrpr = + Parent::pass->targetInterpretation->transformContext(ctx); + latereasoning::LateReasoningCompiler* compiler + = new latereasoning::LateReasoningCompiler(dynamic_cast(scopeIntrpr->function), ctx); + + llvm::Value* subjectRaw = compiler->compileAutoExpand( + decision, + subjectTRaw, + subject, + [&](const Gringo::Symbol & decisionRaw){ + const Expression& decisionE = interpretation::representTransExpression( + decisionRaw.args()[2], subjectT, Parent::pass->man->transcend); + Attachments::put(decisionE, subjectT); + return Parent::process(decisionE, subject); + }); + + argsLatex.push_back(subjectRaw); + } + + return new ExtraArgsFnInvocation(std::move(argsLatex), invocDefault); + } +}; + +} +} //end of namespace xreate::context + +#endif /* LATEX_H */ + diff --git a/cpp/src/compilation/operators.cpp b/cpp/src/compilation/operators.cpp new file mode 100644 index 0000000..2c93079 --- /dev/null +++ b/cpp/src/compilation/operators.cpp @@ -0,0 +1,75 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * operators.cpp + * + * Author: pgess + * Created on April 8, 2017, 1:35 PM + */ + +/** + * \file operators.h + * \brief Helpers to compile various operators + */ + +#include "operators.h" +#include "llvmlayer.h" +#include "ExternLayer.h" +#include + +using namespace llvm; +using namespace std; + +namespace xreate { + +namespace pointerarithmetic { +llvm::Value* +PointerArithmetic::add(llvm::Value *left, llvm::Value *right, compilation::Context context, const std::string& hintVarDecl){ + LLVMLayer* llvm = context.pass->man->llvm; + + if (left->getType()->isPointerTy() && right->getType()->isIntegerTy()){ + + std::vector indexes{right}; + //{llvm::ConstantInt::get(llvm::Type::getInt32Ty(llvm::getGlobalContext()), 0)}; + //indexes.push_back(right); + + return llvm->builder.CreateGEP(left, llvm::ArrayRef(indexes), hintVarDecl); + } + + return nullptr; +} +}//end of pointgerarithmetic namespace + +llvm::Value* +StructUpdate::add(const Expression& left, llvm::Value *leftRaw, const Expression& right, compilation::Context context, const std::string& hintVarDecl){\ + if (!(right.__state == Expression::COMPOUND && right.op == Operator::LIST_NAMED)){ + return nullptr; + } + + PassManager* man = context.pass->man; + + ExpandedType tyOperandLeft = man->root->getType(left); + + const std::vector fieldsFormal = (tyOperandLeft.get().__operator == TypeOperator::CUSTOM)? + man->llvm->layerExtern->getStructFields(man->llvm->layerExtern->lookupType(tyOperandLeft.get().__valueCustom)) + : tyOperandLeft.get().fields; + + std::map indexFields; + for(size_t i=0, size = fieldsFormal.size(); iprocess(value, right.bindings.at(i)); + unsigned int fieldId = indexFields.at(right.bindings.at(i)); + + result = man->llvm->builder.CreateInsertValue(result, valueRaw, llvm::ArrayRef({fieldId})); + } + + return result; +} + +} //end of xreate namespace diff --git a/cpp/src/compilation/operators.h b/cpp/src/compilation/operators.h new file mode 100644 index 0000000..d465944 --- /dev/null +++ b/cpp/src/compilation/operators.h @@ -0,0 +1,36 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * File: operators.h + * Author: pgess + * + * Created on April 8, 2017, 1:33 PM + */ + +#ifndef OPERATORS_H +#define OPERATORS_H + +#include "pass/compilepass.h" + +namespace llvm { + class Value; +} + +namespace xreate { + +namespace pointerarithmetic { + class PointerArithmetic { + public: + static llvm::Value* add(llvm::Value *left, llvm::Value *right, compilation::Context context, const std::string& hintVarDecl); + }; +} //end of pointerarithmetic namespace + +class StructUpdate { +public: + static llvm::Value* add(const Expression& left, llvm::Value *leftRaw, const Expression& right, compilation::Context context, const std::string& hintVarDecl); +}; +} //namespace xreate + +#endif /* OPERATORS_H */ + diff --git a/cpp/src/compilation/polymorph.cpp b/cpp/src/compilation/polymorph.cpp new file mode 100644 index 0000000..5d07277 --- /dev/null +++ b/cpp/src/compilation/polymorph.cpp @@ -0,0 +1,53 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +/* + * Author: pgess + * Created on July 9, 2018, 6:04 PM + * + * \file polymorph.cpp + * \brief polymorph + */ + +#include "compilation/polymorph.h" +using namespace std; + +namespace xreate{ +namespace polymorph{ + +PolymorphFnInvocation::PolymorphFnInvocation(const latereasoning::LateAnnotation& selector, + std::list calleeSpecializations, + CompilePass* pass, + PolymorphQuery* query, + LLVMLayer* llvm, + latereasoning::LateReasoningCompiler* compiler) +: __selector(selector), __calleeSpecializations(calleeSpecializations), +__pass(pass), __query(query), __llvm(llvm), __compiler(compiler) { } + +llvm::Value* +PolymorphFnInvocation::operator()(std::vector&& args, const std::string& hintDecl) { + std::map dictSelectors; + for(ManagedFnPtr specialization : __calleeSpecializations) { + dictSelectors.emplace(specialization->guard, specialization); + } + + compilation::IFunctionUnit* specAny = __pass->getFunctionUnit(__calleeSpecializations.front()); + return __compiler->compileAutoExpand( + __selector, + specAny->prepareResult(), + hintDecl, + [this, &args, hintDecl, &dictSelectors](const Gringo::Symbol & selectorRaw) { + const Expression & selectorE = __query->getValue(selectorRaw); + assert(dictSelectors.count(selectorE) && "Inappropriate specialization guard"); + compilation::BruteFnInvocation* invoc = new compilation::BruteFnInvocation( + __pass->getFunctionUnit(dictSelectors.at(selectorE))->compile(), + __llvm); + + return invoc->operator()(move(args), hintDecl); + }); +} +} +} diff --git a/cpp/src/compilation/polymorph.h b/cpp/src/compilation/polymorph.h new file mode 100644 index 0000000..def1bc1 --- /dev/null +++ b/cpp/src/compilation/polymorph.h @@ -0,0 +1,96 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * File: polymorphcompiler.h + * Author: pgess + * + * Created on October 7, 2017 + */ + +#ifndef POLYMORPHCOMPILER_H +#define POLYMORPHCOMPILER_H + +#include "pass/compilepass.h" +#include "query/polymorph.h" +#include "compilation/latereasoning.h" +#include "compilation/targetinterpretation.h" + +namespace xreate{ +namespace polymorph{ + +typedef Expression Selector; + +class PolymorphFnInvocation: public compilation::IFnInvocation{ +public: + PolymorphFnInvocation(const latereasoning::LateAnnotation& selector, + std::list calleeSpecializations, + CompilePass* pass, + PolymorphQuery* query, + LLVMLayer* llvm, + latereasoning::LateReasoningCompiler* compiler); + + llvm::Value* operator()(std::vector&& args, const std::string& hintDecl = ""); + +private: + latereasoning::LateAnnotation __selector; + std::list __calleeSpecializations; + + CompilePass* __pass; + PolymorphQuery* __query; + LLVMLayer* __llvm; + latereasoning::LateReasoningCompiler* __compiler; +}; + +template +class PolymorphCodeScopeUnit: public Parent{ +public: + + PolymorphCodeScopeUnit(const CodeScope * const codeScope, + compilation::IFunctionUnit* f, + CompilePass* compilePass) + : Parent(codeScope, f, compilePass){ } + +protected: + + compilation::IFnInvocation* + findFunction(const Expression& opCall) override{ +// //Check does invocation require guards satisfaction + const std::string& nameCallee = opCall.getValueString(); + const std::list& specializations = + Parent::pass->man->root->getFunctionSpecializations(nameCallee); + + //Extern function + if(specializations.size() == 0){ + return Parent::findFunction(opCall); + } + + //No other specializations. Check if it has no guard + if(specializations.size() == 1){ + if(!specializations.front()->guard.isValid()){ + return Parent::findFunction(opCall); + } + } + + //Several specializations + PolymorphQuery* query = dynamic_cast ( + Parent::pass->man->transcend->getQuery(QueryId::PolymorphQuery)); + const latereasoning::LateAnnotation& selector = query->get(opCall); + + compilation::Context ctx{this, Parent::function, Parent::pass}; + interpretation::InterpretationScope* scopeIntrpr = + Parent::pass->targetInterpretation->transformContext(ctx); + latereasoning::LateReasoningCompiler* compiler + = new latereasoning::LateReasoningCompiler(dynamic_cast(scopeIntrpr->function), ctx); + + return new PolymorphFnInvocation(selector, specializations, Parent::pass, + query, Parent::pass->man->llvm, compiler); + } +}; + +} +} //end of xreate::polymorph + +#endif /* POLYMORPHCOMPILER_H */ + diff --git a/cpp/src/compilation/scopedecorators.h b/cpp/src/compilation/scopedecorators.h new file mode 100644 index 0000000..cf26986 --- /dev/null +++ b/cpp/src/compilation/scopedecorators.h @@ -0,0 +1,183 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * File: scopedecorators.h + * Author: pgess + * + * Created on February 24, 2017, 11:35 AM + */ + +/** + * \file scopedecorators.h + * \brief Basic code block compilation xreate::compilation::ICodeScopeUnit decorators + */ + + +#ifndef SCOPEDECORATORS_H +#define SCOPEDECORATORS_H + +#include "ast.h" +#include "compilation/targetinterpretation.h" +#include "compilation/versions.h" +#include "compilation/transformations.h" +#include "compilation/polymorph.h" +#include "compilation/latex.h" +#include "analysis/typeinference.h" +#include + +namespace xreate { + +class CompilePass; + +namespace compilation { + +class ICodeScopeUnit; +class IFunctionUnit; + +/**\brief Caching ability for code scope compilation + * \extends xreate::compilation::ICodeScopeUnit + */ +template +class CachedScopeDecorator: public Parent{ + typedef CachedScopeDecorator SELF; + +public: + CachedScopeDecorator(const CodeScope* const codeScope, IFunctionUnit* f, CompilePass* compilePass): Parent(codeScope, f, compilePass){} + + Symbol bindArg(llvm::Value* value, std::string&& alias) + { + //ensure existence of an alias + assert(Parent::scope->__identifiers.count(alias)); + + //memorize new value for an alias + ScopedSymbol id{Parent::scope->__identifiers.at(alias), versions::VERSION_NONE}; + __rawVars[id] = value; + + return Symbol{id, Parent::scope}; + } + + void bindArg(llvm::Value* value, const ScopedSymbol& s) { + __rawVars[s] = value; + } + + llvm::Value* compile(const std::string& hintBlockDecl="") override{ + if (__rawVars.count(ScopedSymbol::RetSymbol)){ + return __rawVars[ScopedSymbol::RetSymbol]; + } + + return Parent::compile(hintBlockDecl); + } + + llvm::Value* + processSymbol(const Symbol& s, std::string hintRetVar) override{ + const CodeScope* scope = s.scope; + SELF* self = dynamic_cast(Parent::function->getScopeUnit(scope)); + + if (self->__rawVars.count(s.identifier)){ + return self->__rawVars[s.identifier]; + } + + //Declaration could be overriden + /* + Expression declaration = CodeScope::getDefinition(s, true); + if (!declaration.isDefined()){ + assert(__declarationsOverriden.count(s.identifier)); + declaration = __declarationsOverriden[s.identifier]; + + } else { + (false); //in case of binding there should be raws provided. + } + } + */ + + llvm::Value* resultRaw = Parent::processSymbol(s, hintRetVar); + self->__rawVars.emplace(s.identifier, resultRaw); + return resultRaw; + } + + void + overrideDeclarations(std::list> bindings){ + reset(); + + for (auto entry: bindings){ + SELF* self = dynamic_cast(Parent::function->getScopeUnit(entry.first.scope)); + assert(self == this); + + self->__declarationsOverriden.emplace(entry.first.identifier, entry.second); + } + } + + void registerChildScope(std::shared_ptr scope){ + __childScopes.push_back(scope); + } + + void reset(){ + __rawVars.clear(); + __declarationsOverriden.clear(); + __childScopes.clear(); + } + +private: + std::unordered_map __declarationsOverriden; + std::unordered_map __rawVars; + std::list> __childScopes; +}; + +template +class TypeConversionScopeDecorator: public Parent { +public: + TypeConversionScopeDecorator(const CodeScope* const codeScope, IFunctionUnit* f, CompilePass* compilePass): Parent(codeScope, f, compilePass){} + + llvm::Value* process(const Expression& expr, const std::string& hintVarDecl="") override { + llvm::Value* resultR = Parent::process(expr, hintVarDecl); + + if(!expr.type.isValid()) { + return resultR; + } + + ExpandedType exprT = Parent::pass->man->root->getType(expr); + llvm::Type* exprTR = Parent::pass->man->llvm->toLLVMType(exprT); + return typeinference::doAutomaticTypeConversion(resultR, exprTR, Parent::pass->man->llvm->builder); + } +}; + +/**\brief Default code scope compilation functionality*/ +typedef CachedScopeDecorator< + TypeConversionScopeDecorator< + latex::LatexBruteScopeDecorator< + polymorph::PolymorphCodeScopeUnit< + compilation::TransformationsScopeDecorator< + interpretation::InterpretationScopeDecorator< + versions::VersionsScopeDecorator>>>>>> + + DefaultCodeScopeUnit; + +} //end of compilation namespace + +struct CachedScopeDecoratorTag; +struct VersionsScopeDecoratorTag; + +template<> +struct DecoratorsDict{ + typedef compilation::CachedScopeDecorator< + compilation::TypeConversionScopeDecorator< + latex::LatexBruteScopeDecorator< + polymorph::PolymorphCodeScopeUnit< + compilation::TransformationsScopeDecorator< + interpretation::InterpretationScopeDecorator< + versions::VersionsScopeDecorator>>>>>> + + result; +}; + +template<> +struct DecoratorsDict{ + typedef versions::VersionsScopeDecorator< + compilation::BasicCodeScopeUnit> result; +}; + +} //end of xreate + +#endif /* SCOPEDECORATORS_H */ + diff --git a/cpp/src/compilation/targetinterpretation.cpp b/cpp/src/compilation/targetinterpretation.cpp index b50bf13..17457db 100644 --- a/cpp/src/compilation/targetinterpretation.cpp +++ b/cpp/src/compilation/targetinterpretation.cpp @@ -1,446 +1,628 @@ -/* +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * * File: targetinterpretation.cpp - * Author: pgess + * Author: pgess * * Created on June 29, 2016, 6:45 PM */ +/** + * \file targetinterpretation.h + * \brief Interpretation support. See more [details on Interpretation](/w/concepts/dsl/) + */ + #include "compilation/targetinterpretation.h" #include "pass/interpretationpass.h" +#include "analysis/typeinference.h" #include "llvmlayer.h" +#include "compilation/scopedecorators.h" +#include "compilation/interpretation-instructions.h" + #include #include +#include using namespace std; +using namespace xreate::compilation; -namespace xreate{ namespace compilation { - - const Expression EXPRESSION_FALSE = Expression(Atom(0)); - const Expression EXPRESSION_TRUE = Expression(Atom(1)); +namespace xreate{ +namespace interpretation{ -//Expression -//InterpretationScope::compile(const Expression& expression){} +const Expression EXPRESSION_FALSE = Expression(Atom(0)); +const Expression EXPRESSION_TRUE = Expression(Atom(1)); CodeScope* -InterpretationScope::processOperatorIf(const Expression& expression){ +InterpretationScope::processOperatorIf(const Expression& expression) { const Expression& exprCondition = process(expression.getOperands()[0]); - if (exprCondition == EXPRESSION_TRUE){ + if (exprCondition == EXPRESSION_TRUE) { return expression.blocks.front(); } return expression.blocks.back(); } CodeScope* InterpretationScope::processOperatorSwitch(const Expression& expression) { const Expression& exprCondition = process(expression.operands[0]); bool flagHasDefault = expression.operands[1].op == Operator::CASE_DEFAULT; //TODO check that one and only one case variant is appropriate - for (size_t size = expression.operands.size(), i= flagHasDefault? 2: 1; igetScope(exprCase.blocks.front())->processScope() == exprCondition){ + if (function->getScope((const CodeScope*) exprCase.blocks.front())->processScope() == exprCondition) { return exprCase.blocks.back(); } } - if (flagHasDefault){ + if (flagHasDefault) { const Expression& exprCaseDefault = expression.operands[1]; return exprCaseDefault.blocks.front(); } assert(false && "Switch has no appropriate variant"); return nullptr; } +CodeScope* +InterpretationScope::processOperatorSwitchVariant(const Expression& expression) { + const Expression& condition = process(expression.operands.at(0)); + assert(condition.op == Operator::VARIANT); + const string& identCondition = expression.bindings.front(); + + Expression opExpected(Atom(condition.getValueDouble())); + auto itFoundValue = std::find(++expression.operands.begin(), expression.operands.end(), opExpected); + assert(itFoundValue != expression.operands.end()); + + int indexBlock = itFoundValue - expression.operands.begin() - 1; + auto blockFound = expression.blocks.begin(); + std::advance(blockFound, indexBlock); + + InterpretationScope* scopeI12n = function->getScope(*blockFound); + + if(condition.operands.size()) { + const Expression& value = condition.operands.at(0); + scopeI12n->overrideBindings({ + {value, identCondition} + }); + } + + return *blockFound; +} + llvm::Value* -InterpretationScope::compileHybrid(const InterpretationOperator& op, const Expression& expression, const Context& context){ - switch(op){ - case IF_INTERPRET_CONDITION: { - CodeScope* scopeResult = processOperatorIf(expression); +InterpretationScope::processLate(const InterpretationOperator& op, const Expression& expression, const Context& context) { + switch(op) { + case IF_INTERPRET_CONDITION: + { + CodeScope* scopeResult = processOperatorIf(expression); + + llvm::Value* result = context.function->getScopeUnit(scopeResult)->compile(); + return result; + } - llvm::Value* result = context.function->getScopeUnit(scopeResult)->compile(); - return result; - } + case SWITCH_INTERPRET_CONDITION: + { + CodeScope* scopeResult = processOperatorSwitch(expression); - case SWITCH_INTERPRET_CONDITION:{ - CodeScope* scopeResult = processOperatorSwitch(expression); + llvm::Value* result = context.function->getScopeUnit(scopeResult)->compile(); + return result; + } - llvm::Value* result = context.function->getScopeUnit(scopeResult)->compile(); - return result; + case SWITCH_VARIANT: + { + CodeScope* scopeResult = processOperatorSwitchVariant(expression); + const Expression& condition = expression.operands.at(0); + const Expression& valueCondition = process(condition); + + const string identCondition = expression.bindings.front(); + auto scopeCompilation = Decorators::getInterface(context.function->getScopeUnit(scopeResult)); + + if(valueCondition.operands.size()) { + //override value + Symbol symbCondition{ScopedSymbol{scopeResult->__identifiers.at(identCondition), versions::VERSION_NONE}, scopeResult}; + scopeCompilation->overrideDeclarations({ + {symbCondition, Expression(valueCondition.operands.at(0))}} + ); + + //set correct type for binding: + TypeAnnotation typeVariant = typeinference::getType(condition, *function->man->ast); + int conditionIndex = valueCondition.getValueDouble(); + ScopedSymbol symbolInternal = scopeResult->getSymbol(identCondition); + scopeResult->__declarations[symbolInternal].bindType(typeVariant.__operands.at(conditionIndex)); } - case FOLD_INTERPRET_INPUT: { - //initialization - const Expression& exprInput = process(expression.getOperands()[0]); - assert(exprInput.op == Operator::LIST); + llvm::Value* result = context.function->getScopeUnit(scopeResult)->compile(); + return result; + } - CodeScope* scopeBody = expression.blocks.front(); + case SWITCH_LATE: + { + latereasoning::LateReasoningCompiler compiler(dynamic_cast(this->function), context); + return compiler.processSwitchLateStatement(expression, ""); + } - const string& nameEl = expression.bindings[0]; - const Symbol& symbolEl = scopeBody->findSymbol(nameEl); - const std::string& idAccum = expression.bindings[1]; - llvm::Value* rawAccum = context.scope->process(expression.getOperands()[1]); - compilation::CodeScopeUnit* unitBody = context.function->getScopeUnit(scopeBody); - InterpretationScope* intrBody = function->getScope(scopeBody); - const std::vector elementsInput= exprInput.getOperands(); + case FOLD_INTERPRET_INPUT: + { + //initialization + const Expression& exprInput = process(expression.getOperands()[0]); + assert(exprInput.op == Operator::LIST); - for (size_t i=0; ireset(); + const string& nameEl = expression.bindings[0]; + Symbol symbEl{ScopedSymbol{scopeBody->__identifiers.at(nameEl), versions::VERSION_NONE}, scopeBody}; + const std::string& idAccum = expression.bindings[1]; + llvm::Value* rawAccum = context.scope->process(expression.getOperands()[1]); - intrBody->overrideBinding(exprElement, nameEl); - unitBody->overrideDeclaration(symbolEl, move(exprElement)); - unitBody->bindArg(rawAccum, string(idAccum)); + InterpretationScope* intrBody = function->getScope(scopeBody); + auto unitBody = Decorators::getInterface(context.function->getScopeUnit(scopeBody)); - rawAccum = unitBody->compile(); - } + const std::vector elementsInput = exprInput.getOperands(); - return rawAccum; - } + for(size_t i = 0; i < elementsInput.size(); ++i) { + const Expression& exprElement = elementsInput[i]; - case CALL_INTERPRET_PARTIAL: { - const std::string &calleeName = expression.getValueString(); - CodeScopeUnit* scopeUnitSelf = context.scope; - ManagedFnPtr callee = this->function->man->ast->findFunction(calleeName); - const FunctionInterpretationData& calleeData = FunctionInterpretationHelper::getSignature(callee); - std::vector argsActual; - PIFSignature sig; - sig.declaration = callee; + intrBody->overrideBindings({ + {exprElement, nameEl} + }); + unitBody->overrideDeclarations({ + {symbEl, exprElement} + }); //resets unitBody + unitBody->bindArg(rawAccum, string(idAccum)); - for(size_t no=0, size = expression.operands.size(); no < size; ++no){ - const Expression& op = expression.operands[no]; + rawAccum = unitBody->compile(); + } - if (calleeData.signature.at(no) == INTR_ONLY){ - sig.bindings.push_back(process(op)); - continue; - } + return rawAccum; + } - argsActual.push_back(scopeUnitSelf->process(op)); +// case FOLD_INF_INTERPRET_INOUT: +// { +// } + + //TODO refactor as InterpretationCallStatement class + case CALL_INTERPRET_PARTIAL: + { + const std::string &calleeName = expression.getValueString(); + ICodeScopeUnit* scopeUnitSelf = context.scope; + ManagedFnPtr callee = this->function->man->ast->findFunction(calleeName); + const FunctionInterpretationData& calleeData = FunctionInterpretationHelper::getSignature(callee); + std::vector argsActual; + PIFSignature sig; + sig.declaration = callee; + + for(size_t no = 0, size = expression.operands.size(); no < size; ++no) { + const Expression& op = expression.operands[no]; + + if (calleeData.signature.at(no) == INTR_ONLY) { + sig.bindings.push_back(process(op)); + continue; } - TargetInterpretation* man = dynamic_cast(this->function->man); - PIFunction* pifunction = man->getFunction(move(sig)); - - llvm::Function* raw = pifunction->compile(); - boost::scoped_ptr statement(new CallStatementRaw(raw, man->pass->man->llvm)); - return (*statement)(move(argsActual)); + argsActual.push_back(scopeUnitSelf->process(op)); } - default: break; + TargetInterpretation* man = dynamic_cast (this->function->man); + PIFunction* pifunction = man->getFunction(move(sig)); + + llvm::Function* raw = pifunction->compile(); + boost::scoped_ptr statement(new BruteFnInvocation(raw, man->pass->man->llvm)); + return (*statement)(move(argsActual)); + } + + case QUERY_LATE: + { + return IntrinsicQueryInstruction( + dynamic_cast(this->function)) + .processLate(expression, context); } - assert(false&& "Unknown hybrid operator"); + default: break; + } + + assert(false && "Unknown late interpretation operator"); return nullptr; } llvm::Value* -InterpretationScope::compile(const Expression& expression, const Context& context){ - const InterpretationData& data = Attachments::get(expression); +InterpretationScope::compile(const Expression& expression, const Context& context) { + const InterpretationData& data = Attachments::get(expression); - if (data.op != InterpretationOperator::NONE){ - return compileHybrid(data.op, expression, context); + if (data.op != InterpretationOperator::NONE) { + return processLate(data.op, expression, context); } Expression result = process(expression); - return context.scope->processLowlevel(result); + return context.scope->process(result); } Expression -InterpretationScope::process(const Expression& expression){ - switch (expression.__state){ - case Expression::VARIANT: - case Expression::INVALID: - assert(false); +InterpretationScope::process(const Expression& expression) { +#ifndef NDEBUG + if (expression.tags.count("bpoint")) { + std::raise(SIGINT); + } +#endif - case Expression::NUMBER: - case Expression::STRING: - return expression; + PassManager* man = (static_cast (function->man))->pass->man; - case Expression::IDENT:{ - const std::string &ident = expression.getValueString(); + switch (expression.__state) { + case Expression::INVALID: + assert(false); - Symbol s = scope->findSymbol(ident); - return Parent::processSymbol(s); - } + case Expression::NUMBER: + case Expression::STRING: + return expression; + + case Expression::IDENT: + { + Symbol s = Attachments::get(expression); + return Parent::processSymbol(s); + } - case Expression::COMPOUND: - break; + case Expression::COMPOUND: + break; - default: assert(false); + default: assert(false); } switch (expression.op) { - case Operator::EQU: { - const Expression& left = process(expression.operands[0]); - const Expression& right = process(expression.operands[1]); + case Operator::EQU: + { + const Expression& left = process(expression.operands[0]); + const Expression& right = process(expression.operands[1]); - if (left == right) return EXPRESSION_TRUE; - return EXPRESSION_FALSE; - } + if (left == right) return EXPRESSION_TRUE; + return EXPRESSION_FALSE; + } - case Operator::NE: { - const Expression& left = process(expression.operands[0]); - const Expression& right = process(expression.operands[1]); + case Operator::NE: + { + const Expression& left = process(expression.operands[0]); + const Expression& right = process(expression.operands[1]); - if (left == right) return EXPRESSION_FALSE; - return EXPRESSION_TRUE; - } + if (left == right) return EXPRESSION_FALSE; + return EXPRESSION_TRUE; + } - case Operator::LOGIC_AND: { - assert(expression.operands.size() == 1); - return process (expression.operands[0]); + case Operator::LOGIC_AND: + { + assert(expression.operands.size() == 1); + return process (expression.operands[0]); + } + + + // case Operator::LOGIC_OR: + case Operator::CALL: + { + const std::string &fnName = expression.getValueString(); + ManagedFnPtr fnAst = this->function->man->ast->findFunction(fnName); + InterpretationFunction* fnUnit = this->function->man->getFunction(fnAst); + + vector args; + args.reserve(expression.getOperands().size()); + + for(size_t i = 0, size = expression.getOperands().size(); i < size; ++i) { + args.push_back(process(expression.getOperands()[i])); } + return fnUnit->process(args); + } -// case Operator::LOGIC_OR: - case Operator::CALL: { - const std::string &fnName = expression.getValueString(); - ManagedFnPtr fnAst = this->function->man->ast->findFunction(fnName); - InterpretationFunction* fnUnit = this->function->man->getFunction(fnAst); + case Operator::CALL_INTRINSIC: + { + assert(false && "Unknown intrinsic"); + } - vector args; - args.reserve(expression.getOperands().size()); + case Operator::QUERY: + { + return IntrinsicQueryInstruction(dynamic_cast(this->function)) + .process(expression); + } + + case Operator::QUERY_LATE: + { + assert(false && "Can't be interpretated"); + return Expression(); + } - for(size_t i=0, size = expression.getOperands().size(); igetScope(scopeResult)->processScope(); + } - return fnUnit->process(args); - } + case Operator::SWITCH: + { + CodeScope* scopeResult = processOperatorSwitch(expression); + return function->getScope(scopeResult)->processScope(); + } - case Operator::IF:{ - CodeScope* scopeResult = processOperatorIf(expression); - return function->getScope(scopeResult)->processScope(); - } + case Operator::SWITCH_VARIANT: + { + CodeScope* scopeResult = processOperatorSwitchVariant(expression); + return function->getScope(scopeResult)->processScope(); + } - case Operator::SWITCH: { - CodeScope* scopeResult = processOperatorSwitch(expression); - return function->getScope(scopeResult)->processScope(); - } + case Operator::VARIANT: + { + if(!expression.operands.size()) return expression; - case Operator::INDEX: { - const Expression& exprKey = process(expression.operands[0]); - const Expression& exprData = processSymbol(scope->findSymbol(expression.getValueString())); + Expression variantData = process(expression.operands[0]); + Expression result{Operator::VARIANT, {variantData}}; + result.setValueDouble(expression.getValueDouble()); + return result; + } + case Operator::INDEX: + { + Expression exprData = process(expression.operands[0]); - if (exprKey.__state == Expression::STRING){ + for (size_t keyId = 1; keyId < expression.operands.size(); ++keyId) { + const Expression& exprKey = process(expression.operands[keyId]); + + if (exprKey.__state == Expression::STRING) { const string& key = exprKey.getValueString(); assert(exprData.__indexBindings.count(key)); + size_t idxKey = exprData.__indexBindings.at(key); - return exprData.operands[exprData.__indexBindings.at(key)]; + exprData = Expression(exprData.operands.at(idxKey)); + continue; } - if (exprKey.__state == Expression::NUMBER){ + if (exprKey.__state == Expression::NUMBER) { int key = exprKey.getValueDouble(); - return exprData.operands[key]; + exprData = Expression(exprData.operands[key]); + continue; } - assert(false); + assert(false && "Inappropriate key"); } - case Operator::FOLD: { - const Expression& exprInput = process(expression.getOperands()[0]); - const Expression& exprInit = process(expression.getOperands()[1]); + return exprData; + } - const std::string& argEl = expression.bindings[0]; - const std::string& argAccum = expression.bindings[1]; + case Operator::FOLD: + { + const Expression& exprInput = process(expression.getOperands()[0]); + const Expression& exprInit = process(expression.getOperands()[1]); - InterpretationScope* body = function->getScope(expression.blocks.front()); + const std::string& argEl = expression.bindings[0]; + const std::string& argAccum = expression.bindings[1]; - Expression accum = exprInit; - for(size_t size=exprInput.getOperands().size(), i=0; ioverrideBinding(exprInput.getOperands()[i], argEl); - body->overrideBinding(accum, argAccum); + InterpretationScope* body = function->getScope(expression.blocks.front()); - accum = body->processScope(); - } + Expression accum = exprInit; + for(size_t size = exprInput.getOperands().size(), i = 0; i < size; ++i) { + body->overrideBindings({ + {exprInput.getOperands()[i], argEl}, + {accum, argAccum} + }); - return accum; + accum = body->processScope(); } -// case Operator::MAP: { -// break; -// } + return accum; + } - default: break; + case Operator::LIST: + case Operator::LIST_NAMED: + case Operator::LIST_RANGE: + { + Expression result(expression.op,{}); + result.operands.resize(expression.operands.size()); + result.bindings = expression.bindings; + result.__indexBindings = expression.__indexBindings; + + int keyId = 0; + for(const Expression& opCurrent : expression.operands) { + result.operands[keyId++] = process(opCurrent); + } + + return result; + } + + // case Operator::MAP: { + // break; + // } + + default: break; } return expression; } InterpretationFunction* -TargetInterpretation::getFunction(FunctionUnit* unit){ +TargetInterpretation::getFunction(IFunctionUnit* unit) { if (__dictFunctionsByUnit.count(unit)) { return __dictFunctionsByUnit.at(unit); } InterpretationFunction* f = new InterpretationFunction(unit->function, this); __dictFunctionsByUnit.emplace(unit, f); assert(__functions.emplace(unit->function.id(), f).second); return f; } PIFunction* -TargetInterpretation::getFunction(PIFSignature&& sig){ - +TargetInterpretation::getFunction(PIFSignature&& sig) { auto f = __pifunctions.find(sig); - if (f != __pifunctions.end()){ + if (f != __pifunctions.end()) { return f->second; } PIFunction* result = new PIFunction(PIFSignature(sig), __pifunctions.size(), this); __pifunctions.emplace(move(sig), result); assert(__dictFunctionsByUnit.emplace(result->functionUnit, result).second); return result; } InterpretationScope* -TargetInterpretation::transformContext(const Context& c){ +TargetInterpretation::transformContext(const Context& c) { return this->getFunction(c.function)->getScope(c.scope->scope); } llvm::Value* -TargetInterpretation::transform(const Expression& expression, llvm::Value* raw, const Context& ctx){ - return raw; -} - -Expression -TargetInterpretation::transform(const Expression& expression, const Context& ctx){ - return transformContext(ctx)->process(expression); -} - -llvm::Value* -TargetInterpretation::compile(const Expression& expression, const Context& ctx){ +TargetInterpretation::compile(const Expression& expression, const Context& ctx) { return transformContext(ctx)->compile(expression, ctx); } -bool -TargetInterpretation::isAcceptable(const Expression& expression){ - const InterpretationData& data = Attachments::get(expression, {ANY, NONE}); - - return (data.resolution == INTR_ONLY || data.op != InterpretationOperator::NONE); -} - InterpretationFunction::InterpretationFunction(const ManagedFnPtr& function, Target* target) - : Function(function, target) -{} +: Function(function, target) { } Expression -InterpretationFunction::process(const std::vector& args){ +InterpretationFunction::process(const std::vector& args) { InterpretationScope* body = getScope(__function->__entry); - for(size_t i=0, size = args.size(); ioverrideBinding(args.at(i), string(body->scope->__bindings.at(i))); + list> bindings; + for(size_t i = 0, size = args.size(); i < size; ++i) { + bindings.push_back(make_pair(args.at(i), body->scope->__bindings.at(i))); } + body->overrideBindings(bindings); return body->processScope(); } // Partial function interpretation -typedef BasicFunctionDecorator PIFunctionUnitParent; -class PIFunctionUnit: public PIFunctionUnitParent{ +typedef BasicFunctionUnit PIFunctionUnitParent; + +class PIFunctionUnit : public PIFunctionUnitParent{ public: PIFunctionUnit(ManagedFnPtr f, std::set&& arguments, size_t id, CompilePass* p) - : PIFunctionUnitParent(f, p), argumentsActual(move(arguments)), __id(id) - {} + : PIFunctionUnitParent(f, p), argumentsActual(move(arguments)), __id(id) { } protected: - std::vector prepareArguments(){ + + std::vector + prepareSignature() override { LLVMLayer* llvm = PIFunctionUnitParent::pass->man->llvm; AST* ast = PIFunctionUnitParent::pass->man->root; CodeScope* entry = PIFunctionUnitParent::function->__entry; std::vector signature; - for(size_t no: argumentsActual){ - Symbol arg = entry->findSymbol(entry->__bindings[no]); + for(size_t no : argumentsActual) { + VNameId argId = entry->__identifiers.at(entry->__bindings.at(no)); + ScopedSymbol arg{argId, versions::VERSION_NONE}; - signature.push_back(llvm->toLLVMType(ast->expandType(entry->__declarations[arg.identifier].type))); + signature.push_back(llvm->toLLVMType(ast->expandType(entry->__declarations.at(arg).type))); } return signature; } - llvm::Function::arg_iterator prepareBindings(){ + llvm::Function::arg_iterator + prepareBindings() override{ CodeScope* entry = PIFunctionUnitParent::function->__entry; - CodeScopeUnit* entryCompilation = PIFunctionUnitParent::getScopeUnit(entry); + ICodeScopeUnit* entryCompilation = PIFunctionUnitParent::getScopeUnit(entry); llvm::Function::arg_iterator fargsI = PIFunctionUnitParent::raw->arg_begin(); - for(size_t no: argumentsActual){ - Symbol arg = entry->findSymbol(entry->__bindings[no]); + for(size_t no : argumentsActual) { + ScopedSymbol arg{entry->__identifiers.at(entry->__bindings.at(no)), versions::VERSION_NONE}; - entryCompilation->__rawVars[arg.identifier] = &*fargsI; - fargsI->setName(entry->__bindings[no]); + entryCompilation->bindArg(&*fargsI, arg); + fargsI->setName(entry->__bindings.at(no)); ++fargsI; } return fargsI; } - virtual std::string prepareName(){ + virtual std::string + prepareName() override { return PIFunctionUnitParent::prepareName() + "_" + std::to_string(__id); } private: std::set argumentsActual; size_t __id; -}; +} ; PIFunction::PIFunction(PIFSignature&& sig, size_t id, TargetInterpretation* target) - : InterpretationFunction(sig.declaration, target), signatureInstance(move(sig)) -{ +: InterpretationFunction(sig.declaration, target), signatureInstance(move(sig)) { const FunctionInterpretationData& functionData = FunctionInterpretationHelper::getSignature(signatureInstance.declaration); std::set argumentsActual; - for (size_t no=0, size=functionData.signature.size(); no < size; ++no){ - if (functionData.signature.at(no) != INTR_ONLY){ + for (size_t no = 0, size = functionData.signature.size(); no < size; ++no) { + if (functionData.signature.at(no) != INTR_ONLY) { argumentsActual.insert(no); } } functionUnit = new PIFunctionUnit(signatureInstance.declaration, move(argumentsActual), id, target->pass); CodeScope* entry = signatureInstance.declaration->__entry; - CodeScopeUnit* entryUnit = functionUnit->getEntry(); + auto entryUnit = Decorators::getInterface<>(functionUnit->getEntry()); InterpretationScope* entryIntrp = InterpretationFunction::getScope(entry); - for(size_t no=0, sigNo=0, size = entry->__bindings.size(); no < size; ++no){ - if (functionData.signature.at(no) == INTR_ONLY){ - entryIntrp->overrideBinding(signatureInstance.bindings[sigNo], entry->__bindings[no]); - entryUnit->overrideDeclaration(entry->findSymbol(entry->__bindings[no]), Expression(signatureInstance.bindings[sigNo])); + list> bindingsPartial; + list> declsPartial; + + for(size_t no = 0, sigNo = 0, size = entry->__bindings.size(); no < size; ++no) { + if(functionData.signature.at(no) == INTR_ONLY) { + bindingsPartial.push_back({signatureInstance.bindings[sigNo], entry->__bindings[no]}); + + VNameId argId = entry->__identifiers.at(entry->__bindings[no]); + Symbol argSymbol{ScopedSymbol + {argId, versions::VERSION_NONE}, entry}; + declsPartial.push_back({argSymbol, signatureInstance.bindings[sigNo]}); ++sigNo; } } + + entryIntrp->overrideBindings(bindingsPartial); + entryUnit->overrideDeclarations(declsPartial); } llvm::Function* -PIFunction::compile(){ +PIFunction::compile() { llvm::Function* raw = functionUnit->compile(); return raw; } -bool operator<(const PIFSignature& lhs, const PIFSignature& rhs){ +bool operator<(const PIFSignature& lhs, const PIFSignature& rhs) { if (lhs.declaration.id() != rhs.declaration.id()) { return lhs.declaration.id() < rhs.declaration.id(); } return lhs.bindings < rhs.bindings; } -bool operator<(const PIFSignature& lhs, PIFunction* const rhs){ +bool operator<(const PIFSignature& lhs, PIFunction * const rhs) { return lhs < rhs->signatureInstance; } -bool operator<(PIFunction* const lhs, const PIFSignature& rhs){ +bool operator<(PIFunction * const lhs, const PIFSignature& rhs) { return lhs->signatureInstance < rhs; } -}} \ No newline at end of file +} +} + +/** \class xreate::interpretation::InterpretationFunction + * + * Holds list of xreate::interpretation::InterpretationScope 's focused on interpretation of individual code scopes + * + * There is particulat subclass PIFunction intended to represent partially interpreted functions + *\sa TargetInterpretation, [Interpretation Concept](/w/concepts/dfa) + */ +/** \class xreate::interpretation::TargetInterpretation + * + * Executed during compilation and intented to preprocess eligible parts of code. + * Established on [Targets Infrastructure](\ref compilation::Target) + * + * Holds list of InterpretationFunction / PIFunction to represent interpretation process for individual functions + * + * In order to be activated during compilation process there is + * InterpretationScopeDecorator implementation of ICodeScopeUnit + * \sa InterpretationPass, compilation::Target, [Interpretation Concept](/w/concepts/dfa) + * + */ diff --git a/cpp/src/compilation/targetinterpretation.h b/cpp/src/compilation/targetinterpretation.h index 0ef32e7..867b2f4 100644 --- a/cpp/src/compilation/targetinterpretation.h +++ b/cpp/src/compilation/targetinterpretation.h @@ -1,116 +1,130 @@ -/* - * To change this license header, choose License Headers in Project Properties. - * To change this template file, choose Tools | Templates - * and open the template in the editor. - */ - -/* +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * * File: targetstatic.h - * Author: pgess + * Author: pgess * * Created on July 2, 2016, 1:25 PM */ #ifndef TARGETSTATIC_H #define TARGETSTATIC_H #include "ast.h" +#include "pass/compilepass.h" #include "compilation/targets.h" -#include "transformations.h" #include "pass/interpretationpass.h" +#include "transcendlayer.h" -namespace xreate{ namespace compilation { - -class TargetInterpretation; -class InterpretationScope; -class InterpretationFunction; +namespace xreate{ namespace interpretation{ + class TargetInterpretation; + class InterpretationScope; + class InterpretationFunction; +}} +namespace xreate{ namespace compilation{ template <> - struct TargetInfo { + struct TargetInfo { typedef Expression Result; - typedef InterpretationScope Scope; - typedef InterpretationFunction Function; - }; - - template<> - struct TransformerInfo { - static const int id = 1; - }; + typedef interpretation::InterpretationScope Scope; + typedef interpretation::InterpretationFunction Function; + }; +}} -class InterpretationScope: public Scope{ +namespace xreate{ namespace interpretation{ + + /** \brief Encapsulates interpretation of a single Code Scope */ +class InterpretationScope: public compilation::Scope{ typedef Scope Parent; public: - InterpretationScope(CodeScope* scope, Function* f): Parent(scope, f) {} + InterpretationScope(const CodeScope* scope, compilation::Function* f): Parent(scope, f) {} Expression process(const Expression& expression) override; - llvm::Value* compile(const Expression& expression, const Context& context); + llvm::Value* compile(const Expression& expression, const compilation::Context& context); private: - llvm::Value* compileHybrid(const InterpretationOperator& op, const Expression& expression, const Context& context); + llvm::Value* processLate(const InterpretationOperator& op, const Expression& expression, const compilation::Context& context); //llvm::Value* compilePartialFnCall(const Expression& expression, const Context& context); CodeScope* processOperatorIf(const Expression& expression); CodeScope* processOperatorSwitch(const Expression& expression); + CodeScope* processOperatorSwitchVariant(const Expression& expression); }; -class InterpretationFunction: public Function{ +/** \brief Encapsulates interpretation of a single %Function */ +class InterpretationFunction: public compilation::Function{ public: - InterpretationFunction(const ManagedFnPtr& function, Target* target); + InterpretationFunction(const ManagedFnPtr& function, compilation::Target* target); Expression process(const std::vector& args); }; -/* - * Partially interpreted function signature - */ +/** \brief Signature of a partially interpreted function */ struct PIFSignature{ ManagedFnPtr declaration; std::vector bindings; }; class PIFunctionUnit; +/** \brief Partially interpreted function */ class PIFunction: public InterpretationFunction{ public: PIFunctionUnit* functionUnit; PIFSignature signatureInstance; PIFunction(PIFSignature&& sig, size_t id, TargetInterpretation* target); llvm::Function* compile(); }; bool operator<(const PIFSignature& lhs, PIFunction* const rhs); bool operator<(PIFunction* const lhs, const PIFSignature& rhs); -class TargetInterpretation: public Target, public Transformer{ +/** \brief Encapsulates actual [Interpretation](/w/concepts/dfa) based on InterpretationPass analysis results */ +class TargetInterpretation: public compilation::Target{ public: TargetInterpretation(AST* root, CompilePass* passCompilation): Target(root), pass(passCompilation){} - //transformer: -public: - virtual llvm::Value* transform(const Expression& expression, llvm::Value* raw, const Context& ctx) override; - virtual Expression transform(const Expression& expression, const Context& ctx) override; - virtual bool isAcceptable(const Expression& expression) override; - //target: public: - InterpretationFunction* getFunction(FunctionUnit* unit); + InterpretationFunction* getFunction(compilation::IFunctionUnit* unit); PIFunction* getFunction(PIFSignature&& sig); private: std::map __pifunctions; - std::map __dictFunctionsByUnit; + std::map __dictFunctionsByUnit; //self: public: CompilePass* pass; - llvm::Value* compile(const Expression& expression, const Context& ctx); + llvm::Value* compile(const Expression& expression, const compilation::Context& ctx); + InterpretationScope* transformContext(const compilation::Context& c); + private: - InterpretationScope* transformContext(const Context& c); }; +/**\brief Interpretation-aware Code Scope decorator + * \extends xreate::compilation::ICodeScopeUnit + */ +template +class InterpretationScopeDecorator: public Parent{ +public: + InterpretationScopeDecorator(const CodeScope* const codeScope, compilation::IFunctionUnit* f, CompilePass* compilePass): Parent(codeScope, f, compilePass){} + + virtual llvm::Value* process(const Expression& expr, const std::string& hintVarDecl){ + const InterpretationData& data = Attachments::get(expr, {ANY, NONE}); + bool flagInterpretationEligible = (data.resolution == INTR_ONLY || data.op != InterpretationOperator::NONE); + + if (flagInterpretationEligible){ + compilation::Context ctx{this, this->function, this->pass}; + return Parent::pass->targetInterpretation->compile(expr, ctx); + } + + return Parent::process(expr, hintVarDecl); + } +}; - -}} +}} //end of xreate:: interpretation #endif /* TARGETSTATIC_H */ \ No newline at end of file diff --git a/cpp/src/compilation/targets.h b/cpp/src/compilation/targets.h index f6b47bb..0b31ddd 100644 --- a/cpp/src/compilation/targets.h +++ b/cpp/src/compilation/targets.h @@ -1,161 +1,213 @@ -/* +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * * File: targetabstract.h - * Author: pgess + * Author: pgess * * Created on July 2, 2016, 1:25 PM */ +/** + * \file + * \brief Compilation targets infrastructure + */ + + #ifndef TARGETABSTRACT_H #define TARGETABSTRACT_H -#include "ast.h" +#include "ast.h" #include #include +#include namespace xreate{ namespace compilation { template struct TargetInfo{ //typedef Result //typedef Function //typedef Scope }; template class Function; template class Target; template class Scope{ + typedef typename TargetInfo::Scope Self; + public: - CodeScope* scope; + const CodeScope* scope; + Function* function=0; typename TargetInfo::Result processSymbol(const Symbol& s){ - CodeScope* scope = s.scope; - typename TargetInfo::Scope* self = function->getScope(scope); + const CodeScope* scope = s.scope; + Self* self = function->getScope(scope); if (self->__bindings.count(s.identifier)) { return self->__bindings[s.identifier]; } - const Expression& declaration = CodeScope::findDeclaration(s); + const Expression& declaration = CodeScope::getDefinition(s, true); if (!declaration.isDefined()){ assert(false); //for bindings there should be result already } return self->__bindings[s.identifier] = self->process(declaration); } typename TargetInfo::Result processScope() { - if (raw) return *raw; - - raw = process(scope->getBody()); - return *raw; + return process(scope->getBody()); } // typename TargetInfo::Result // processFunction(typename TargetInfo::Function* fnRemote, const std::vector::Result>& args){ // Scope scopeRemote = fnRemote->getScope(fnRemote->__function->__entry); // // if (scopeRemote->raw){ // return scopeRemote->raw; // } // // return fnRemote->process(args); // } virtual typename TargetInfo::Result process(const Expression& expression)=0; - Scope(CodeScope* codeScope, Function* f) + Scope(const CodeScope* codeScope, Function* f) : scope(codeScope), function(f) {} virtual ~Scope(){} void - overrideBinding(typename TargetInfo::Result arg, const std::string& name){ - assert(scope->__identifiers.count(name)); + overrideBindings(std::list::Result, std::string>> bindings){ + std::list::Result, ScopedSymbol>> bindingsSymbols; - VID id = scope->__identifiers.at(name); - __bindings[id] = arg; + for (auto entry: bindings){ + assert(scope->__identifiers.count(entry.second)); + ScopedSymbol id{scope->__identifiers.at(entry.second), versions::VERSION_NONE}; + bindingsSymbols.push_back(std::make_pair(entry.first, id)); + } - //reset the result if any: - raw.reset(); + overrideBindings(bindingsSymbols); } -protected: - Function* function=0; - std::map::Result> __bindings; - typename boost::optional::Result> raw; + void + overrideBindings(std::list::Result, ScopedSymbol>> bindings){ + reset(); + + for (auto entry: bindings){ + __bindings[entry.second] = entry.first; + } + } - //ResultType findFunction(const std::string& callee); + bool + isBindingDefined(const ScopedSymbol& id){ + return __bindings.count(id); + } + + void registerChildScope(std::shared_ptr scope){ + __childScopes.push_back(scope); + } + + void reset(){ + __bindings.clear(); + __childScopes.clear(); + } + +protected: + std::map::Result> __bindings; + std::list> __childScopes; }; template class Function{ typedef typename TargetInfo::Result Result; + typedef typename TargetInfo::Scope ConcreteScope; public: Function(const ManagedFnPtr& function, Target* target) : man(target), __function(function) {} virtual ~Function(){}; - typename TargetInfo::Scope* - getScope(CodeScope* scope){ - if (!__scopes.count(scope)){ - typename TargetInfo::Scope* unit = new typename TargetInfo::Scope(scope, this); - __scopes.emplace(scope, std::unique_ptr::Scope>(unit)); + ConcreteScope* + getScope(const CodeScope* const scope){ + if (__scopes.count(scope)) { + auto result = __scopes.at(scope).lock(); + + if (result){ + return result.get(); + } + } + + std::shared_ptr unit(new ConcreteScope(scope, this)); + + if (scope->__parent != nullptr){ + getScope(scope->__parent)->registerChildScope(unit); + + } else { + assert(!__entryScope); + __entryScope = unit; } - return __scopes.at(scope).get(); + if (!__scopes.emplace(scope, unit).second){ + __scopes[scope] = unit; + } + + return unit.get(); } virtual Result process(const std::vector& args)=0; Target* man=0; ManagedFnPtr __function; protected: - std::map::Scope>> __scopes; + std::map> __scopes; + std::shared_ptr __entryScope; }; +/** \brief Similar to xreate::IPass */ template class Target { typedef typename TargetInfo::Function ConcreteFunction; public: Target(AST* root): ast(root){} ConcreteFunction* getFunction(const ManagedFnPtr& function){ unsigned int id = function.id(); if (!__functions.count(id)){ ConcreteFunction* unit = new ConcreteFunction(function, this); __functions.emplace(id, unit); return unit; } return __functions.at(id); } AST* ast; virtual ~Target(){ for (const auto& entry: __functions){ delete entry.second; } } protected: std::map __functions; }; }} -#endif /* TARGETABSTRACT_H */ \ No newline at end of file +#endif /* TARGETABSTRACT_H */ diff --git a/cpp/src/compilation/transformations.cpp b/cpp/src/compilation/transformations.cpp index d77ca83..34cc7fd 100644 --- a/cpp/src/compilation/transformations.cpp +++ b/cpp/src/compilation/transformations.cpp @@ -1,143 +1,38 @@ -/* - * File: Transformations.cpp - * Author: pgess - * - * Created on June 18, 2016, 6:23 PM +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * transformation.cpp + * + * Author: pgess + * Created on March 27, 2017, 4:04 PM */ -#include "compilation/transformations.h" -#include "pass/compilepass.h" -#include "llvmlayer.h" -#include +/** + * \file transformations.h + * \brief Not used. + */ -using namespace llvm; -namespace xreate { namespace compilation { +#include "transformations.h" -Transformations::Transformations(CompilePass* passCompilation): pass(passCompilation) { -} - -void -Transformations::subscribe(const std::string& annotation, int handler){ - __subscriptions.emplace(annotation, handler); -} - -bool -Transformations::isAcceptable(const Expression& expression){ - //check subscription based on expression attachments - if (Attachments::get(expression, {false, 0}).flagSubscribed){ - return true; - } - - //subscription based on expression annotations; - if (expression.tags.size() == 0) return false; - - for (auto tag: expression.tags) { - if (__subscriptions.count(tag.first)){ - return true; - } - } - - return false; -} - -Expression -Transformations::transform(const Expression& expression, const Context& ctx){ - Expression result = expression; - - for (auto handler: getAppropriateTransformers(expression)){ - result = handler->transform(result, ctx); - } - - return result; -} - -llvm::Value* -Transformations::transform(const Expression& expression, llvm::Value* raw, const Context& ctx){ - for (auto handler: getAppropriateTransformers(expression)){ - raw = handler->transform(expression, raw, ctx); - } - - return raw; -} +namespace xreate { namespace compilation { std::list -Transformations::getAppropriateTransformers(const Expression& expression){ - +TransformationsManager::getRelevantTransformers(const Expression& expression){ std::list result; - + for (auto tag: expression.tags) { if (__subscriptions.count(tag.first)){ auto handlers = __subscriptions.equal_range(tag.first); - - for (auto handlerIt=handlers.first; handlerIt!= handlers.second; ++handlerIt){ - Transformer* handler = __transformers[handlerIt->second]; - - if (handler->isAcceptable(expression)){ - result.push_back(handler); - } + + for (auto handler = handlers.first; handler != handlers.second; ++handler){ + result.push_back(__transformers[handler->second]); } } } - - auto subscriberInternal = Attachments::get(expression, {false, 0}); - if (subscriberInternal.flagSubscribed){ - result.push_back(__transformers[subscriberInternal.subscriberId]); - } - - return result; -} -TransformerSaturation::TransformerSaturation(Transformations* man) - : __man(man) { - - man->subscribe("break", TransformerInfo::id); -} - -bool -TransformerSaturation::isAcceptable(const Expression& expression){ - return true; -} - -bool -TransformerSaturation::exists() const{ - return __block != nullptr; -} - -llvm::Value* -TransformerSaturation::transform(const Expression& expression, llvm::Value* raw, const Context& ctx){ - __block = __man->pass->man->llvm->builder.GetInsertBlock(); - - return raw; -} - -llvm::BasicBlock* -TransformerSaturation::getBlock() const{ - return __block; -} - -void -TransformerSaturation::inject(llvm::BasicBlock* blockAllocation, llvm::BasicBlock* blockExit, compilation::Context context){ - llvm::Type* tyInt1 = llvm::Type::getInt1Ty(llvm::getGlobalContext()); - llvm::Value* valueConstOne = llvm::ConstantInt::get(tyInt1, 1); - llvm::Value* valueConstFalse = llvm::ConstantInt::get(tyInt1, 0); - - //allocation of saturation flag - IRBuilder<> builderAlloca(blockAllocation, blockAllocation->getFirstInsertionPt()); - llvm::Value* flagSaturation = builderAlloca.CreateAlloca(tyInt1, valueConstOne, "flagSaturation"); - builderAlloca.CreateStore(valueConstFalse, flagSaturation, true); - - //set up saturation flag - llvm::BasicBlock* blockSaturation = __block; - IRBuilder<> builderSaturation(blockSaturation, blockSaturation->getFirstInsertionPt()); - builderSaturation.CreateStore(valueConstOne, flagSaturation, true); - - //check saturation flag: - //TODO remove blockContinue, receive from caller block to continue. - llvm::BasicBlock *blockContinue = llvm::BasicBlock::Create(llvm::getGlobalContext(), "continue", context.function->raw); - context.pass->man->llvm->builder.CreateCondBr(context.pass->man->llvm->builder.CreateLoad(flagSaturation), blockExit, blockContinue); - - context.pass->man->llvm->builder.SetInsertPoint(blockContinue); + return result; } -}} \ No newline at end of file +} } //namespace xreate diff --git a/cpp/src/compilation/transformations.h b/cpp/src/compilation/transformations.h index daec0bf..2dcf8bc 100644 --- a/cpp/src/compilation/transformations.h +++ b/cpp/src/compilation/transformations.h @@ -1,119 +1,116 @@ -/* - * File: Transformations.h - * Author: pgess +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * File: transformations.h + * Author: pgess * - * Created on June 18, 2016, 6:23 PM + * Created on March 25, 2017, 9:04 PM */ #ifndef TRANSFORMATIONS_H #define TRANSFORMATIONS_H -#include "ast.h" #include "pass/compilepass.h" -#include "attachments.h" - -namespace llvm { - class BasicBlock; -} namespace xreate { namespace compilation { - - class Transformer{ - public: - virtual llvm::Value* transform(const Expression& expression, llvm::Value* raw, const Context& ctx)=0; - virtual Expression transform(const Expression& expression, const Context& ctx){return expression;} - virtual bool isAcceptable(const Expression& expression)=0; - - virtual ~Transformer(){}; - }; - - class TransformerSaturation: public Transformer{ - public: - llvm::Value* transform(const Expression& expression, llvm::Value* raw, const Context& ctx); - bool isAcceptable(const Expression& expression); - TransformerSaturation(Transformations*); - llvm::BasicBlock* getBlock() const; - bool exists() const; - void inject(llvm::BasicBlock* blockAllocation, llvm::BasicBlock* blockExit, compilation::Context context); - - private: - llvm::BasicBlock* __block = nullptr; - Transformations* __man; - }; +template +struct TransformerInfo { + //static const unsigned int id = 1; (current vacant id) +}; - template - struct TransformerInfo { - //static const int id = 1; (next vacant id) - }; +class Transformer{ +public: + virtual llvm::Value* transform(const Expression& expression, llvm::Value* raw, const Context& ctx)=0; + virtual ~Transformer(){}; +}; + +class TransformationsManager { +public: + std::list getRelevantTransformers(const Expression& expression); - template <> - struct TransformerInfo { - static const int id = 0; - }; - class Transformations; + template + void registerTransformer(const std::string& annotation, TransformerType* t){ + const int id = TransformerInfo::id; + + assert(!__transformers.count(id)); + __transformers[id] = t; + __subscriptions.emplace(annotation, id); + } - struct SubscriberInfo{ - bool flagSubscribed; - int subscriberId; - }; + template + void unregisterTransformer(const std::string& annotation, TransformerType* t){ + const unsigned int id = TransformerInfo::id; + + auto range = __subscriptions.equal_range(annotation); + const auto entry = make_pair(annotation, id); + __subscriptions.erase(std::find_if(range.first, range.second, [id](const auto& el){return el.second == id;})); + __transformers.erase(id); + } - class Transformations: public Transformer { - public: - xreate::CompilePass* pass; - - bool isAcceptable(const Expression& expression); - llvm::Value* transform(const Expression& expression, llvm::Value* raw, const Context& ctx) override; - Expression transform(const Expression& expression, const Context& ctx) override; + template + TransformerType* update(TransformerType* newInstance){ + const int id = TransformerInfo::id; - Transformations(CompilePass*); - void subscribe(const std::string& annotation, int handler); + Transformer* oldInstance = __transformers[id]; + __transformers[id] = newInstance; - template - void registerTransformer(TransformerType* t){ - const int id = TransformerInfo::id; - - __transformers[id] = t; - } + return static_cast(oldInstance); + } + + template + bool exists(){ + const int id = TransformerInfo::id; - template - static void subscribe(const Holder& holder){ - //assert(! Attachments::exists()); - - const int id = TransformerInfo::id; - - if (Attachments::exists(holder)){ - const int idOld = Attachments::get(holder).subscriberId; - assert(idOld == id); - return; - } + return __transformers.count(id); + } - Attachments::put(holder, {true, id}); - } + template + TransformerType* get(){ + const int id = TransformerInfo::id; + return static_cast(__transformers.at(id)); + } + +private: + std::map __transformers; + std::multimap __subscriptions; +}; - template - TransformerType* get(){ - const int id = TransformerInfo::id; - return static_cast(__transformers.at(id)); +/**\brief Provides custom transformations during Code Scope compilation + * \extends xreate::compilation::ICodeScopeUnit + */ +template +class TransformationsScopeDecorator: public Transformer, public Parent { + // SCOPE DECORATOR PART +public: + TransformationsScopeDecorator(const CodeScope* const codeScope, IFunctionUnit* f, CompilePass* compilePass) + : Parent(codeScope, f, compilePass){} + + virtual llvm::Value* + process(const Expression& expr, const std::string& hintVarDecl=""){ + llvm::Value* result = Parent::process(expr, hintVarDecl); + return transform(expr, result, Context{this, Parent::function, Parent::pass}); + } + + // TRANSFORMER PART +public: + virtual llvm::Value* + transform(const Expression& expression, llvm::Value* raw, const Context& ctx) { + llvm::Value* result = raw; + TransformationsManager* man = Parent::pass->managerTransformations; + + if (expression.tags.size()) + for (Transformer* handler: man->getRelevantTransformers(expression)){ + result = handler->transform(expression, result, ctx); } - - private: - std::map __transformers; - std::multimap __subscriptions; - std::list getAppropriateTransformers(const Expression& expression); - }; -}} - -namespace xreate { - template<> - struct AttachmentsDict - { - typedef xreate::compilation::SubscriberInfo Data; - static const unsigned int key = 4; - }; -} + return result; + } +}; +} } + #endif /* TRANSFORMATIONS_H */ diff --git a/cpp/src/compilation/transformersaturation.cpp b/cpp/src/compilation/transformersaturation.cpp new file mode 100644 index 0000000..1411cca --- /dev/null +++ b/cpp/src/compilation/transformersaturation.cpp @@ -0,0 +1,84 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * transformersaturation.cpp + * + * Author: pgess + * Created on March 25, 2017, 10:06 PM + */ + +/** + * \file transformersaturation.h + * \brief Loop saturation support + */ + +#include "transformersaturation.h" +#include "llvmlayer.h" + +using namespace llvm; + +namespace xreate { namespace compilation { + +TransformerSaturation::TransformerSaturation(llvm::BasicBlock* allocationBlock, TransformationsManager* manager) + : man(manager), blockAllocation(allocationBlock){ + + if (man->exists()){ + oldInstance = man->update(this); + + } else { + man->registerTransformer("break", this); + } +} + +TransformerSaturation::~TransformerSaturation(){ + if (oldInstance) { + man->update(oldInstance); + + } else { + man->unregisterTransformer("break", this); + } +} + +llvm::Value* +TransformerSaturation::transform(const Expression& expression, llvm::Value* raw, const Context& ctx){ + processBreak(ctx); + + return raw; +} + + +void +TransformerSaturation::processBreak(const Context& ctx){ + allocateFlag(ctx); + + //show the saturation flag + llvm::IRBuilder<>& builder = ctx.pass->man->llvm->builder; + llvm::Type* tyInt1 = llvm::Type::getInt1Ty(ctx.pass->man->llvm->llvmContext); + llvm::Constant* constTrue = llvm::ConstantInt::get(tyInt1, 1); + builder.CreateStore(constTrue, flagSaturation, true); +} + +void +TransformerSaturation::allocateFlag(const Context& ctx){ + //allocation of saturation flag + IRBuilder<> builder(blockAllocation, blockAllocation->getFirstInsertionPt()); + llvm::Type* tyInt1 = llvm::Type::getInt1Ty(ctx.pass->man->llvm->llvmContext); + + llvm::Constant* constTrue = llvm::ConstantInt::get(tyInt1, 1); + flagSaturation = builder.CreateAlloca(tyInt1, constTrue, "flagSaturation"); + llvm::Constant* constFalse = llvm::ConstantInt::get(tyInt1, 0); + builder.CreateStore(constFalse, flagSaturation, true); +} + +bool +TransformerSaturation::insertSaturationChecks(llvm::BasicBlock* blockContinue, llvm::BasicBlock* blockExit, const Context& ctx){ + if (!flagSaturation) return false; + + llvm::IRBuilder<>& builder = ctx.pass->man->llvm->builder; + builder.CreateCondBr(builder.CreateLoad(flagSaturation), blockExit, blockContinue); + + return true; +} + +} } diff --git a/cpp/src/compilation/transformersaturation.h b/cpp/src/compilation/transformersaturation.h new file mode 100644 index 0000000..bb370a1 --- /dev/null +++ b/cpp/src/compilation/transformersaturation.h @@ -0,0 +1,45 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * File: transformersaturation.h + * Author: pgess + * + * Created on March 25, 2017, 9:59 PM + */ + +#ifndef TRANSFORMERSATURATION_H +#define TRANSFORMERSATURATION_H + +#include "transformations.h" + +namespace xreate { namespace compilation { + +class TransformerSaturation: public Transformer{ +public: + TransformerSaturation(llvm::BasicBlock* allocationBlock, TransformationsManager* manager); + ~TransformerSaturation(); + + llvm::Value* transform(const Expression& expression, llvm::Value* raw, const Context& ctx) override; + + void processBreak(const Context& ctx); + + void allocateFlag(const Context& ctx); + bool insertSaturationChecks(llvm::BasicBlock* blockContinue, llvm::BasicBlock* blockExit, const Context& ctx); + +private: + TransformationsManager* man; + TransformerSaturation* oldInstance = nullptr; + llvm::BasicBlock* blockAllocation; + llvm::Value* flagSaturation = nullptr; +}; + +template <> +struct TransformerInfo { + static const unsigned int id = 0; +}; + +} } + +#endif /* TRANSFORMERSATURATION_H */ + diff --git a/cpp/src/compilation/versions.h b/cpp/src/compilation/versions.h new file mode 100644 index 0000000..3aeaab5 --- /dev/null +++ b/cpp/src/compilation/versions.h @@ -0,0 +1,155 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * versions.cpp + * + * Author: pgess + * Created on January 21, 2017, 1:24 PM + */ + +/** + * \file + * \brief CodeScope's Decorator to support Versions + */ + +#include "pass/versionspass.h" +#include "pass/compilepass.h" +#include "llvmlayer.h" + +namespace xreate { + class CompilePass; + +namespace compilation { + class ICodeScopeUnit; + class IFunctionUnit; +} + +namespace versions{ + +/**\brief Enables compilation of code with versioned variables + * \details Dictates order of computation determined by VersionsPass + * \extends xreate::compilation::ICodeScopeUnit + * \sa VersionsPass, VersionsGraph + */ +template +class VersionsScopeDecorator: public Parent{ + typedef VersionsScopeDecorator SELF; + +public: + VersionsScopeDecorator(const CodeScope* const codeScope, compilation::IFunctionUnit* f, CompilePass* compilePass): Parent(codeScope, f, compilePass){} + + virtual llvm::Value* processSymbol(const Symbol& s, std::string hintSymbol=""){ + if (Attachments::exists(s)){ + const std::list dependencies = Attachments::get(s); + + for(const Symbol& symbolDependent: dependencies){ + processSymbol(symbolDependent); + } + } + + llvm::Value* result = Parent::processSymbol(s, hintSymbol); + + if (s.identifier.version == VERSION_INIT){ + llvm::Value* storage = SELF::processIntrinsicInit(result->getType(), hintSymbol); + setSymbolStorage(s, storage); + + processIntrinsicCopy(result, storage); + return compilation::ICodeScopeUnit::pass->man->llvm->builder.CreateLoad(storage); + + } else if (s.identifier.version != VERSION_NONE){ + Symbol symbolInitVersion = getSymbolInitVersion(s); + + llvm::Value* storage = getSymbolStorage(symbolInitVersion); + processIntrinsicCopy(result, storage); + + return compilation::ICodeScopeUnit::pass->man->llvm->builder.CreateLoad(storage); + } + + return result; + } + + llvm::Value* + processIntrinsicInit(llvm::Type* typeStorage, const std::string& hintVarDecl=""){ + LLVMLayer* llvm = compilation::ICodeScopeUnit::pass->man->llvm; + + llvm::IntegerType* tyInt = llvm::Type::getInt32Ty(llvm->llvmContext); + llvm::ConstantInt* constOne = llvm::ConstantInt::get(tyInt, 1, false); + + return llvm->builder.CreateAlloca(typeStorage, constOne, hintVarDecl); + } + + void + processIntrinsicCopy(llvm::Value* value, llvm::Value* storage){ + compilation::ICodeScopeUnit::pass->man->llvm->builder.CreateStore(value, storage); + } + +private: + std::map __symbolStorage; + + static Symbol + getSymbolInitVersion(const Symbol& s){ + return Symbol{ScopedSymbol{s.identifier.id, VERSION_INIT}, s.scope}; + } + + llvm::Value* + getSymbolStorage(const Symbol& s){ + return __symbolStorage.at(s); + } + + void setSymbolStorage(const Symbol& s, llvm::Value* storage){ + __symbolStorage[s] = storage; + } + +}; + +template +class VersionedFunctionDecorator : public Parent { +public: + VersionedFunctionDecorator(ManagedFnPtr f, CompilePass* p) + : Parent(f, p){} + +protected: + std::vector prepareArguments() { + std::vector&& arguments = Parent::prepareArguments(); + + return arguments; + } +}; +} } //end of namespace xreate::versions + +// llvm::Value* +// processIntrinsicInitAndCopy(){ +// +// } + +//llvm::Value* +//process(const Expression& expr, const std::string& hintVarDecl){ +// case Operator::CALL_INTRINSIC: { +// enum INRINSIC{INIT, COPY}; +// +// const ExpandedType& typSymbol = pass->man->root->expandType(expr.type); +// +// INTRINSIC op = (INTRINSIC) expr.getValueDouble(); +// +// switch (op){ +// case INIT: { +// llvm::Type* typSymbolRaw = l.toLLVMType(typSymbol); +// +// +// return storage; +// } +// +// case COPY: { +// llvm::Type* typSymbolRaw = l.toLLVMType(typSymbol); +// llvm::value* valueOriginal = process(expr.getOperands()[0], hintVarDecl); +// llvm::Value* storage = l.builder.CreateAlloca(typSymbolRaw, constOne, hintVarDecl); +// llvm::Value* valueCopy = l.builder.CreateStore(valueOriginal, storage); +// +// return valueCopy; +// } +// } +// return; +// } +//} +//}; diff --git a/cpp/src/contextrule.cpp b/cpp/src/contextrule.cpp index af3c84e..a24d528 100644 --- a/cpp/src/contextrule.cpp +++ b/cpp/src/contextrule.cpp @@ -1,53 +1,61 @@ -/* +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * * contextrule.cpp * * Created on: Jan 2, 2016 - * Author: pgess + * Author: pgess + */ + +/** + * \file contextrule.h + * \brief Context rules support. See more on [context rules](/w/concepts/context#context-rules) */ #include "contextrule.h" -#include "clasplayer.h" -#include "analysis/aux.h" +#include "transcendlayer.h" +#include "analysis/utils.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).\n"; listrepHead_ = xreate::analysis::compile(head); assert(repHead_.size() == 1); listrepGuards_ = xreate::analysis::compile(guards); assert(repGuards_.size() == 1); listrepBody_ = xreate::analysis::compile(body); assert(repBody_.size() == 1); - const std::string& atomBindingScope = Config::get("clasp.bindings.scope"); + const std::string& atomBindingScope = Config::get("transcend.bindings.scope"); boost::format formatContextVisibility("context_rule_visibility(ScopeX, %1%)"); boost::format formatScopeBind(atomBindingScope + "(ScopeX, %1%, Linkage)"); 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/contextrule.h b/cpp/src/contextrule.h index 7d06e3b..8d7227b 100644 --- a/cpp/src/contextrule.h +++ b/cpp/src/contextrule.h @@ -1,30 +1,34 @@ -/* +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * * contextrule.h * * Created on: Jan 2, 2016 - * Author: pgess + * Author: pgess */ + #ifndef SRC_CONTEXTRULE_H_ #define SRC_CONTEXTRULE_H_ #include "ast.h" #include namespace xreate { typedef unsigned int ScopePacked; class ContextRule { - public: - ContextRule(const Expression& rule); - std::string compile(const ScopePacked& scopeId) const; - - private: - Expression head; - Expression guards; - Expression body; +public: + ContextRule(const Expression& rule); + std::string compile(const ScopePacked& scopeId) const; + +private: + Expression head; + Expression guards; + Expression body; }; } #endif /* SRC_CONTEXTRULE_H_ */ diff --git a/cpp/src/llvmlayer.cpp b/cpp/src/llvmlayer.cpp index ca7ce01..eb4228b 100644 --- a/cpp/src/llvmlayer.cpp +++ b/cpp/src/llvmlayer.cpp @@ -1,255 +1,244 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * llvmlayer.cpp + * + * Author: pgess + */ + +/** + * \file llvmlayer.h + * \brief Wrapper over LLVM + */ + #include "ast.h" #include "llvmlayer.h" #include "ExternLayer.h" #include "llvm/ExecutionEngine/ExecutionEngine.h" #include "llvm/ExecutionEngine/MCJIT.h" #include "llvm/Support/TargetSelect.h" #include #include using namespace llvm; using namespace xreate; using namespace std; LLVMLayer::LLVMLayer(AST* root) - : ast(root), builder(getGlobalContext()) { - module = new llvm::Module(root->getModuleName(), llvm::getGlobalContext()); +: llvmContext(), +builder(llvmContext), +ast(root), +module(new llvm::Module(root->getModuleName(), llvmContext)) { layerExtern = new ExternLayer(this); layerExtern->init(root); } void* -LLVMLayer::getFunctionPointer(llvm::Function* function){ - uint64_t entryAddr = jit->getFunctionAddress(function->getName().str()); - return (void*) entryAddr; +LLVMLayer::getFunctionPointer(llvm::Function* function) { + uint64_t entryAddr = jit->getFunctionAddress(function->getName().str()); + return (void*) entryAddr; } void -LLVMLayer::initJit(){ - std::string ErrStr; - LLVMInitializeNativeTarget(); - llvm::InitializeNativeTargetAsmPrinter(); - - llvm::EngineBuilder builder((std::unique_ptr(module))); - jit = builder - .setEngineKind(llvm::EngineKind::JIT) - .setErrorStr(&ErrStr) - .setVerifyModules(true) - .create(); +LLVMLayer::initJit() { + std::string ErrStr; + LLVMInitializeNativeTarget(); + llvm::InitializeNativeTargetAsmPrinter(); + + llvm::EngineBuilder builder(std::unique_ptr(module.release())); + jit.reset(builder + .setEngineKind(llvm::EngineKind::JIT) + .setErrorStr(&ErrStr) + .setVerifyModules(true) + .create() + ); } void -LLVMLayer::print(){ +LLVMLayer::print() { llvm::PassManager PM; PM.addPass(llvm::PrintModulePass(llvm::outs(), "banner")); - PM.run(*module); -} - -llvm::BasicBlock* -LLVMLayer::initExceptionBlock(llvm::BasicBlock* blockException){ - initExceptionsSupport(); - - PointerType* tyInt8P = PointerType::getInt8PtrTy(llvm::getGlobalContext()); - Value* nullInt8P = llvm::ConstantPointerNull::get(tyInt8P); - - - builder.SetInsertPoint(blockException); - llvm::Function* fAllocate = module->getFunction("__cxa_allocate_exception"); - llvm::Function* fThrow = module->getFunction("__cxa_throw"); - - auto exception = builder.CreateCall(fAllocate, ConstantInt::get(IntegerType::getInt64Ty(getGlobalContext()), 4)); - vector throwParams{exception, nullInt8P, nullInt8P}; - builder.CreateCall(fThrow, ArrayRef(throwParams)); - builder.CreateUnreachable(); - - return blockException; + llvm::AnalysisManager aman; + PM.run(*module.get(), aman); } void -LLVMLayer::moveToGarbage(void *o) -{ +LLVMLayer::moveToGarbage(void *o) { __garbage.push_back(o); } llvm::Type* -LLVMLayer:: -toLLVMType(const ExpandedType& ty) const { - std::map empty; - return toLLVMType(ty, empty); +LLVMLayer::toLLVMType(const ExpandedType& ty) const { + std::map empty; + return toLLVMType(ty, empty); } llvm::Type* -LLVMLayer:: -toLLVMType(const ExpandedType& ty, std::map& conjuctions) const -{ +LLVMLayer::toLLVMType(const ExpandedType& ty, std::map& conjuctions) const { TypeAnnotation t = ty; - switch (t.__operator) + switch (t.__operator) { + case TypeOperator::LIST: { - case TypeOperator::ARRAY: - { - assert(t.__operands.size()==1); + assert(t.__operands.size() == 1); - TypeAnnotation elTy = t.__operands.at(0); - return llvm::ArrayType::get(toLLVMType(ExpandedType(move(elTy)), conjuctions), t.__size); - } - - case TypeOperator::STRUCT: - case TypeOperator::TUPLE: - { - assert(t.__operands.size()); + TypeAnnotation elTy = t.__operands.at(0); + return llvm::ArrayType::get(toLLVMType(ExpandedType(move(elTy)), conjuctions), t.__size); + } - std::vector pack_; - pack_.reserve(t.__operands.size()); + case TypeOperator::LIST_NAMED: + { + std::vector pack_; + pack_.reserve(t.__operands.size()); - std::transform(t.__operands.begin(), t.__operands.end(), std::inserter(pack_, pack_.end()), - [this, &conjuctions](const TypeAnnotation& t){ - return toLLVMType(ExpandedType(TypeAnnotation(t)), conjuctions); - }); + std::transform(t.__operands.begin(), t.__operands.end(), std::inserter(pack_, pack_.end()), + [this, &conjuctions](const TypeAnnotation & t) { + return toLLVMType(ExpandedType(TypeAnnotation(t)), conjuctions); + }); - llvm::ArrayRef pack(pack_); + llvm::ArrayRef pack(pack_); - //process recursive types: - if (conjuctions.count(t.conjuctionId)) { - auto result = conjuctions[t.conjuctionId]; - result->setBody(pack, false); + //process recursive types: + if (conjuctions.count(t.conjuctionId)) { + auto result = conjuctions[t.conjuctionId]; + result->setBody(pack, false); - return result; - } + return result; + } - return llvm::StructType::get(llvm::getGlobalContext(), pack, false); - }; + return llvm::StructType::get(llvmContext, pack, false); + }; - case TypeOperator::LINK: { - llvm::StructType* conjuction = llvm::StructType::create(llvm::getGlobalContext()); - int id = t.conjuctionId; + case TypeOperator::LINK: + { + llvm::StructType* conjuction = llvm::StructType::create(llvmContext); + int id = t.conjuctionId; - conjuctions.emplace(id, conjuction); - return conjuction; - }; + conjuctions.emplace(id, conjuction); + return conjuction; + }; - case TypeOperator::CALL: - { - assert(false); - }; + case TypeOperator::CALL: + { + assert(false); + }; - case TypeOperator::CUSTOM: - { - //Look in extern types + case TypeOperator::CUSTOM: + { + //Look in extern types + clang::QualType qt = layerExtern->lookupType(t.__valueCustom); + return layerExtern->toLLVMType(qt); + }; - clang::QualType qt = layerExtern->lookupType(t.__valueCustom); - return layerExtern->toLLVMType(qt); - }; + //DEBT omit ID field in case of single variant. + case TypeOperator::VARIANT: + { + /* Variant Type Layout: + * { + * id :: i8, Holds stored variant id + * storage:: type of biggest variant + * } + */ + uint64_t sizeStorage = 0; + llvm::Type* typStorageRaw = llvm::Type::getVoidTy(llvmContext); + for(const TypeAnnotation& subtype : t.__operands) { + llvm::Type* subtypeRaw = toLLVMType(ExpandedType(subtype), conjuctions); + if (subtypeRaw->isVoidTy()) continue; + + uint64_t sizeSubtype = module->getDataLayout().getTypeStoreSize(subtypeRaw); + if (sizeSubtype > sizeStorage) { + sizeStorage = sizeSubtype; + typStorageRaw = subtypeRaw; + } + } - case TypeOperator::VARIANT: { - int size = t.fields.size(); - assert(size); + std::vector layout; + layout.push_back(llvm::Type::getInt8Ty(llvmContext)); //id - int bitcount = ceil(log2(size)); - return llvm::Type::getIntNTy(llvm::getGlobalContext(), bitcount); + const bool flagHoldsData = sizeStorage > 0; + if (flagHoldsData) { + layout.push_back(typStorageRaw); //storage } + + return llvm::StructType::get(llvmContext, llvm::ArrayRef(layout)); + } - case TypeOperator::NONE: { - switch (t.__value) { - case TypePrimitive::Bool: - return llvm::Type::getInt1Ty(llvm::getGlobalContext()); + case TypeOperator::NONE: + { + switch (t.__value) { + case TypePrimitive::I32: + case TypePrimitive::Int: + case TypePrimitive::Num: + return llvm::Type::getInt32Ty(llvmContext); - case TypePrimitive::I32: - case TypePrimitive::Int: - case TypePrimitive::Num: - return llvm::Type::getInt32Ty(llvm::getGlobalContext()); + case TypePrimitive::Bool: + return llvm::Type::getInt1Ty(llvmContext); - case TypePrimitive::I8: - return llvm::Type::getInt8Ty(llvm::getGlobalContext()); + case TypePrimitive::I8: + return llvm::Type::getInt8Ty(llvmContext); - case TypePrimitive::Float: - return llvm::Type::getDoubleTy(llvm::getGlobalContext()); + case TypePrimitive::I64: + return llvm::Type::getInt64Ty(llvmContext); - case TypePrimitive::String: - return llvm::Type::getInt8PtrTy(llvm::getGlobalContext()); + case TypePrimitive::Float: + return llvm::Type::getDoubleTy(llvmContext); - default: - assert(false); - } - } + case TypePrimitive::String: + return llvm::Type::getInt8PtrTy(llvmContext); + + case TypePrimitive::Invalid: + return llvm::Type::getVoidTy(llvmContext); default: assert(false); + } + } + + default: + assert(false); } assert(false); return nullptr; } -void -LLVMLayer::initExceptionsSupport(){ - Type* typInt8Ptr = PointerType::get(IntegerType::get(module->getContext(), 8), 0); - - if (!module->getFunction("__cxa_throw")) { - std::vector fThrowSignature{typInt8Ptr, typInt8Ptr, typInt8Ptr}; - - FunctionType* tyFThrow = FunctionType::get( - /*Result=*/Type::getVoidTy(module->getContext()), - /*Params=*/fThrowSignature, - /*isVarArg=*/false); - - llvm::Function::Create( - /*Type=*/tyFThrow, - /*Linkage=*/GlobalValue::ExternalLinkage, - /*Name=*/"__cxa_throw", module); // (external, no body) - } - - if (!module->getFunction("__cxa_allocate_exception")) { - std::vectorfAllocateSignature{IntegerType::get(module->getContext(), 64)}; - - FunctionType* tyFAllocate = FunctionType::get( - /*Result=*/typInt8Ptr, - /*Params=*/fAllocateSignature, - /*isVarArg=*/false); - - llvm::Function::Create( - /*Type=*/tyFAllocate, - /*Linkage=*/GlobalValue::ExternalLinkage, - /*Name=*/"__cxa_allocate_exception", module); // (external, no body) - } -} - -bool TypeUtils::isStruct(const ExpandedType& ty){ +bool +TypeUtils::isStruct(const ExpandedType& ty) { const TypeAnnotation& t = ty.get(); - if (t.__operator==TypeOperator::STRUCT) { + if (t.__operator == TypeOperator::LIST_NAMED) { return true; } if (t.__operator != TypeOperator::CUSTOM) { return false; } clang::QualType tqual = llvm->layerExtern->lookupType(t.__valueCustom); const clang::Type * raw = tqual.getTypePtr(); - // TODO skip ALL the pointers until non-pointer type found + // TODO skip ALL the pointers until non-pointer type found if (raw->isStructureType()) return true; if (!raw->isAnyPointerType()) return false; clang::QualType pointee = raw->getPointeeType(); return pointee->isStructureType(); } - -bool TypeUtils::isPointer(const ExpandedType &ty) { +bool +TypeUtils::isPointer(const ExpandedType &ty) { if (ty.get().__operator != TypeOperator::CUSTOM) return false; clang::QualType qt = llvm->layerExtern->lookupType(ty.get().__valueCustom); return llvm->layerExtern->isPointer(qt); } - std::vector TypeUtils::getStructFields(const ExpandedType &t) { - return (t.get().__operator == TypeOperator::STRUCT) - ? t.get().fields - : llvm->layerExtern->getStructFields( - llvm->layerExtern->lookupType(t.get().__valueCustom)); + return (t.get().__operator == TypeOperator::LIST_NAMED) + ? t.get().fields + : llvm->layerExtern->getStructFields( + llvm->layerExtern->lookupType(t.get().__valueCustom)); } diff --git a/cpp/src/llvmlayer.h b/cpp/src/llvmlayer.h index fbbc823..900bb0d 100644 --- a/cpp/src/llvmlayer.h +++ b/cpp/src/llvmlayer.h @@ -1,58 +1,69 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * llvmlayer.h + * + * Author: pgess + */ + #ifndef LLVMLAYER_H #define LLVMLAYER_H #include "llvm/IR/Module.h" #include "llvm/IR/Function.h" #include "llvm/IR/PassManager.h" #include "llvm/IR/CallingConv.h" #include "llvm/IR/Verifier.h" #include "llvm/IR/IRPrintingPasses.h" #include "llvm/IR/IRBuilder.h" #include "llvm/Support/raw_ostream.h" #include "llvm/IR/LLVMContext.h" #include "llvm/ExecutionEngine/ExecutionEngine.h" #include "utils.h" namespace xreate { - class AST; - class ExternLayer; - class TypeAnnotation; - class LLVMLayer { - public: - LLVMLayer(AST* rootAST); +class AST; +class ExternLayer; +class TypeAnnotation; + +class LLVMLayer { +public: + LLVMLayer(AST* rootAST); + + mutable llvm::LLVMContext llvmContext; + llvm::IRBuilder<> builder; + AST *ast = 0; + ExternLayer *layerExtern =0; + std::unique_ptr module; + std::unique_ptr jit; + + + void moveToGarbage(void *o); - AST *ast = 0; - ExternLayer *layerExtern =0; - llvm::Module *module = 0; - llvm::ExecutionEngine* jit= 0; - llvm::IRBuilder<> builder; + llvm::Type* toLLVMType(const Expanded& ty) const; + void print(); + void* getFunctionPointer(llvm::Function* function); - void moveToGarbage(void *o); + void initJit(); + +private: + llvm::Type* toLLVMType(const Expanded& ty, std::map& conjunctions) const; + std::vector __garbage; +}; - llvm::Type* toLLVMType(const Expanded& ty) const; - void print(); - void* getFunctionPointer(llvm::Function* function); +struct TypeUtils { + bool isStruct(const Expanded& ty); + bool isPointer(const Expanded& ty); + std::vector getStructFields(const Expanded& t); - void initJit(); + TypeUtils(LLVMLayer*llvmlayer) + : llvm(llvmlayer){} - llvm::BasicBlock* initExceptionBlock(llvm::BasicBlock* block); private: - void initExceptionsSupport(); - llvm::Type* toLLVMType(const Expanded& ty, std::map& conjunctions) const; - std::vector __garbage; - }; - - struct TypeUtils { - bool isStruct(const Expanded& ty); - bool isPointer(const Expanded& ty); - std::vector getStructFields(const Expanded& t); - - TypeUtils(LLVMLayer*llvmlayer) - : llvm(llvmlayer){} - - private: - LLVMLayer* llvm; - }; + LLVMLayer* llvm; +}; + } #endif // LLVMLAYER_H diff --git a/cpp/src/modules.cpp b/cpp/src/modules.cpp new file mode 100644 index 0000000..c8ff3f6 --- /dev/null +++ b/cpp/src/modules.cpp @@ -0,0 +1,183 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * modules.cpp + * + * Author: pgess + * Created on July 22, 2017, 5:13 PM + */ + +/** + * \file modules.h + * \brief Modules support + */ + +#include "modules.h" +#include "modules/Parser.h" +#include "analysis/utils.h" +#include +#include +#include +#include +#include + +namespace fs = boost::filesystem; + +namespace xreate { namespace modules{ +void +ModuleRecord::addModuleQuery(const Expression& query){ + __queries.push_back(query); +} + +void +ModuleRecord::addControllerPath(const std::string& path){ + __controllers.push_back(path); +} + +void +ModuleRecord::addDiscoveryPath(const std::string& path){ + __discoveries.push_back(path); +} + +void +ModuleRecord::addProperty(const Expression& prop){ + __properties.push_back(prop); +} + +void +ModulesSolver::loadControllers(const ModuleRecord& module){ + for (const std::string& pathController: module.__controllers){ + std::fstream fileContent(pathController); + __program << fileContent.rdbuf(); + } +} + +void +ModulesSolver::extractProperties(const ModuleRecord& module){ + unsigned int moduleId = __registry->getModuleHash(module.__path); + const std::string atomProperty = "bind_module"; + boost::format formatProperty(atomProperty + "(%1%, %2%)."); + + for (const Expression& property: module.__properties){ + std::list reprProp = xreate::analysis::compile(property); + assert(reprProp.size()== 1); + + __program << (formatProperty % moduleId % reprProp.front()) + << std::endl; + } +} + +void +ModulesSolver::discoverModules(const ModuleRecord& moduleClient){ + std::regex extXreate("\\.xreate$", std::regex::basic); + + for(const std::string& path: moduleClient.__discoveries){ + for(fs::directory_entry e: fs::recursive_directory_iterator(path)) { + if (fs::is_regular_file(e.status())){ + if (!std::regex_search(e.path().string(), extXreate)) continue; + + FILE* script = fopen(e.path().c_str(), "r"); + Scanner scanner(script); + Parser parser(&scanner); + parser.Parse(); + assert(!parser.errors->count && "Discovery errors"); + parser.module.__path = e.path().c_str(); + + extractProperties(parser.module); + fclose(script); + } + } + } +} + +void +ModulesSolver::extractRequirements(const ModuleRecord& module){ + const std::string atomQuery = "module_require"; + boost::format formatProperty(atomQuery + "(%1%, %2%)."); + unsigned int moduleId = __registry->getModuleHash(module.__path); + + for (const Expression& query: module.__queries){ + std::list reprQuery = xreate::analysis::compile(query); + assert(reprQuery.size()== 1); + + __program << (formatProperty % moduleId % reprQuery.front()) + << std::endl; + } +} +void + +ModulesSolver::add(const std::string& base){ + __program << base; +} + +void +ModulesSolver::init(const std::string& programBase, const ModuleRecord& module){ + add(programBase); + extractRequirements(module); + extractProperties(module); + loadControllers(module); + discoverModules(module); + + std::cout << __program.str() << std::endl; +} + +std::list +ModulesSolver::run(const ModuleRecord& module){ + const std::string atomDecision = "module_include"; + unsigned int moduleId = __registry->getModuleHash(module.__path); + + std::list result; + std::vector args{"clingo", nullptr}; + DefaultGringoModule moduleDefault; + Gringo::Scripts scriptsDefault(moduleDefault); + ClingoLib ctl(scriptsDefault, 0, args.data(), {}, 0); + + ctl.add("base", {}, __program.str()); + ctl.ground({{"base", {}}}, nullptr); + ctl.solve([&atomDecision, this, &result, moduleId](Gringo::Model const &model) { + for (Gringo::Symbol atom : model.atoms(clingo_show_type_atoms)) { + std::cout << atom << std::endl; + + if (std::strcmp(atom.name().c_str(), atomDecision.c_str())==0){ + auto rowDecision = TranscendLayer::parse(atom); + + unsigned int moduleIdActual = std::get<0>(rowDecision); + if (moduleIdActual == moduleId){ + Gringo::Symbol moduleDecided = std::get<1>(rowDecision); + switch (moduleDecided.type()) { + case Gringo::SymbolType::Str: + result.push_back(moduleDecided.string().c_str()); + break; + + case Gringo::SymbolType::Num: + result.push_back(__registry->getModuleNameByHash(moduleDecided.num())); + break; + + default: assert(false && "Inappropriate symbol type"); + } + } + } + } + return true; + }, {}); + + return result; +} + +const std::string& +ModulesRegistry::getModuleNameByHash(unsigned int hash){ + auto result = __registry.right.find(hash); + assert(result != __registry.right.end()); + + return result->second; +} + +unsigned int +ModulesRegistry::getModuleHash(const std::string& moduleName){ + auto result = __registry.left.insert(Hash::left_value_type(moduleName, __registry.size())); + + return result.first->second; +} + +}} //namespace xreate::modules diff --git a/cpp/src/modules.h b/cpp/src/modules.h new file mode 100644 index 0000000..6800cd2 --- /dev/null +++ b/cpp/src/modules.h @@ -0,0 +1,90 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * File: modules.h + * Author: pgess + * + * Created on July 22, 2017, 5:11 PM + */ + +#ifndef MODULES_H +#define MODULES_H + +#include "ast.h" +#include + +#ifndef FRIENDS_MODULES_TESTS +#define FRIENDS_MODULES_TESTS +#endif + +namespace xreate { namespace modules{ + +/**\brief Cache of already processed modules */ +class ModulesRegistry{ +public: + const std::string& getModuleNameByHash(unsigned int hash); + unsigned int getModuleHash(const std::string& moduleName); + +private: + typedef boost::bimap Hash; + Hash __registry; +}; + +class ModulesSolver; + +/**\brief Holds information related to an individual module + * \sa XreateManagerDecoratorModules, ModulesSolver, ModulesRegistry + */ +class ModuleRecord { + FRIENDS_MODULES_TESTS + friend class ModulesSolver; + +public: + void addModuleQuery(const Expression& query); + void addControllerPath(const std::string& path); + void addDiscoveryPath(const std::string& path); + void addProperty(const Expression& prop); + +private: + std::list __queries; + std::list __controllers; + std::list __discoveries; + std::list __properties; + +public: + std::string __path; +}; + +/** \brief Resolves module's requrements + * \sa XreateManagerDecoratorModules, ModuleRecord + */ +class ModulesSolver{ + FRIENDS_MODULES_TESTS + +public: + ModulesSolver(ModulesRegistry *registry): __registry(registry) {} + + /** \brief Loads content of *controllers* into logic program for resolution */ + void loadControllers(const ModuleRecord& module); + + /** \brief Discovers specified path for existing modules and stores found modules' properties */ + void discoverModules(const ModuleRecord& moduleClient); + + void extractProperties(const ModuleRecord& module); + void extractRequirements(const ModuleRecord& module); + + void add(const std::string& base); + + void init(const std::string& programBase, const ModuleRecord& module); + std::list run(const ModuleRecord& module); + +private: + ModulesRegistry* __registry; + +public: + std::ostringstream __program; +}; +}} //end namespace xreate::modules + +#endif /* MODULES_H */ diff --git a/cpp/src/pass/abstractpass.cpp b/cpp/src/pass/abstractpass.cpp index fc4e19f..9cc6285 100644 --- a/cpp/src/pass/abstractpass.cpp +++ b/cpp/src/pass/abstractpass.cpp @@ -1,35 +1,103 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * Author: pgess + */ + +/** + * \file abstractpass.h + * \brief Infrastructure to iterate over AST to facilitate analysis and compilation. + */ + #include "abstractpass.h" #include "attachments.h" -#include "passmanager.h" +#include "xreatemanager.h" using namespace std; namespace xreate { - template<> - void defaultValue(){} +template<> +void defaultValue(){} - void AbstractPassBase::finish(){} +void IPass::finish(){} - AbstractPassBase::AbstractPassBase(PassManager *manager) - : man(manager) { - } +IPass::IPass(PassManager *manager) + : man(manager) { +} + +template<> +void +AbstractPass::processSymbol(const Symbol& symbol, PassContext context, const std::string& hintSymbol) +{ + if (__visitedSymbols.isCached(symbol)) + return; - template<> - void - AbstractPass::processSymbol(const std::string& ident, PassContext context) - { - const Symbol& symbol = context.scope->findSymbol(ident); + __visitedSymbols.setCachedValue(symbol); + const Expression& declaration = CodeScope::getDefinition(symbol, true); - if (__visitedSymbols.isCached(symbol)) - return; + if (declaration.isDefined()){ + PassContext context2 = context.updateScope(symbol.scope); + process(declaration, context2, hintSymbol); + } +} + +template<> +void +AbstractPass::process(const Expression& expression, PassContext context, const std::string& varDecl){ + if (expression.__state == Expression::COMPOUND){ + for (const Expression &op: expression.getOperands()) { + process(op, context); + } - __visitedSymbols.setCachedValue(symbol); - const Expression& declaration = CodeScope::findDeclaration(symbol); + for (CodeScope* scope: expression.blocks) { + process(scope, context); + } - if (declaration.isDefined()){ - PassContext context2 = context.updateScope(symbol.scope); - process(declaration, context2, ident); + if (expression.op == Operator::CALL){ + processExpressionCall(expression, context); } + + return; + } + + if (expression.__state == Expression::IDENT){ + assert(context.scope); + processSymbol(Attachments::get(expression), context, expression.getValueString()); } -} \ No newline at end of file +} +} + +/** + * \class xreate::IPass + * + * Each pass has to have IPass interface to be controllable by XreateManager. + * However in most cases users should inherit minimal useful implementation xreate::AbstractPass + * + * \note It's usually expected that custom Pass publish processing results by one of the following means: + * - xreate::Attachments for communicating with other Passes + * - IAnalysisReport to feed xreate::TranscendLayer solver + * + * \sa xreate::XreateManager, xreate::AbstractPass + */ + +/** + * \class xreate::AbstractPass + * + * Iterates over %AST and provides functions to alter processing of particular %AST nodes. + * Thus client should not re-implement every possible node processing + * and it's enough to focus only on relevant nodes. + * + * Template parameter `Output` specify type of node processing result data. + * + * Automatically caches already visited nodes + * + * \note It's usually expected that custom Pass publish processing results by one of the following means: + * - xreate::Attachments for communicating with other Passes + * - IAnalysisReport to feed xreate::TranscendLayer solver + * + * + * \sa xreate::XreateManager, xreate::IPass, xreate::AST + */ + diff --git a/cpp/src/pass/abstractpass.h b/cpp/src/pass/abstractpass.h index 328a916..9c8648b 100644 --- a/cpp/src/pass/abstractpass.h +++ b/cpp/src/pass/abstractpass.h @@ -1,201 +1,206 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * Author: pgess + */ + #ifndef ABSTRACTPASS_H #define ABSTRACTPASS_H #include "ast.h" -#include "passmanager.h" +#include "xreatemanager.h" #include namespace xreate { + /** \brief Holds current position in %AST while traversing*/ struct PassContext { - CodeScope* scope = 0; + const CodeScope* scope = 0; ManagedFnPtr function; ManagedRulePtr rule; std::string varDecl; PassContext() {} - PassContext&& updateScope(CodeScope* scopeNew) { + PassContext updateScope(const CodeScope* scopeNew) { PassContext context2{*this}; context2.scope = scopeNew; - return std::move(context2); + return context2; } ~PassContext(){} }; - class AbstractPassBase { + /** \brief Base class for all passes to inherit */ + class IPass { public: - AbstractPassBase(PassManager* manager); + IPass(PassManager* manager); + virtual ~IPass(){} + + /** \brief Executes pass */ virtual void run()=0; + + /** \brief Finalizes pass. Empty by default*/ virtual void finish(); PassManager* man; }; template Output defaultValue(); template<> void defaultValue(); + /** \brief Stores processing results for already visited nodes */ template class SymbolCache: private std::map{ public: bool isCached(const Symbol& symbol){ return this->count(symbol); } Output setCachedValue(const Symbol& symbol, Output&& value){ (*this)[symbol] = value; return value; } Output getCachedValue(const Symbol& symbol){ assert(this->count(symbol)); return this->at(symbol); } }; + /** \brief Set of already visited nodes */ template<> class SymbolCache: private std::set{ public: bool isCached(const Symbol& symbol){ bool result = this->count(symbol) > 0; return result; } void setCachedValue(const Symbol& symbol){ this->insert(symbol); } void getCachedValue(const Symbol& symbol){ } }; - template - class AbstractPass: public AbstractPassBase { - - SymbolCache __visitedSymbols; - - protected: - Output processSymbol(const std::string& ident, PassContext context){ - const Symbol& symbol = context.scope->findSymbol(ident); - - if (__visitedSymbols.isCached(symbol)) - return __visitedSymbols.getCachedValue(symbol); - - - const Expression& declaration = CodeScope::findDeclaration(symbol); - if (declaration.isDefined()){ - PassContext context2 = context.updateScope(symbol.scope); - - Output&& result = process(declaration, context2, ident); - return __visitedSymbols.setCachedValue(symbol, std::move(result)); - } - - return defaultValue(); - } - - SymbolCache& getSymbolCache(){ - return __visitedSymbols; - } - - public: - AbstractPass(PassManager* manager) - : AbstractPassBase(manager){} - - virtual Output processFnCall(ManagedFnPtr function, PassContext context){ - return defaultValue(); - } +/** \brief Minimal useful IPass implementation*/ +template +class AbstractPass: public IPass { + SymbolCache __visitedSymbols; - virtual void processFnCallUncertain(ManagedFnPtr function, PassContext context) - {} +protected: + virtual Output processSymbol(const Symbol& symbol, PassContext context, const std::string& hintSymbol=""){ + if (__visitedSymbols.isCached(symbol)) + return __visitedSymbols.getCachedValue(symbol); - virtual void process(ManagedRulePtr rule) - {} + const Expression& declaration = CodeScope::getDefinition(symbol, true); + if (declaration.isDefined()){ + PassContext context2 = context.updateScope(symbol.scope); - virtual Output process(ManagedFnPtr function) - { - PassContext context; - context.function = function; + Output&& result = process(declaration, context2, hintSymbol); + return __visitedSymbols.setCachedValue(symbol, std::move(result)); + } - return process(function->getEntryScope(), context); - } + return defaultValue(); + } - virtual Output process(CodeScope* scope, PassContext context, const std::string& hintBlockDecl=""){ - context.scope = scope; - return process(scope->getBody(), context); - } + Output processExpressionCall(const Expression& expression, PassContext context){ + const std::string &calleeName = expression.getValueString(); + std::list callees = man->root->getFunctionSpecializations(calleeName); + if (callees.size() == 1 && callees.front()){ + return processFnCall(callees.front(), context); - virtual Output process(const Expression& expression, PassContext context, const std::string& varDecl=""){ - switch (expression.__state) { - case Expression::COMPOUND: - assert(expression.op != Operator::MAP || (expression.op == Operator::MAP && expression.blocks.size())); - - //TODO there are discrepancies for SWITCH CASE scopes.case body parent scope differs from context.scope. - for (const Expression &op: expression.getOperands()) { - process(op, context); - } - - // - for (CodeScope* scope: expression.blocks) { - process(scope, context); - } - - if (expression.op == Operator::CALL) { - const std::string &calleeName = expression.getValueString(); - std::list callees = man->root->getFunctionVariants(calleeName); - if (callees.size() == 1 && callees.front()){ - processFnCall(callees.front(), context); - } else { - for (const ManagedFnPtr& callee: callees){ - processFnCallUncertain(callee, context); - } - } - } - break; - - case Expression::IDENT: - assert(context.scope); - return processSymbol(expression.getValueString(), context); - - default: - break; + } else { + for (const ManagedFnPtr& callee: callees){ + processFnCallUncertain(callee, context); } return defaultValue(); } + } + + SymbolCache& getSymbolCache(){ + return __visitedSymbols; + } + +public: + AbstractPass(PassManager* manager) + : IPass(manager){} + + /** \brief Processes function invocation instruction */ + virtual Output processFnCall(ManagedFnPtr functionCallee, PassContext context){ + return defaultValue(); + } + + /** \brief Processes function invocation instruction in uncertain cases + * \details Executed when it's impossible statically determine exact function invocation. + * In this case get executed for all possible candidates + */ + virtual void processFnCallUncertain(ManagedFnPtr functionCallee, PassContext context) + {} + + /** \brief Processes Logic Rule */ + virtual void process(ManagedRulePtr rule) + {} + + /** \brief Processes Function */ + virtual Output process(ManagedFnPtr function) + { + PassContext context; + context.function = function; - void run() { - ManagedRulePtr rule = man->root->begin(); - while (rule.isValid()) { - process(rule); - ++rule; - } + return process(function->getEntryScope(), context); + } - ManagedFnPtr f = man->root->begin(); - while (f.isValid()) { - process(f); - ++f; - } + /** \brief Processes single CodeScope */ + virtual Output process(CodeScope* scope, PassContext context, const std::string& hintBlockDecl=""){ + context.scope = scope; + + return processSymbol(Symbol{ScopedSymbol::RetSymbol, scope}, context); + } + + //TODO expose Symbol instead of varDecl. Required by DFAPass. + /** \brief Processes single Expression */ + virtual Output process(const Expression& expression, PassContext context, const std::string& varDecl=""){ + if (expression.__state == Expression::IDENT){ + assert(context.scope); + return processSymbol(Attachments::get(expression), context, expression.getValueString()); } - }; - template<> - void - AbstractPass::processSymbol(const std::string& ident, PassContext context); -} -#endif + assert(false); + return defaultValue(); + } -//PROCESS FUNCTION: -// const Symbol& symbolFunction{0, function->getEntryScope()}; -// -// if (__visitedSymbols.isCached(symbolFunction)) -// return __visitedSymbols.getCachedValue(symbolFunction); -// -// PassContext context; -// context.function = function; -// -// Output&& result = process(function->getEntryScope(), context); -// return __visitedSymbols.setCachedValue(symbolFunction, std::move(result)); \ No newline at end of file + /** \brief Executes AST traverse */ + void run() { + ManagedRulePtr rule = man->root->begin(); + while (rule.isValid()) { + process(rule); + ++rule; + } + + ManagedFnPtr f = man->root->begin(); + while (f.isValid()) { + process(f); + ++f; + } + } + +}; + +template<> +void +AbstractPass::processSymbol(const Symbol& symbol, PassContext context, const std::string& hintSymbol); + +template<> +void +AbstractPass::process(const Expression& expression, PassContext context, const std::string& hintSymbol); + +} +#endif diff --git a/cpp/src/pass/adhocpass.cpp b/cpp/src/pass/adhocpass.cpp deleted file mode 100644 index 65cde19..0000000 --- a/cpp/src/pass/adhocpass.cpp +++ /dev/null @@ -1,81 +0,0 @@ -/* - * adhoc.cpp - * - * Created on: Nov 28, 2015 - * Author: pgess - */ - -#include "pass/adhocpass.h" -#include "query/context.h" - -namespace xreate { - AdhocScheme* - AdhocPass::determineForScope(CodeScope* entry){ - const ScopePacked scopeId = man->clasp->pack(entry); - const Domain& domain = queryContext->getContext(scopeId); - AdhocScheme* scheme = nullptr; - - 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->getBody().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/adhocpass.h b/cpp/src/pass/adhocpass.h deleted file mode 100644 index 45877ad..0000000 --- a/cpp/src/pass/adhocpass.h +++ /dev/null @@ -1,50 +0,0 @@ -/* - * adhoc.h - * - * Created on: Nov 28, 2015 - * Author: pgess - */ -//SECTIONTAG adhoc pass -#ifndef SRC_INSTRUCTIONS_ADHOC_H_ -#define SRC_INSTRUCTIONS_ADHOC_H_ - -#include "abstractpass.h" - -#ifndef FRIEND_ADHOC_UNITTESTS - #define FRIEND_ADHOC_UNITTESTS -#endif - -namespace xreate { - - class ContextQuery; - - class AdhocScheme { - public: - AdhocScheme(const Expression& scheme); - CodeScope* getImplementationForCommand(const std::string& comm); - const TypeAnnotation& getResultType(); - const std::string& getContext(); - - private: - TypeAnnotation __resultType; - std::string __context; - std::map __commands; - }; - - class AdhocPass: public AbstractPass { - FRIEND_ADHOC_UNITTESTS - - public: - AdhocPass(PassManager* manager): AbstractPass(manager) {} - AdhocScheme* determineForScope(CodeScope* entry); - - // virtual void process(const Expression& expression, PassContext context, const std::string& varDecl=""); - void run() override; - - private: - std::map __schemes; - ContextQuery* queryContext; - }; -} - -#endif /* SRC_INSTRUCTIONS_ADHOC_H_ */ diff --git a/cpp/src/pass/cfapass.cpp b/cpp/src/pass/cfapass.cpp index c4afd00..2a51dc4 100644 --- a/cpp/src/pass/cfapass.cpp +++ b/cpp/src/pass/cfapass.cpp @@ -1,100 +1,198 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * cfapass.cpp + * + * Author: pgess + */ + +/** + * \file cfapass.h + * \brief Control Flow Analysis(CFA) + */ + #include "cfapass.h" #include "analysis/cfagraph.h" +#include "analysis/DominatorsAnalysisProvider.h" #include using namespace std; -using namespace xreate; +using namespace xreate::cfa; void -CFAPass::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); - } +CFAPassBasic::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 CFAPass::run(){ - initSignatures(); +void +CFAPassBasic::run(){ + initSignatures(); - return AbstractPass::run(); + return AbstractPass::run(); } void -CFAPass::finish() -{ - man->clasp->setCFAData(move(__context.graph)); +CFAPassBasic::finish(){ + man->transcend->registerReport(__context.graph); + boost::scoped_ptr cfaAdapter(dominators::CFAGraphAdapter::build(__context.graph)); + dominators::DominatorsAnalysisProvider* reportDominators = new dominators::DominatorsAnalysisProvider(); + reportDominators->run(cfaAdapter.get()); + man->transcend->registerReport(reportDominators); return AbstractPass::finish(); } void -CFAPass::processFnCall(ManagedFnPtr function, PassContext context) -{ - ClaspLayer* clasp = man->clasp; - __context.graph->addCallConnection(clasp->pack(context.scope), function->getName()); +CFAPassBasic::processFnCall(ManagedFnPtr function, PassContext context){ + TranscendLayer* transcend = man->transcend; + __context.graph->addCallConnection(transcend->pack(context.scope), function->getName()); - return AbstractPass::processFnCall(function, context); + return AbstractPass::processFnCall(function, context); } void -CFAPass::processFnCallUncertain(ManagedFnPtr function, PassContext context){ - ClaspLayer* clasp = man->clasp; - __context.graph->addCallConnection(clasp->pack(context.scope), function->getName()); +CFAPassBasic::processFnCallUncertain(ManagedFnPtr function, PassContext context){ + TranscendLayer* transcend = man->transcend; + __context.graph->addCallConnection(transcend->pack(context.scope), function->getName()); - return AbstractPass::processFnCallUncertain(function, context); + return AbstractPass::processFnCallUncertain(function, context); } void -CFAPass::process(CodeScope* scope, PassContext context, const std::string& hintBlockDecl){ - ClaspLayer* clasp = man->clasp; +CFAPassBasic::process(CodeScope* scope, PassContext context, const std::string& hintBlockDecl){ + TranscendLayer* transcend = man->transcend; - CodeScope* scopeParent = context.scope; - ScopePacked scopeId = clasp->pack(scope); + const CodeScope* scopeParent = context.scope; + ScopePacked scopeId = transcend->pack(scope); - if (scopeParent){ - __context.graph->addParentConnection(scopeId, clasp->pack(scopeParent)); - } else { - __context.graph->addParentConnection(scopeId, context.function->getName()); - } + __context.graph->addScope(scope); + + //Parent Relations + if (scopeParent){ + __context.graph->addParentConnection(scopeId, transcend->pack(scopeParent)); + } else { + __context.graph->addParentConnection(scopeId, context.function->getName()); + } - //TOTEST scope annotations - //SECTIONTAG context gather scope annotations - __context.graph->addScopeAnnotations(scopeId, scope->tags); + //TOTEST scope annotations + //SECTIONTAG context gather scope annotations + __context.graph->addScopeAnnotations(scopeId, scope->tags); - __context.graph->addContextRules(scopeId, scope->contextRules); + __context.graph->addContextRules(scopeId, scope->contextRules); - return AbstractPass::process(scope, context, hintBlockDecl); + return AbstractPass::process(scope, context, hintBlockDecl); } //TOTEST scope annotations via scheme void -CFAPass::process(const Expression& expression, PassContext context, const std::string& varDecl){ - ClaspLayer* clasp = man->clasp; +CFAPassBasic::process(const Expression& expression, PassContext context, const std::string& varDecl){ + TranscendLayer* transcend = man->transcend; - if (expression.__state == Expression::COMPOUND){ - Operator op= expression.op; + if (expression.__state == Expression::COMPOUND){ + Operator op= expression.op; - if (__signatures.count(op)) { - assert(expression.blocks.size()); + 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()); - } - } - } + for (const auto& scheme: boost::make_iterator_range(__signatures.equal_range(expression.op))) { + __context.graph->addScopeAnnotations(transcend->pack(expression.blocks.front()), scheme.second.getOperands()); + } + } + } - return AbstractPass::process(expression, context, varDecl); + return AbstractPass::process(expression, context, varDecl); } void -CFAPass::process(ManagedFnPtr function) -{ - __context.graph->addFunctionAnnotations(function->getName(), function->getTags()); - return AbstractPass::process(function); +CFAPassBasic::process(ManagedFnPtr function){ + __context.graph->addFunctionAnnotations(function->getName(), function->getTags()); + return AbstractPass::process(function); } -CFAPass::CFAPass(PassManager* manager) - : AbstractPass(manager) - , __context{new xreate::analysis::CFAGraph(manager->clasp)} +CFAPassBasic::CFAPassBasic(PassManager* manager) +: AbstractPass(manager) + , __context{new CFAGraph(manager->transcend)} {} + +/****************************SCOPE DEPENDENCIES********************************/ +void +CFAPassDependenciesDecorator::process(const Expression& expression, PassContext context, const std::string& varDecl){ + TranscendLayer* transcend = man->transcend; + + if (expression.__state == Expression::COMPOUND) + switch(expression.op){ + case Operator::SEQUENCE:{ + ScopePacked scopePrev = transcend->pack(expression.blocks.front()); + for(auto scopeIt= ++expression.blocks.begin(); scopeIt != expression.blocks.end(); ++scopeIt){ + ScopePacked scopeCurrent = transcend->pack(*scopeIt); + __context.graph->addDependency(scopeCurrent, scopePrev); + scopePrev = scopeCurrent; + } + break; + } + + default: break; + } + + return Parent::process(expression, context, varDecl); +} + +void +CFAPassDependenciesDecorator::processFnCall(ManagedFnPtr function, PassContext context){ + TranscendLayer* transcend = man->transcend; + + const CodeScope* scopeCaller = context.scope; + assert(scopeCaller); + ScopePacked scopeCallerPacked = transcend->pack(scopeCaller); + + if(__context.graph->isDependent(scopeCallerPacked)){ + ScopePacked scopeCalleePacked = transcend->pack(function->getEntryScope()); + __context.graph->transmitDependencies(scopeCalleePacked, scopeCallerPacked); + } + + Parent::processFnCall(function, context); +} + +void +CFAPassDependenciesDecorator::processFnCallUncertain(ManagedFnPtr function, PassContext context){ + TranscendLayer* transcend = man->transcend; + + const CodeScope* scopeCaller = context.scope; + assert(scopeCaller); + ScopePacked scopeCallerPacked = transcend->pack(scopeCaller); + + if(__context.graph->isDependent(scopeCallerPacked)){ + ScopePacked scopeCalleePacked = transcend->pack(function->getEntryScope()); + __context.graph->transmitDependencies(scopeCalleePacked, scopeCallerPacked); + } + + Parent::processFnCallUncertain(function, context); +} + +void +CFAPassDependenciesDecorator::process(CodeScope* scope, + PassContext context, const std::string& hintBlockDecl){ + + TranscendLayer* transcend = man->transcend; + const CodeScope* scopeParent = context.scope; + + if (scopeParent){ + ScopePacked scopePacked = transcend->pack(scope); + ScopePacked scopeParentPacked = transcend->pack(scopeParent); + if (!__context.graph->isDependent(scopePacked) && + __context.graph->isDependent(scopeParentPacked)) { + __context.graph->transmitDependencies(scopePacked, scopeParentPacked); + } + } + + Parent::process(scope, context, hintBlockDecl); +} +/** + * \class xreate::cfa::CFAPass + * \details Provides CFA, important analysis for reasoning. Iterates over AST and stores collected data in CFAGraph + */ diff --git a/cpp/src/pass/cfapass.h b/cpp/src/pass/cfapass.h index a064c6d..20f7467 100644 --- a/cpp/src/pass/cfapass.h +++ b/cpp/src/pass/cfapass.h @@ -1,38 +1,67 @@ -// Control Flow Graph determination pass +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * Author: pgess + * + * cfapass.cpp + * Control Flow Graph building pass + */ + #ifndef CFGPASS_H #define CFGPASS_H -#include "passmanager.h" -#include "clasplayer.h" +#include "xreatemanager.h" +#include "transcendlayer.h" #include "abstractpass.h" -namespace xreate{namespace analysis { - class CFAGraph; -}} - -namespace xreate { -class CFAPass : public AbstractPass -{ +namespace xreate{namespace cfa { + +class CFAGraph; + +/** \brief Control Flow Analysis Pass(%CFA)*/ +class CFAPassBasic : 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; - CFAPass(PassManager* manager); - + CFAPassBasic(PassManager* manager); void finish() override; void run() override; -private: + + const CFAGraph* getReport() const {return __context.graph; } + +protected: struct { - xreate::analysis::CFAGraph* graph; + CFAGraph* graph; } __context; std::multimap __signatures; //CFA data for particular operators void initSignatures(); -}; } +}; + +class CFAPassDependenciesDecorator: public CFAPassBasic{ + typedef CFAPassBasic Parent; + +public: + CFAPassDependenciesDecorator(PassManager* manager): CFAPassBasic(manager) {} + + void process(const Expression& expression, PassContext context, const std::string& varDecl) 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; +}; + +class CFAPass: public CFAPassDependenciesDecorator{ +public: + CFAPass(PassManager* manager): CFAPassDependenciesDecorator(manager) {} +}; + +}} //end of namespace xreate::cfa #endif // CFGPASS_H diff --git a/cpp/src/pass/compilepass.cpp b/cpp/src/pass/compilepass.cpp index 78666b5..d747d1b 100644 --- a/cpp/src/pass/compilepass.cpp +++ b/cpp/src/pass/compilepass.cpp @@ -1,829 +1,750 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * Author: pgess + * + * compilepass.cpp + */ + +/** + * \file compilepass.h + * \brief Compilation pass + */ + #include "compilepass.h" -#include "clasplayer.h" +#include "transcendlayer.h" #include #include "llvmlayer.h" #include "query/containers.h" -#include "query/context.h" #include "compilation/containers.h" -#include "compilation/transformations.h" -#include "compilation/latecontextcompiler2.h" #include "ExternLayer.h" -#include "pass/adhocpass.h" #include "compilation/targetinterpretation.h" - +#include "pass/versionspass.h" +#include "compilation/scopedecorators.h" +#include "compilation/operators.h" +#include "compilation/latex.h" +#include "analysis/typeinference.h" #include #include #include using namespace std; -using namespace xreate; -using namespace xreate::compilation; using namespace llvm; -//TODO use Scope - -//SECTIONTAG types/convert implementation -//TODO type conversion: -//a) automatically expand types int -> bigger int; int -> floating -//b) detect exact type of `num` based on max used numeral / function type -//c) warning if need to truncate (allow/dissalow based on annotations) - -namespace xreate { - -llvm::Value* -doAutomaticTypeConversion(llvm::Value* source, llvm::Type* tyTarget, llvm::IRBuilder<>& builder){ - if (tyTarget->isIntegerTy() && source->getType()->isIntegerTy()) - { - llvm::IntegerType* tyTargetInt = llvm::dyn_cast(tyTarget); - llvm::IntegerType* tySourceInt = llvm::dyn_cast(source->getType()); - - if (tyTargetInt->getBitWidth() < tySourceInt->getBitWidth()){ - return builder.CreateCast(llvm::Instruction::Trunc, source, tyTarget); - } - - if (tyTargetInt->getBitWidth() > tySourceInt->getBitWidth()){ - return builder.CreateCast(llvm::Instruction::SExt, source, tyTarget); - } - } - - if (source->getType()->isIntegerTy() && tyTarget->isFloatingPointTy()){ - return builder.CreateCast(llvm::Instruction::SIToFP, source, tyTarget); - } - - return source; -} - +namespace xreate{ +namespace compilation{ std::string -BasicFunctionDecorator::prepareName(){ - AST* ast = FunctionUnit::pass->man->root; +BasicFunctionUnit::prepareName() { + AST* ast = IFunctionUnit::pass->man->root; - string name = ast->getFunctionVariants(FunctionUnit::function->__name).size() > 1? - FunctionUnit::function->__name + std::to_string(FunctionUnit::function.id()) : - FunctionUnit::function->__name; + string name = ast->getFunctionSpecializations(IFunctionUnit::function->__name).size() > 1 ? + IFunctionUnit::function->__name + std::to_string(IFunctionUnit::function.id()) : + IFunctionUnit::function->__name; return name; } std::vector -BasicFunctionDecorator::prepareArguments(){ - LLVMLayer* llvm = FunctionUnit::pass->man->llvm; - AST* ast = FunctionUnit::pass->man->root; - CodeScope* entry = FunctionUnit::function->__entry; +BasicFunctionUnit::prepareSignature() { + LLVMLayer* llvm = IFunctionUnit::pass->man->llvm; + AST* ast = IFunctionUnit::pass->man->root; + CodeScope* entry = IFunctionUnit::function->__entry; std::vector signature; std::transform(entry->__bindings.begin(), entry->__bindings.end(), std::inserter(signature, signature.end()), - [llvm, ast, entry](const std::string &arg)->llvm::Type* { - assert(entry->__identifiers.count(arg)); + [llvm, ast, entry](const std::string & arg)->llvm::Type* { + assert(entry->__identifiers.count(arg)); - VID argid = entry->__identifiers.at(arg); - return llvm->toLLVMType(ast->expandType(entry->__declarations.at(argid).type)); - }); + ScopedSymbol argid{entry->__identifiers.at(arg), versions::VERSION_NONE}; + return llvm->toLLVMType(ast->expandType(entry->__declarations.at(argid).type)); + }); return signature; } llvm::Type* -BasicFunctionDecorator::prepareResult(){ - LLVMLayer* llvm = FunctionUnit::pass->man->llvm; - AST* ast = FunctionUnit::pass->man->root; - CodeScope* entry = FunctionUnit::function->__entry; +BasicFunctionUnit::prepareResult() { + LLVMLayer* llvm = IFunctionUnit::pass->man->llvm; + AST* ast = IFunctionUnit::pass->man->root; + CodeScope* entry = IFunctionUnit::function->__entry; - return llvm->toLLVMType(ast->expandType(entry->__declarations[0].type)); + return llvm->toLLVMType(ast->expandType(entry->__declarations.at(ScopedSymbol::RetSymbol).type)); } llvm::Function::arg_iterator -BasicFunctionDecorator::prepareBindings(){ - CodeScope* entry = FunctionUnit::function->__entry; - CodeScopeUnit* entryCompilation = FunctionUnit::getScopeUnit(entry); - llvm::Function::arg_iterator fargsI = FunctionUnit::raw->arg_begin(); +BasicFunctionUnit::prepareBindings() { + CodeScope* entry = IFunctionUnit::function->__entry; + ICodeScopeUnit* entryCompilation = IFunctionUnit::getScopeUnit(entry); + llvm::Function::arg_iterator fargsI = IFunctionUnit::raw->arg_begin(); for (std::string &arg : entry->__bindings) { - VID argid = entry->__identifiers[arg]; + ScopedSymbol argid{entry->__identifiers[arg], versions::VERSION_NONE}; - entryCompilation->__rawVars[argid] = &*fargsI; + entryCompilation->bindArg(&*fargsI, argid); fargsI->setName(arg); ++fargsI; } return fargsI; } -//SECTIONTAG late-context FunctionDecorator -template -class LateContextFunctionDecorator: public Parent{ -public: - LateContextFunctionDecorator(ManagedFnPtr f, CompilePass* p) - : Parent(f, p), contextCompiler(this, p) - {} +//DEBT compiler rigidly depends on exact definition of DefaultFunctionUnit +typedef latex::LatexBruteFunctionDecorator< + compilation::BasicFunctionUnit> -protected: - std::vector prepareArguments(){ - std::vector&& arguments = Parent::prepareArguments(); + BruteFunctionDefault; - size_t sizeLateContextDemand = contextCompiler.getFunctionDemandSize(); - if (sizeLateContextDemand) { - llvm::Type* ty32 = llvm::Type::getInt32Ty(llvm::getGlobalContext()); - llvm::Type* tyDemand = llvm::ArrayType::get(ty32, sizeLateContextDemand); +ICodeScopeUnit::ICodeScopeUnit(const CodeScope * const codeScope, IFunctionUnit* f, CompilePass* compilePass) +: pass(compilePass), function(f), scope(codeScope), currentBlockRaw(nullptr) { } - arguments.push_back(tyDemand); - } - - return arguments; - } - - llvm::Function::arg_iterator prepareBindings(){ - llvm::Function::arg_iterator fargsI = Parent::prepareBindings(); +llvm::Value* +BruteFnInvocation::operator()(std::vector&& args, const std::string& hintDecl) { + llvm::Function* calleeInfo = dyn_cast(__callee); - size_t sizeLateContextDemand = contextCompiler.getFunctionDemandSize(); - if (sizeLateContextDemand){ - fargsI->setName("latecontext"); - contextCompiler.rawContextArgument = &*fargsI; - ++fargsI; + if (calleeInfo) { + auto argsFormal = calleeInfo->args(); + size_t sizeArgsF = std::distance(argsFormal.begin(), argsFormal.end()); + assert(args.size() >= sizeArgsF); + assert(calleeInfo->isVarArg() || args.size() == sizeArgsF); + + auto argFormal = argsFormal.begin(); + for(size_t argId = 0; argId < args.size(); ++argId){ + if(argFormal != argsFormal.end()){ + args[argId] = typeinference::doAutomaticTypeConversion( + args.at(argId), argFormal->getType(), llvm->builder); + ++argFormal; + } } - - return fargsI; } -public: - LateContextCompiler2 contextCompiler; - -}; - -//SECTIONTAG adhoc FunctionDecorator -template -class AdhocFunctionDecorator: public Parent{ -public: - AdhocFunctionDecorator(ManagedFnPtr f, CompilePass* p) - : Parent(f, p) {} - -protected: - llvm::Type* prepareResult(){ - PassManager* man = Parent::pass->man; - CodeScope* entry = Parent::function->__entry; - LLVMLayer* llvm = Parent::pass->man->llvm; - AST* ast = Parent::pass->man->root; - AdhocPass* adhocpass = reinterpret_cast(man->getPassById(PassId::AdhocPass)); - - if (! Parent::function->isPrefunction){ - return Parent::prepareResult(); - } - - adhocImplementation = adhocpass->determineForScope(entry); - return llvm->toLLVMType(ast->expandType(adhocImplementation->getResultType())); + //Do not name function call that returns Void. + std::string nameStatement = hintDecl; + if (calleeInfo->getReturnType()->isVoidTy()) { + nameStatement.clear(); } -public: - AdhocScheme* adhocImplementation=nullptr; - -}; + return llvm->builder.CreateCall(__calleeTy, __callee, args, nameStatement); +} -typedef LateContextFunctionDecorator< - AdhocFunctionDecorator< - BasicFunctionDecorator>> DefaultFunctionUnit; +//DESABLEDFEATURE implement inlining +class CallStatementInline : public IFnInvocation{ +public: -CodeScopeUnit::CodeScopeUnit(CodeScope* codeScope, FunctionUnit* f, CompilePass* compilePass) - : scope(codeScope), pass(compilePass), function(f) -{} + CallStatementInline(IFunctionUnit* caller, IFunctionUnit* callee, LLVMLayer* l) + : __caller(caller), __callee(callee), llvm(l) { } + llvm::Value* operator()(std::vector&& args, const std::string& hintDecl) { + //TOTEST inlining + // CodeScopeUnit* entryCompilation = outer->getScopeUnit(function->__entry); + // for(int i=0, size = args.size(); ibindArg(args.at(i), string(entryCompilation->scope->__bindings.at(i))); + // } + // + // + // return entryCompilation->compile(); -llvm::Value* -CallStatementRaw::operator() (std::vector&& args, const std::string& hintDecl) { - llvm::Function* calleeInfo = dyn_cast(__callee); - - if (calleeInfo){ - auto argsFormal = calleeInfo->args(); - - int pos=0; - //SECTIONTAG types/convert function ret value - for (auto argFormal = argsFormal.begin(); argFormal!=argsFormal.end(); ++argFormal, ++pos){ - args[pos] = doAutomaticTypeConversion(args[pos], argFormal->getType(), llvm->builder); - } + return nullptr; } - return llvm->builder.CreateCall(__calleeTy, __callee, args, hintDecl); -} - -//DEBT implement inlining -class CallStatementInline: public CallStatement{ -public: - CallStatementInline(FunctionUnit* caller, FunctionUnit* callee, LLVMLayer* l) - : __caller(caller), __callee(callee), llvm(l) {} - - llvm::Value* operator() (std::vector&& args, const std::string& hintDecl) { - //TOTEST inlining -// CodeScopeUnit* entryCompilation = outer->getScopeUnit(function->__entry); -// for(int i=0, size = args.size(); ibindArg(args.at(i), string(entryCompilation->scope->__bindings.at(i))); -// } -// -// -// return entryCompilation->compile(); - } - private: - FunctionUnit* __caller; - FunctionUnit* __callee; - LLVMLayer* llvm; - - bool isInline(){ - // Symbol ret = Symbol{0, function->__entry}; - // bool flagOnTheFly = SymbolAttachments::get(ret, false); - //TODO consider inlining - return false; - } -}; + IFunctionUnit* __caller; + IFunctionUnit* __callee; + LLVMLayer* llvm; + + bool + isInline() { + // Symbol ret = Symbol{0, function->__entry}; + // bool flagOnTheFly = SymbolAttachments::get(ret, false); + //TODO consider inlining + return false; + } +} ; +BasicCodeScopeUnit::BasicCodeScopeUnit(const CodeScope * const codeScope, IFunctionUnit* f, CompilePass* compilePass) +: ICodeScopeUnit(codeScope, f, compilePass) { } -} +llvm::Value* +BasicCodeScopeUnit::processSymbol(const Symbol& s, std::string hintRetVar) { + Expression declaration = CodeScope::getDefinition(s); + const CodeScope* scopeExternal = s.scope; + ICodeScopeUnit* scopeBruteExternal = ICodeScopeUnit::function->getScopeUnit(scopeExternal); + assert(scopeBruteExternal->currentBlockRaw); + + llvm::Value* resultRaw; + llvm::BasicBlock* blockOwn = pass->man->llvm->builder.GetInsertBlock(); + + if (scopeBruteExternal->currentBlockRaw == blockOwn) { + resultRaw = scopeBruteExternal->process(declaration, hintRetVar); + scopeBruteExternal->currentBlockRaw = currentBlockRaw = + pass->man->llvm->builder.GetInsertBlock(); + + } else { + pass->man->llvm->builder.SetInsertPoint(scopeBruteExternal->currentBlockRaw); + resultRaw = scopeBruteExternal->processSymbol(s, hintRetVar); + pass->man->llvm->builder.SetInsertPoint(blockOwn); + } -void -CodeScopeUnit::overrideDeclaration(const Symbol binding, Expression&& declaration){ - function->getScopeUnit(binding.scope)->__declarationsOverriden.emplace(binding.identifier, move(declaration)); + return resultRaw; } -//SECTIONTAG late-context find callee function -//TOTEST static late context decisions -//TOTEST dynamic late context decisions - -CallStatement* -CodeScopeUnit::findFunction(const std::string& calleeName){ +IFnInvocation* +BasicCodeScopeUnit::findFunction(const Expression& opCall) { + const std::string& calleeName = opCall.getValueString(); LLVMLayer* llvm = pass->man->llvm; - ClaspLayer* clasp = pass->man->clasp; - DefaultFunctionUnit* function = dynamic_cast(this->function); - ContextQuery* queryContext = pass->queryContext; - - const std::list& specializations = pass->man->root->getFunctionVariants(calleeName); + const std::list& specializations = pass->man->root->getFunctionSpecializations(calleeName); //if no specializations registered - check external function - if (specializations.size()==0){ + if (specializations.size() == 0) { llvm::Function* external = llvm->layerExtern->lookupFunction(calleeName); - return new CallStatementRaw(external, llvm); - } + llvm::outs() << "Debug/External function: " << calleeName; + external->getType()->print(llvm::outs(), true); + llvm::outs() << "\n"; - //no decisions required - if (specializations.size()==1){ - if (!specializations.front()->guardContext.isValid()) { - return new CallStatementRaw( pass->getFunctionUnit(specializations.front())->compile(), llvm); - } + return new BruteFnInvocation(external, llvm); } - //TODO move dictSpecialization over to a separate function in order to perform cache, etc. - //prepare specializations dictionary - std::map dictSpecializations; + //There should be only one specialization without any valid guards at this point + return new BruteFnInvocation(pass->getFunctionUnit( + pass->man->root->findFunction(calleeName))->compile(), + llvm); +} - boost::optional variantDefault; - boost::optional variant; +//DISABLEDFEATURE transformations +// if (pass->transformations->isAcceptable(expr)){ +// return pass->transformations->transform(expr, result, ctx); +// } - for(const ManagedFnPtr& f: specializations){ - const Expression& guard = f->guardContext; +llvm::Value* +BasicCodeScopeUnit::process(const Expression& expr, const std::string& hintVarDecl) { +#define DEFAULT(x) (hintVarDecl.empty()? x: hintVarDecl) + llvm::Value *left; + llvm::Value *right; + LLVMLayer& l = *pass->man->llvm; + xreate::compilation::AdvancedInstructions instructions = xreate::compilation::AdvancedInstructions({this, function, pass}); - //default case: - if (!guard.isValid()){ - variantDefault = f; - continue; - } + switch (expr.op) { + case Operator::SUB: case Operator::MUL: + case Operator::DIV: case Operator::EQU: case Operator::LSS: + case Operator::GTR: case Operator::NE: case Operator::LSE: + case Operator::GTE: + assert(expr.__state == Expression::COMPOUND); + assert(expr.operands.size() == 2); - assert(dictSpecializations.emplace(guard, f).second && "Found several identical specializations"); - } + left = process(expr.operands[0]); + right = process(expr.operands[1]); - //check static context - ScopePacked scopeCaller = clasp->pack(this->scope); - const string atomSpecialization = "specialization"; - const Expression topicSpecialization(Operator::CALL, {(Atom(string(atomSpecialization))), (Atom(string(calleeName))), (Atom(scopeCaller))}); + break; - const Decisions& decisions = queryContext->getFinalDecisions(scopeCaller); - if (decisions.count(topicSpecialization)){ - variant = dictSpecializations.at(decisions.at(topicSpecialization)); + default:; } - //TODO check only demand for this particular topic. - size_t sizeDemand = function->contextCompiler.getFunctionDemandSize(); + switch (expr.op) { + case Operator::ADD: + { + left = process(expr.operands[0]); + Context context{this, function, pass}; - //decision made if static context found or no late context exists(and there is default variant) - bool flagHasStaticDecision = variant || (variantDefault && !sizeDemand); + llvm::Value* resultSU = StructUpdate::add(expr.operands[0], left, expr.operands[1], context, DEFAULT("tmp_add")); + if (resultSU) return resultSU; - //if no late context exists - if (flagHasStaticDecision) { - FunctionUnit* calleeUnit = pass->getFunctionUnit(variant? *variant: *variantDefault); + right = process(expr.operands[1]); - //inlining possible based on static decision only -// if (calleeUnit->isInline()) { -// return new CallStatementInline(function, calleeUnit); -// } + llvm::Value* resultAddPA = pointerarithmetic::PointerArithmetic::add(left, right, context, DEFAULT("tmp_add")); + if (resultAddPA) { + return resultAddPA; + } - return new CallStatementRaw(calleeUnit->compile(), llvm); + return l.builder.CreateAdd(left, right, DEFAULT("tmp_add")); + break; } - //require default variant if no static decision made - assert(variantDefault); + case Operator::SUB: + return l.builder.CreateSub(left, right, DEFAULT("tmp_sub")); + break; - llvm::Function* functionVariantDefault = this->pass->getFunctionUnit(*variantDefault)->compile(); - llvm::Value* resultFn = function->contextCompiler.findFunction(calleeName, functionVariantDefault, scopeCaller); - llvm::PointerType *resultPTy = cast(resultFn->getType()); - llvm::FunctionType *resultFTy = cast(resultPTy->getElementType()); - return new CallStatementRaw(resultFn, resultFTy, llvm); -} + case Operator::MUL: + return l.builder.CreateMul(left, right, DEFAULT("tmp_mul")); + break; -void -CodeScopeUnit::bindArg(llvm::Value* value, std::string&& alias) -{ - //reset cached compiled value if any - raw = nullptr; + case Operator::DIV: + return l.builder.CreateSDiv(left, right, DEFAULT("tmp_div")); + break; - //ensure existing of an alias - assert(scope->__identifiers.count(alias)); + case Operator::EQU: { + if (left->getType()->isIntegerTy()) return l.builder.CreateICmpEQ(left, right, DEFAULT("tmp_equ")); + if (left->getType()->isFloatingPointTy()) return l.builder.CreateFCmpOEQ(left, right, DEFAULT("tmp_equ")); - //memorize new value for an alias - VID id = scope->__identifiers.at(alias); - __rawVars[id] = value; -} + const ExpandedType& leftT = pass->man->root->getType(expr.operands[0]); + const ExpandedType& rightT = pass->man->root->getType(expr.operands[0]); -llvm::Value* -CodeScopeUnit::process(const Expression& expr, const std::string& hintVarDecl){ + if(leftT->__operator == TypeOperator::VARIANT && rightT->__operator == TypeOperator::VARIANT){ + llvm::Type* selectorT = llvm::cast(left->getType())->getElementType(0); + llvm::Value* leftUnwapped = typeinference::doAutomaticTypeConversion(left, selectorT, l.builder); + llvm::Value* rightUnwapped = typeinference::doAutomaticTypeConversion(right, selectorT, l.builder); + return l.builder.CreateICmpEQ(leftUnwapped, rightUnwapped, DEFAULT("tmp_equ")); + } - Context ctx{this, this->function, this->pass}; - if (pass->targetInterpretation->isAcceptable(expr)){ - return pass->targetInterpretation->compile(expr, ctx); + break; } - llvm::Value* result = processLowlevel(expr, hintVarDecl); + case Operator::NE: + return l.builder.CreateICmpNE(left, right, DEFAULT("tmp_ne")); + break; - if (pass->transformations->isAcceptable(expr)){ - return pass->transformations->transform(expr, result, ctx); - } + case Operator::LSS: + return l.builder.CreateICmpSLT(left, right, DEFAULT("tmp_lss")); + break; - return result; -} + case Operator::LSE: + return l.builder.CreateICmpSLE(left, right, DEFAULT("tmp_lse")); + break; -llvm::Value* -CodeScopeUnit::processLowlevel(const Expression& expr, const std::string& hintVarDecl){ -#define DEFAULT(x) (hintVarDecl.empty()? x: hintVarDecl) - llvm::Value *left; llvm::Value *right; - LLVMLayer& l = *pass->man->llvm; - xreate::compilation::Advanced instructions = xreate::compilation::Advanced({this, function, 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: case Operator::NE: case Operator::LSE: - case Operator::GTE: + case Operator::GTR: + return l.builder.CreateICmpSGT(left, right, DEFAULT("tmp_gtr")); + break; - assert(expr.__state == Expression::COMPOUND); - assert(expr.operands.size() == 2); + case Operator::GTE: + return l.builder.CreateICmpSGE(left, right, DEFAULT("tmp_gte")); + break; - left = process(expr.operands[0]); - right = process(expr.operands[1]); + case Operator::NEG: + left = process(expr.operands[0]); + return l.builder.CreateNeg(left, DEFAULT("tmp_neg")); + break; - //SECTIONTAG types/convert binary operation - right = doAutomaticTypeConversion(right, left->getType(), l.builder); - break; + case Operator::CALL: + { + assert(expr.__state == Expression::COMPOUND); + shared_ptr callee(findFunction(expr)); + const std::string& nameCallee = expr.getValueString(); - default:; - } + //prepare arguments + std::vector args; + args.reserve(expr.operands.size()); - switch (expr.op) { - case Operator::ADD: - return l.builder.CreateAdd(left, right, DEFAULT("tmp_add")); - break; + std::transform(expr.operands.begin(), expr.operands.end(), std::inserter(args, args.end()), + [this](const Expression & operand) { + return process(operand); + } + ); - case Operator::SUB: - return l.builder.CreateSub(left, right, DEFAULT("tmp_sub")); - break; + return (*callee)(move(args), DEFAULT("res_" + nameCallee)); + } - case Operator::MUL: - return l.builder.CreateMul(left, right, DEFAULT("tmp_mul")); - break; + case Operator::IF: + { + return instructions.compileIf(expr, DEFAULT("tmp_if")); + } - case Operator::DIV: - return l.builder.CreateSDiv(left, right, DEFAULT("tmp_div")); - break; + case Operator::SWITCH: + { + return instructions.compileSwitch(expr, DEFAULT("tmp_switch")); + } - case Operator::EQU: - if (left->getType()->isIntegerTy()) return l.builder.CreateICmpEQ(left, right, DEFAULT("tmp_equ")); - if (left->getType()->isFloatingPointTy()) return l.builder.CreateFCmpOEQ(left, right, DEFAULT("tmp_equ")); - break; + case Operator::LOGIC_AND: + { + assert(expr.operands.size() == 1); + return process(expr.operands[0]); + } - case Operator::NE: - return l.builder.CreateICmpNE(left, right, DEFAULT("tmp_ne")); - break; + case Operator::LIST: + { + return instructions.compileListAsSolidArray(expr, DEFAULT("tmp_list")); + }; - case Operator::LSS: - return l.builder.CreateICmpSLT(left, right, DEFAULT("tmp_lss")); - break; + case Operator::LIST_RANGE: + { + assert(false); //no compilation phase for a range list + // return InstructionList(this).compileConstantArray(expr, l, hintRetVar); + }; - case Operator::LSE: - return l.builder.CreateICmpSLE(left, right, DEFAULT("tmp_lse")); - break; + case Operator::LIST_NAMED: + { + typedef Expanded ExpandedType; - case Operator::GTR: - return l.builder.CreateICmpSGT(left, right, DEFAULT("tmp_gtr")); - break; + ExpandedType tyStructLiteral = l.ast->getType(expr); - case Operator::GTE: - return l.builder.CreateICmpSGE(left, right, DEFAULT("tmp_gte")); - break; + const std::vector fieldsFormal = (tyStructLiteral.get().__operator == TypeOperator::CUSTOM) ? + l.layerExtern->getStructFields(l.layerExtern->lookupType(tyStructLiteral.get().__valueCustom)) + : tyStructLiteral.get().fields; - case Operator::NEG: - left = process(expr.operands[0]); - return l.builder.CreateNeg(left, DEFAULT("tmp_neg")); - break; + std::map indexFields; + for (size_t i = 0, size = fieldsFormal.size(); i < size; ++i) { + indexFields.emplace(fieldsFormal[i], i); + } - case Operator::CALL: { - assert(expr.__state == Expression::COMPOUND); + llvm::StructType* tyLiteralRaw = llvm::cast(l.toLLVMType(tyStructLiteral)); + llvm::Value* record = llvm::UndefValue::get(tyLiteralRaw); - std::string nameCallee = expr.getValueString(); - shared_ptr callee(findFunction(nameCallee)); + for (size_t i = 0; i < expr.operands.size(); ++i) { + const Expression& operand = expr.operands.at(i); + unsigned int fieldId = indexFields.at(expr.bindings.at(i)); + llvm::Value* result = process(operand); + assert(result); + record = l.builder.CreateInsertValue(record, result, llvm::ArrayRef({fieldId})); + } - //prepare arguments - std::vector args; - args.reserve(expr.operands.size()); + return record; + }; - std::transform(expr.operands.begin(), expr.operands.end(), std::inserter(args, args.end()), - [this](const Expression &operand) { - return process(operand); - } - ); + case Operator::MAP: + { + assert(expr.blocks.size()); + return instructions.compileMapSolidOutput(expr, DEFAULT("map")); + }; - ScopePacked outerScopeId = pass->man->clasp->pack(this->scope); + case Operator::FOLD: + { + return instructions.compileFold(expr, DEFAULT("fold")); + }; - //TASK a) refactor CALL/ADHOC/find function - //SECTIONTAG late-context propagation arg - size_t calleeDemandSize = pass->queryContext->getFunctionDemand(nameCallee).size(); - if (calleeDemandSize){ - DefaultFunctionUnit* function = dynamic_cast(this->function); - llvm::Value* argLateContext = function->contextCompiler.compileContextArgument(nameCallee, outerScopeId); - args.push_back(argLateContext); - } + case Operator::FOLD_INF: + { + return instructions.compileFoldInf(expr, DEFAULT("fold")); + }; - return (*callee)(move(args), DEFAULT("res_"+nameCallee)); - } + case Operator::INDEX: + { + //TASK allow multiindex compilation + assert(expr.operands.size() == 2); + assert(expr.operands[0].__state == Expression::IDENT); - case Operator::IF: - { - return instructions.compileIf(expr, DEFAULT("tmp_if")); - } + const std::string& hintIdent = expr.operands[0].getValueString(); + Symbol s = Attachments::get(expr.operands[0]); + const ExpandedType& t2 = pass->man->root->getType(expr.operands[0]); - case Operator::SWITCH: - { - return instructions.compileSwitch(expr, DEFAULT("tmp_switch")); - } + llvm::Value* aggr = processSymbol(s, hintIdent); - case Operator::LOOP_CONTEXT: + switch (t2.get().__operator) { + case TypeOperator::LIST_NAMED: case TypeOperator::CUSTOM: { - return instructions.compileLoopContext(expr, DEFAULT("tmp_loop")); - } - - case Operator::LOGIC_AND: { - assert(expr.operands.size() == 1); - return process (expr.operands[0]); - } + std::string idxField; + const Expression& idx = expr.operands.at(1); + switch (idx.__state) { + + //named struct field + case Expression::STRING: + idxField = idx.getValueString(); + break; + + //anonymous struct field + case Expression::NUMBER: + idxField = to_string((int) idx.getValueDouble()); + break; + + default: + assert(false && "Wrong index for a struct"); + } - case Operator::LIST: - { - return instructions.compileListAsSolidArray(expr, DEFAULT("tmp_list")); + return instructions.compileStructIndex(aggr, t2, idxField); }; - case Operator::LIST_RANGE: + case TypeOperator::LIST: { - assert(false); //no compilation phase for a range list - // return InstructionList(this).compileConstantArray(expr, l, hintRetVar); + std::vector indexes; + std::transform(++expr.operands.begin(), expr.operands.end(), std::inserter(indexes, indexes.end()), + [this] (const Expression & op) { + return process(op); + } + ); + + return instructions.compileArrayIndex(aggr, indexes, DEFAULT(string("el_") + hintIdent)); }; - case Operator::LIST_NAMED: - { - typedef Expanded ExpandedType; + default: + assert(false); + } + }; - ExpandedType tyRaw = l.ast->expandType(expr.type); + case Operator::CALL_INTRINSIC: + { + const std::string op = expr.getValueString(); - const std::vector fields = (tyRaw.get().__operator == TypeOperator::CUSTOM)? - l.layerExtern->getStructFields(l.layerExtern->lookupType(tyRaw.get().__valueCustom)) - : tyRaw.get().fields; + if (op == "copy") { + llvm::Value* result = process(expr.getOperands().at(0)); - std::map indexFields; - for(size_t i=0, size = fields.size(); i::getInterface(this); + llvm::Value* storage = decoratorVersions->processIntrinsicInit(result->getType()); + decoratorVersions->processIntrinsicCopy(result, storage); - llvm::StructType* tyRecord = llvm::cast(l.toLLVMType(tyRaw)); - llvm::Value* record = llvm::UndefValue::get(tyRecord); + return l.builder.CreateLoad(storage, hintVarDecl); + } - for (size_t i=0; igetElementType(fieldId); -// result = llvm::UndefValue::get(tyNullField); -// -// } else { - result = process(operand); -// } + case Operator::VARIANT: + { + const ExpandedType& typVariant = pass->man->root->getType(expr); + llvm::Type* typVariantRaw = l.toLLVMType(typVariant); + llvm::Type* typIdRaw = llvm::cast(typVariantRaw)->getElementType(0); + + uint64_t id = expr.getValueDouble(); + llvm::Value* variantRaw = llvm::UndefValue::get(typVariantRaw); + variantRaw = l.builder.CreateInsertValue(variantRaw, llvm::ConstantInt::get(typIdRaw, id), llvm::ArrayRef({0})); + + const bool flagDoReference = expr.operands.size(); + if (flagDoReference) { + const ExpandedType& subtyp = ExpandedType(typVariant->__operands.at(id)); + llvm::Type* subtypRaw = l.toLLVMType(subtyp); + Attachments::put(expr.operands.at(0), subtyp); + llvm::Value* subtypValue = process(expr.operands.at(0)); + + llvm::Type* typStorageRaw = llvm::cast(typVariantRaw)->getElementType(1); + llvm::Value* addrAsStorage = l.builder.CreateAlloca(typStorageRaw); + llvm::Value* addrAsSubtyp = l.builder.CreateBitOrPointerCast(addrAsStorage, subtypRaw->getPointerTo()); + + l.builder.CreateStore(subtypValue, addrAsSubtyp); + llvm::Value* storageRaw = l.builder.CreateLoad(typStorageRaw, addrAsStorage); + variantRaw = l.builder.CreateInsertValue(variantRaw, storageRaw, llvm::ArrayRef({1})); + } - assert (result); - record = l.builder.CreateInsertValue(record, result, llvm::ArrayRef({fieldId})); - } + return variantRaw; + } - return record; - }; + case Operator::SWITCH_VARIANT: + { + return instructions.compileSwitchVariant(expr, DEFAULT("tmpswitch")); + } + case Operator::SWITCH_LATE: + { + assert(false && "Instruction's compilation should've been redirected to interpretation"); + return nullptr; + } + case Operator::SEQUENCE: + { + return instructions.compileSequence(expr); + } - case Operator::MAP: - { - assert(expr.blocks.size()); - return instructions.compileMapSolidOutput(expr, DEFAULT("map")); - }; + case Operator::UNDEF: + { + llvm::Type* typExprUndef = l.toLLVMType(typeinference::getType(expr, *pass->man->root)); + return llvm::UndefValue::get(typExprUndef); + } - case Operator::FOLD: - { - return instructions.compileFold(expr, DEFAULT("fold")); - }; + case Operator::INVALID: + assert(expr.__state != Expression::COMPOUND); - case Operator::FOLD_INF: + switch (expr.__state) { + case Expression::IDENT: { - return instructions.compileFoldInf(expr, DEFAULT("fold")); - }; + Symbol s = Attachments::get(expr); + return processSymbol(s, expr.getValueString()); + } - case Operator::INDEX: + case Expression::NUMBER: { - //TODO allow multiindex - assert(expr.operands.size()==1); - const std::string &ident = expr.getValueString(); - Symbol s = scope->findSymbol(ident); - const TypeAnnotation& t = CodeScope::findDeclaration(s).type; - const ExpandedType& t2 = pass->man->root->expandType(t); - llvm::Value* aggr = compileSymbol(s, ident); - - 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(); - - 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(aggr, indexes, DEFAULT(string("el_") + ident)); - }; - - default: - assert(false); - } - }; - - //SECTIONTAG adhoc actual compilation - //TODO a) make sure that it's correct: function->adhocImplementation built for Entry scope and used in another scope - case Operator::ADHOC: { - DefaultFunctionUnit* function = dynamic_cast(this->function); - assert(function->adhocImplementation && "Adhoc implementation not found"); - string comm = expr.operands[0].getValueString(); + llvm::Type* typConst = l.toLLVMType(typeinference::getType(expr, *pass->man->root)); + int literal = expr.getValueDouble(); - CodeScope* scope = function->adhocImplementation->getImplementationForCommand(comm); - CodeScopeUnit* unitScope = function->getScopeUnit(scope); + return llvm::ConstantInt::get(typConst, literal); + } - //SECTIONTAG types/convert ADHOC ret convertation - llvm::Type* resultTy = l.toLLVMType( pass->man->root->expandType(function->adhocImplementation->getResultType())); - return doAutomaticTypeConversion(unitScope->compile(), resultTy, l.builder); + case Expression::STRING: + { + return instructions.compileConstantStringAsPChar(expr.getValueString(), DEFAULT("tmp_str")); }; - case Operator::SEQUENCE: { - assert (expr.getOperands().size()); - - llvm::Value* result; - for(const Expression &op: expr.getOperands()){ - result = process(op, ""); - } - - return result; + default: + { + break; } + }; - 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(), 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; - break; - - default: break; + default: break; } - assert(false); + assert(false && "Can't compile expression"); return 0; } llvm::Value* -CodeScopeUnit::compile(const std::string& hintBlockDecl){ - if (raw != nullptr) return raw; - +BasicCodeScopeUnit::compile(const std::string& hintBlockDecl) { + LLVMLayer* llvm = pass->man->llvm; if (!hintBlockDecl.empty()) { - llvm::BasicBlock *block = llvm::BasicBlock::Create(llvm::getGlobalContext(), hintBlockDecl, function->raw); + llvm::BasicBlock *block = llvm::BasicBlock::Create(llvm->llvmContext, hintBlockDecl, function->raw); pass->man->llvm->builder.SetInsertPoint(block); } - raw = process(scope->getBody()); - return raw; -} - -llvm::Value* -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]; - } - - //compilation transformations could override symbol declarations. - Expression declaration = CodeScope::findDeclaration(s); - if (!declaration.isDefined()){ - if (self->__declarationsOverriden.count(s.identifier)){ - declaration = self->__declarationsOverriden[s.identifier]; - - } else { - assert(false); //in case of bindings there should be raws already. - } - } - - return self->__rawVars[s.identifier] = self->process(declaration, hintRetVar); + currentBlockRaw = pass->man->llvm->builder.GetInsertBlock(); + Symbol symbScope = Symbol{ScopedSymbol::RetSymbol, scope}; + return processSymbol(symbScope); } +ICodeScopeUnit::~ICodeScopeUnit() { } +IFunctionUnit::~IFunctionUnit() { } llvm::Function* -FunctionUnit::compile(){ +IFunctionUnit::compile() { if (raw != nullptr) return raw; LLVMLayer* llvm = pass->man->llvm; llvm::IRBuilder<>& builder = llvm->builder; string&& functionName = prepareName(); - std::vector&& types = prepareArguments(); + std::vector&& types = prepareSignature(); llvm::Type* expectedResultType = prepareResult(); llvm::FunctionType *ft = llvm::FunctionType::get(expectedResultType, types, false); raw = llvm::cast(llvm->module->getOrInsertFunction(functionName, ft)); prepareBindings(); - - const std::string&blockName = "entry"; + const std::string&blockName = "entry"; llvm::BasicBlock* blockCurrent = builder.GetInsertBlock(); - llvm::Value* result =getScopeUnit(function->__entry)->compile(blockName); + llvm::Value* result = getScopeUnit(function->__entry)->compile(blockName); assert(result); //SECTIONTAG types/convert function ret value - builder.CreateRet(doAutomaticTypeConversion(result, expectedResultType, llvm->builder)); + builder.CreateRet(typeinference::doAutomaticTypeConversion(result, expectedResultType, llvm->builder)); - if (blockCurrent){ - builder.SetInsertPoint(blockCurrent); + if (blockCurrent) { + builder.SetInsertPoint(blockCurrent); } llvm->moveToGarbage(ft); return raw; } -CodeScopeUnit* -FunctionUnit::getScopeUnit(CodeScope* scope){ - if (!scopes.count(scope)){ - CodeScopeUnit* unit = new CodeScopeUnit(scope, this, pass); - scopes.emplace(scope, std::unique_ptr(unit)); +ICodeScopeUnit* +IFunctionUnit::getScopeUnit(const CodeScope * const scope) { + if (__scopes.count(scope)) { + auto result = __scopes.at(scope).lock(); + + if (result) { + return result.get(); + } } - return scopes.at(scope).get(); -} + std::shared_ptr unit(pass->buildCodeScopeUnit(scope, this)); + + if (scope->__parent != nullptr) { + auto parentUnit = Decorators::getInterface(getScopeUnit(scope->__parent)); + parentUnit->registerChildScope(unit); + + } else { + __orphanedScopes.push_back(unit); + } + + if (!__scopes.emplace(scope, unit).second) { + __scopes[scope] = unit; + } -CodeScopeUnit* -FunctionUnit::getEntry(){ - return getScopeUnit(function->getEntryScope()); + return unit.get(); } -CodeScopeUnit* -FunctionUnit::getScopeUnit(ManagedScpPtr scope){ +ICodeScopeUnit* +IFunctionUnit::getScopeUnit(ManagedScpPtr scope) { return getScopeUnit(&*scope); } -FunctionUnit* -CompilePass::getFunctionUnit(const ManagedFnPtr& function){ - unsigned int id = function.id(); +ICodeScopeUnit* +IFunctionUnit::getEntry() { + return getScopeUnit(function->getEntryScope()); +} + +template<> +compilation::IFunctionUnit* +CompilePassCustomDecorators +::buildFunctionUnit(const ManagedFnPtr& function) { + return new BruteFunctionDefault(function, this); +} + +template<> +compilation::ICodeScopeUnit* +CompilePassCustomDecorators +::buildCodeScopeUnit(const CodeScope * const scope, IFunctionUnit* function) { + return new DefaultCodeScopeUnit(scope, function, this); +} + +} // end of compilation - if (!functions.count(id)){ - FunctionUnit* unit = new DefaultFunctionUnit(function, this); +compilation::IFunctionUnit* +CompilePass::getFunctionUnit(const ManagedFnPtr& function) { + unsigned int id = function.id(); + + if (!functions.count(id)) { + compilation::IFunctionUnit* unit = buildFunctionUnit(function); functions.emplace(id, unit); return unit; } return functions.at(id); } void -CompilePass::run(){ - transformations = new Transformations(this); - transformations->registerTransformer(new TransformerSaturation(transformations)); - - targetInterpretation = new TargetInterpretation(this->man->root, this); +CompilePass::run() { + //Initialization: + managerTransformations = new xreate::compilation::TransformationsManager(); + targetInterpretation = new interpretation::TargetInterpretation(this->man->root, this); - queryContext = reinterpret_cast (man->clasp->getQuery(QueryId::ContextQuery)); + //Determine entry function: + StaticModel model = man->transcend->query(Config::get("function-entry")); + assert(model.size() && "Error: No entry function found"); + assert(model.size() == 1 && "Error: Ambiguous entry function"); - //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>(TranscendLayer::parse(model.begin()->second)); + compilation::IFunctionUnit* unitMain = getFunctionUnit(man->root->findFunction(nameMain)); - string nameMain = std::get<0>(ClaspLayer::parse(model->first->second)); - FunctionUnit* unitMain = getFunctionUnit(man->root->findFunction(nameMain)); + //Compilation itself: entry = unitMain->compile(); } llvm::Function* -CompilePass::getEntryFunction(){ - assert(entry); - return entry; +CompilePass::getEntryFunction() { + assert(entry); + return entry; } void -CompilePass::prepareQueries(ClaspLayer* clasp){ - clasp->registerQuery(new containers::Query(), QueryId::ContainersQuery); - clasp->registerQuery(new ContextQuery(), QueryId::ContextQuery); +CompilePass::prepareQueries(TranscendLayer* transcend) { + transcend->registerQuery(new containers::Query(), QueryId::ContainersQuery); + transcend->registerQuery(new polymorph::PolymorphQuery(), QueryId::PolymorphQuery); + transcend->registerQuery(new latex::LatexQuery(), QueryId::LatexQuery); } - -//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; - //} - +} //end of namespace xreate + +/** + * \class xreate::CompilePass + * \brief Encapsulates all compilation activities + * + * xreate::CompilePass iterates over xreate::AST tree and produces executable code fed by data(via xreate::Attachments) gathered by previous passes as well as data via queries(xreate::IQuery) from xreate:TranscendLayer reasoner. + * Compilation's done using xreate::LLVMLayer(wrapper over LLVM toolchain) and based on following aspects: + * - Containers support. See \ref compilation/containers.h + * - Late Conext compilation. See xreate::context::LateContextCompiler2 + * - Interpretation support. See xreate::interpretation::TargetInterpretation + * - Loop saturation support. See xreate::compilation::TransformerSaturation + * - External Code access. See xreate::ExternLayer(wrapper over Clang library) + * + * \section adaptability_sect Adaptability + * xreate::CompilePass's architecture provides adaptability by employing: + * - %Function Decorators to alter function-level compilation. See xreate::compilation::IFunctionUnit + * - Code Block Decorators to alter code block level compilation. See xreate::compilation::ICodeScopeUnit + * Default functionality defined by \ref xreate::compilation::DefaultCodeScopeUnit + * - Targets to allow more versitile extensions. + * Currently only xreate::interpretation::TargetInterpretation use Targets infrastructure. See xreate::compilation::Target + * - %Altering Function invocation. xreate::compilation::ICallStatement + * + * Client able to construct compiler with desired decorators using xreate::compilation::CompilePassCustomDecorators. + * As a handy alias, `CompilePassCustomDecorators` constructs default compiler + * + */ diff --git a/cpp/src/pass/compilepass.h b/cpp/src/pass/compilepass.h index 416de88..7853fb8 100644 --- a/cpp/src/pass/compilepass.h +++ b/cpp/src/pass/compilepass.h @@ -1,155 +1,208 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * Author: pgess + * + * compilepass.h + */ + #ifndef COMPILEPASS_H #define COMPILEPASS_H #include "abstractpass.h" + #include "llvm/IR/Function.h" namespace xreate { - class AdhocScheme; - class ClaspLayer; - class ContextQuery; - class LLVMLayer; + class TranscendLayer; + class CompilePass; + class LLVMLayer; + + namespace interpretation{ + class TargetInterpretation; + } } -//namespace llvm { -// class Function; -// class Value; -// class Type; -//} - -namespace xreate { - -class CompilePass; - -namespace compilation { - -class CodeScopeUnit; -class FunctionUnit; - -class TargetInterpretation; +namespace xreate { namespace compilation { +class ICodeScopeUnit; +class IFunctionUnit; +class TransformationsManager; +/** \brief Holds current position in %AST while traversing*/ struct Context{ - CodeScopeUnit* scope; - FunctionUnit* function; + ICodeScopeUnit* scope; + IFunctionUnit* function; CompilePass* pass; }; -class CallStatement { +/** \brief Interface to specify custom way of function invocation + * \details Default implementation is xreate::compilation::RawFnInvocation + */ +class IFnInvocation { public: + /** \brief Returns result of custom function invocation for given arguments*/ virtual llvm::Value* operator() (std::vector&& args, const std::string& hintDecl="") = 0; }; -class CallStatementRaw: public CallStatement{ +/** \brief Default IFnInvocation implementation */ +class BruteFnInvocation: public IFnInvocation{ public: - CallStatementRaw(llvm::Function* callee, LLVMLayer* l) + BruteFnInvocation(llvm::Function* callee, LLVMLayer* l) : __callee(callee), __calleeTy(callee->getFunctionType()), llvm(l) {} - CallStatementRaw(llvm::Value* callee, llvm::FunctionType* ty, LLVMLayer* l) + BruteFnInvocation(llvm::Value* callee, llvm::FunctionType* ty, LLVMLayer* l) : __callee(callee), __calleeTy(ty), llvm(l) {} + + /** \brief Makes type conversions and returns LLVM call statement with given arguments*/ llvm::Value* operator() (std::vector&& args, const std::string& hintDecl=""); -private: +protected: llvm::Value* __callee; llvm::FunctionType* __calleeTy; - LLVMLayer* llvm; }; -class CodeScopeUnit { +/** \brief Interface to allow modification of CodeScope compilation + * \details Default implementation defined in xreate::compilation::DefaultCodeScopeUnit + */ +class ICodeScopeUnit{ public: - CodeScopeUnit(CodeScope* codeScope, FunctionUnit* f, CompilePass* compilePass); - - void bindArg(llvm::Value* value, std::string&& alias); - void overrideDeclaration(const Symbol binding, Expression&& declaration); - 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=""); - llvm::Value* processLowlevel(const Expression& expr, const std::string& hintVarDecl=""); + CompilePass* const pass; + IFunctionUnit* const function; + const CodeScope* const scope; + llvm::BasicBlock* currentBlockRaw; - CodeScope* scope; + ICodeScopeUnit(const CodeScope* const codeScope, IFunctionUnit* f, CompilePass* compilePass); + virtual ~ICodeScopeUnit(); -private: - CompilePass* pass; - llvm::Value* raw = nullptr; - FunctionUnit* function; - std::unordered_map __declarationsOverriden; + virtual llvm::Value* compile(const std::string& hintBlockDecl="")=0; + virtual llvm::Value* processSymbol(const Symbol& s, std::string hintRetVar="")=0; + virtual llvm::Value* process(const Expression& expr, const std::string& hintVarDecl="")=0; - - CallStatement* findFunction(const std::string& callee); + virtual Symbol bindArg(llvm::Value* value, std::string&& alias)=0; + virtual void bindArg(llvm::Value* value, const ScopedSymbol& s)=0; + virtual void reset() = 0; +protected: + virtual IFnInvocation* findFunction(const Expression& opCall)=0; }; -class IFunctionDecorator { +/** \brief Minimal useful ICodeScopeUnit implementation suited for inheritance */ +class BasicCodeScopeUnit: public ICodeScopeUnit{ +public: + BasicCodeScopeUnit(const CodeScope* const codeScope, IFunctionUnit* f, CompilePass* compilePass); + + llvm::Value* processSymbol(const Symbol& s, std::string hintRetVar="") override; + llvm::Value* process(const Expression& expr, const std::string& hintVarDecl="") override; + llvm::Value* compile(const std::string& hintBlockDecl="") override; + protected: - virtual std::string prepareName() = 0; - virtual std::vector prepareArguments() = 0; - virtual llvm::Type* prepareResult() = 0; - virtual llvm::Function::arg_iterator prepareBindings() = 0; - virtual ~IFunctionDecorator(){} + IFnInvocation* findFunction(const Expression& opCall) override; }; -class FunctionUnit: public IFunctionDecorator{ +/** \brief Interface to specify compilation of %Function */ +class IFunctionUnit{ public: - FunctionUnit(ManagedFnPtr f, CompilePass* p) - : function(f), pass(p) {} + IFunctionUnit(ManagedFnPtr f, CompilePass* p): function(f), pass(p) {} + virtual ~IFunctionUnit(); llvm::Function* compile(); - CodeScopeUnit* getEntry(); - CodeScopeUnit* getScopeUnit(CodeScope* scope); - CodeScopeUnit* getScopeUnit(ManagedScpPtr scope); + ICodeScopeUnit* getEntry(); + ICodeScopeUnit* getScopeUnit(const CodeScope * const scope); + ICodeScopeUnit* getScopeUnit(ManagedScpPtr scope); + virtual llvm::Type* prepareResult() = 0; + ManagedFnPtr function; llvm::Function* raw = nullptr; protected: CompilePass* pass=nullptr; + virtual std::string prepareName() = 0; + virtual std::vector prepareSignature() = 0; + virtual llvm::Function::arg_iterator prepareBindings() = 0; + private: - std::map> scopes; + std::map> __scopes; + std::list> __orphanedScopes; }; -class BasicFunctionDecorator: public FunctionUnit{ +/** \brief Minimal useful IFunctionUnit implementation suited for inheritance */ +class BasicFunctionUnit: public IFunctionUnit{ public: - BasicFunctionDecorator(ManagedFnPtr f, CompilePass* p) - : FunctionUnit(f, p) {} + BasicFunctionUnit(ManagedFnPtr f, CompilePass* p) + : IFunctionUnit(f, p) {} protected: - std::string prepareName(); - virtual std::vector prepareArguments(); - virtual llvm::Type* prepareResult(); - virtual llvm::Function::arg_iterator prepareBindings(); + std::string prepareName() override; + virtual std::vector prepareSignature() override; + virtual llvm::Type* prepareResult() override; + virtual llvm::Function::arg_iterator prepareBindings() override; }; - - class Transformations; -} // end of namespace `xreate::compilation` +} // end of namespace compilation class CompilePass : public AbstractPass { - friend class LateContextCompiler; - friend class LateContextCompiler2; - friend class compilation::CodeScopeUnit; - friend class compilation::FunctionUnit; + friend class compilation::BasicCodeScopeUnit; + friend class compilation::IFunctionUnit; public: - compilation::Transformations* transformations; + compilation::TransformationsManager* managerTransformations; + interpretation::TargetInterpretation* targetInterpretation; CompilePass(PassManager* manager): AbstractPass(manager) {} - compilation::FunctionUnit* getFunctionUnit(const ManagedFnPtr& function); + /** \brief Executes compilation process */ void run() override; + + /**\brief Returns compiled specified %Function + * \details Executes function compilation or read cache if it's already done + */ + compilation::IFunctionUnit* getFunctionUnit(const ManagedFnPtr& function); + + /**\brief Returns compiled main(entry) %Function in program */ llvm::Function* getEntryFunction(); - static void prepareQueries(ClaspLayer* clasp); + + /** \brief Initializes queries required by compiler. See xreate::IQuery, xreate::TranscendLayer */ + static void prepareQueries(TranscendLayer* transcend); + + + +protected: + virtual compilation::IFunctionUnit* buildFunctionUnit(const ManagedFnPtr& function)=0; + virtual compilation::ICodeScopeUnit* buildCodeScopeUnit(const CodeScope* const scope, compilation::IFunctionUnit* function)=0; + private: //TODO free `functions` in destructor - std::map functions; + std::map functions; llvm::Function* entry = 0; +}; + +namespace compilation{ - ContextQuery* queryContext; - compilation::TargetInterpretation* targetInterpretation; +/** \brief Constructs compiler with desired %Function and %Code Scope decorators. See adaptability in xreate::CompilePass*/ +template +class CompilePassCustomDecorators: public ::xreate::CompilePass{ +public: + CompilePassCustomDecorators(PassManager* manager): ::xreate::CompilePass(manager) {} + + virtual compilation::IFunctionUnit* buildFunctionUnit(const ManagedFnPtr& function) override{ + return new FUNCTION_DECORATOR(function, this); + } + virtual compilation::ICodeScopeUnit* buildCodeScopeUnit(const CodeScope* const scope, IFunctionUnit* function) override{ + return new SCOPE_DECORATOR(scope, function, this); + } }; -} +template<> +compilation::IFunctionUnit* +CompilePassCustomDecorators::buildFunctionUnit(const ManagedFnPtr& function); + +template<> +compilation::ICodeScopeUnit* +CompilePassCustomDecorators::buildCodeScopeUnit(const CodeScope* const scope, IFunctionUnit* function); + +}} //end of namespace xreate::compilation #endif // COMPILEPASS_H diff --git a/cpp/src/pass/dfapass.cpp b/cpp/src/pass/dfapass.cpp index 7a019e1..de02dc1 100644 --- a/cpp/src/pass/dfapass.cpp +++ b/cpp/src/pass/dfapass.cpp @@ -1,240 +1,266 @@ -#include "pass/dfapass.h" -#include "analysis/dfagraph.h" +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * Author: pgess + * + * dfapass.cpp + */ + +/** + * \file dfapass.h + * \brief Data Flow Analysis(DFA) + */ + +//DEBT DFA represent VersionaPass in declarative form using applyDependencies +// applyDependencies(expression, context, cache, decl); + +//DEBT DFA prepare static annotations and represent InterpretationPass in declarative form +// applyStaticAnnotations(expression, context, cache, decl); + +//DEBT DFA Eliminate dfa schemes -#include "passmanager.h" -#include "clasplayer.h" +#include "pass/dfapass.h" +#include "xreatemanager.h" +#include "transcendlayer.h" #include +#include using namespace std; -using namespace xreate::analysis; - -namespace xreate{ +namespace xreate {namespace dfa { DFAPass::DFAPass(PassManager* manager) - : AbstractPass(manager) - , __context{new xreate::analysis::DFAGraph(manager->clasp)} - , clasp(manager->clasp) -{} +: AbstractPass(manager) +, graph{new DFAGraph()} -SymbolNode -DFAPass::process(CodeScope* scope, PassContext context, const std::string& hintBlockDecl){ - const SymbolNode& retActual = AbstractPass::process(scope, context, hintBlockDecl); - const SymbolPacked& retFormal{0, clasp->pack(scope)}; - __context.graph->addConnection(retFormal, retActual, DFGConnection::STRONG); +, transcend(manager->transcend) { } - return retFormal; -} +void +DFAPass::processCallInstance(const Expression& expr, PassContext context, const SymbolNode& result) { + const string &nameCalleeFunction=expr.getValueString(); -SymbolNode -DFAPass::process(const Expression& expression, PassContext context, const std::string& decl) -{ - ExpressionCache cache; + //TODO implement processFnCall/Uncertain + list variantsCalleeFunction=man->root->getFunctionSpecializations(nameCalleeFunction); - if (!decl.empty()){ - cache.result = clasp->pack(context.scope->findSymbol(decl), context.function->getName() + ":" + decl); + vector operands; + operands.reserve(expr.getOperands().size()); - } else if (!expression.tags.empty()) { - cache.result = __context.graph->createAnonymousSymbol(clasp->pack(context.scope)); + for(const Expression& arg : expr.getOperands()) { + operands.push_back(process(arg, context)); + } - } else { - cache.result = SymbolTransient{{}, clasp->pack(context.scope)}; + //Set calling relations: + DFACallInstanceType type=variantsCalleeFunction.size()>1?WEAK:STRONG; + for(ManagedFnPtr function : variantsCalleeFunction) { + CodeScope *scopeRemote=function->getEntryScope(); + DFACallInstance callInstance; + callInstance.fnName=function->getName(); + callInstance.type=type; + + std::vector::const_iterator nodeActual=operands.begin(); + for(const std::string &identFormal : scopeRemote->__bindings) { + const ScopedSymbol symbolFormal{scopeRemote->__identifiers.at(identFormal), versions::VERSION_NONE}; + SymbolPacked symbolFormalPacked=transcend->pack(Symbol{symbolFormal, scopeRemote}, nameCalleeFunction+":"+identFormal); + callInstance.args.push_back(std::make_pair(symbolFormalPacked, *nodeActual)); + + ++nodeActual; + } + + callInstance.retActual=result; + SymbolNode retFormal=SymbolNode(transcend->pack(Symbol{ScopedSymbol::RetSymbol, scopeRemote}, nameCalleeFunction+":[ret]")); + + graph->addCallInstance(std::move(callInstance)); } +} +void +DFAPass::processDependencies(const SymbolNode& node, const Expression& expression, PassContext context, ProcessingCache& cache) { cache.operands.reserve(expression.getOperands().size()); - for (const Expression &op: expression.getOperands()) { - cache.operands.push_back(process(op, context)); + for(const Expression &op : expression.getOperands()) { + const SymbolNode& subnodeOperand=process(op, context); + + cache.operands.push_back(subnodeOperand); + graph->addDependency(node, subnodeOperand); } cache.blocks.reserve(expression.blocks.size()); - for (CodeScope* scope: expression.blocks) { - cache.blocks.push_back(process(scope, context)); - } + for(CodeScope* block : expression.blocks) { + const SymbolNode& subnodeBlock=process(block, context); - if (expression.__state == Expression::COMPOUND) { - processCompoundOp(expression, context, cache, decl); + cache.blocks.push_back(subnodeBlock); + graph->addDependency(node, subnodeBlock); + } +} - } else { - processElementaryOp(expression, context, cache, decl); +void +DFAPass::processAnnotations(const Expression& expression, PassContext context, const SymbolNode& ident){ + for (const pair& tag : expression.tags){ + graph->printInplaceAnnotation(ident, tag.second); } +} - applyDependencies(expression, context, cache, decl); - applyStaticAnnotations(expression, context, cache, decl); - applySignatureAnnotations(expression, context, cache, decl); - applyInPlaceAnnotations(expression, context, cache, decl); +SymbolNode +DFAPass::process(const Expression& expression, PassContext context, const std::string& varDecl) { + SymbolNode result; -//TODO Null ad hoc DFG implementation -// if (expression.isNone()){ -// return SymbolTransient{{Atom(Config::get("clasp.nonevalue"))}}; -// } + if(Attachments::exists(expression)){ + Symbol varSymbol=Attachments::get(expression); + result=transcend->pack(varSymbol, varDecl); - //non initialized(SymbolInvalid) value + } else if(expression.__state==Expression::IDENT&&expression.tags.size()==0){ + Symbol varSymbol=Attachments::get(expression); + result=transcend->pack(varSymbol, expression.getValueString()); - return cache.result; -} + } else { + result=SymbolAnonymous{expression.id}; + } + processAnnotations(expression, context, result); + ProcessingCache cache; -void -DFAPass::processElementaryOp(const Expression& expression, PassContext context, DFAPass::ExpressionCache& cache, const std::string& varDecl){ switch(expression.__state) { - case Expression::IDENT: { - std::string identifier = expression.getValueString(); + case Expression::COMPOUND: { + switch(expression.op) { + case Operator::CALL: { + processCallInstance(expression, context, result); + break; + } - SymbolNode nodeFrom = AbstractPass::process(expression, context, identifier); - if (SymbolPacked* nodeTo = boost::get(&cache.result)){ - __context.graph->addConnection(*nodeTo, nodeFrom, DFGConnection::STRONG); - - } else { - // cache.result = nodeFrom; - } + case Operator::IF: { + const SymbolNode& scopeA=process(expression.blocks.front(), context, "ifTrue" + std::to_string(expression.id)); + const SymbolNode& scopeB=process(expression.blocks.back(), context, "ifFalse" + std::to_string(expression.id)); + const SymbolNode& condition=process(expression.operands.at(0), context); + graph->addDependency(result, scopeA); + graph->addDependency(result, scopeB); + graph->addDependency(result, condition); + graph->printWeakAlias(result, scopeA); + graph->printWeakAlias(result, scopeB); break; } - default: break; - } -} + case Operator::SWITCH: + case Operator::SWITCH_VARIANT: { + for(CodeScope* block : expression.blocks) { + const SymbolNode& subnodeBlock=process(block, context, "case"+to_string(block->getBody().id)); -void -DFAPass::processCompoundOp(const Expression& expression, PassContext context, ExpressionCache& cache, const std::string& varDecl){ - - switch(expression.op) { - //apply calling relation - case Operator::CALL: { - const string &nameCalleeFunction = expression.getValueString(); - - //TODO implement processFnCall/Uncertain - list variantsCalleeFunction = man->root->getFunctionVariants(nameCalleeFunction); - if (variantsCalleeFunction.size()!=1) return; - ManagedFnPtr function= variantsCalleeFunction.front(); - - // set calling relations: - CodeScope *scopeRemote = function->getEntryScope(); - std::vector::iterator nodeActual = cache.operands.begin(); - for (const std::string &identFormal: scopeRemote->__bindings) { - const Symbol &symbolFormal = scopeRemote->findSymbol(identFormal); - __context.graph->addConnection(clasp->pack(symbolFormal, nameCalleeFunction + ":" + identFormal), *nodeActual, DFGConnection::WEAK); - ++nodeActual; + graph->addDependency(result, subnodeBlock); + graph->printWeakAlias(result, subnodeBlock); } - //TODO represent RET connection + const SymbolNode& condition=process(expression.operands.at(0), context); + graph->addDependency(result, condition); break; } - //apply PROTOTYPE relation - case Operator::MAP: { - SymbolNode nodeFrom= cache.operands.front(); - - SymbolPacked* nodeFromPacked = boost::get(&nodeFrom); - assert(nodeFromPacked); + case Operator::MAP: + processDependencies(result, expression, context, cache); + graph->printOperator(Operator::MAP, {result, cache.operands.at(0), cache.blocks.at(0)}); + break; - SymbolPacked* nodeTo = boost::get(&cache.result); - assert(nodeTo); + case Operator::FOLD: + processDependencies(result, expression, context, cache); + graph->printOperator(Operator::FOLD, {result, cache.operands.at(0), cache.operands.at(1), cache.blocks.at(0)}); + break; - __context.graph->addConnection(*nodeTo, *nodeFromPacked, DFGConnection::PROTOTYPE); + case Operator::LIST: + processDependencies(result, expression, context, cache); + graph->printOperator(Operator::LIST, {result}, expression.getOperands().size()); break; - } - default: break; - } -} + case Operator::LIST_RANGE: + processDependencies(result, expression, context, cache); + graph->printOperator(Operator::LIST_RANGE, {result}); + break; -void -DFAPass::applyDependencies(const Expression& expression, PassContext context, ExpressionCache& cache, const std::string& decl){ - for (SymbolNode &op: cache.operands) { - __context.graph->addDependencyConnection(cache.result, op); - } + case Operator::INDEX: + processDependencies(result, expression, context, cache); + graph->printOperator(Operator::INDEX, {result, cache.operands.at(0), cache.operands.at(1)}); + break; - for (SymbolNode &block: cache.blocks) { - __context.graph->addDependencyConnection(cache.result, block); + default: { + processDependencies(result, expression, context, cache); + break; + } + } + break; } - switch(expression.__state) { - case Expression::IDENT: { - const string& identName = expression.getValueString(); + case Expression::IDENT: { + SymbolNode symbIdent=AbstractPass::process(expression, context, varDecl); - SymbolNode identSymbol = clasp->pack(context.scope->findSymbol(identName), context.function->getName() + ":" + identName); - __context.graph->addDependencyConnection(cache.result, identSymbol); + if(!(result==symbIdent)){ + graph->addDependency(result, symbIdent); + graph->printAlias(result, symbIdent); } - default: break; + break; } -} - -void -DFAPass::applyStaticAnnotations(const Expression& expression, PassContext context, ExpressionCache& cache, const std::string& decl){ - switch(expression.__state) { - case Expression::NUMBER: - case Expression::STRING: - __context.graph->addAnnotation(cache.result, Expression(Atom("static"))); - break; + case Expression::NUMBER: + case Expression::STRING: { + break; + } - default: break; + case Expression::INVALID: + case Expression::BINDING: { + assert(false); + break; + } } + + return result; } -void -DFAPass::applySignatureAnnotations(const Expression& expression, PassContext context, ExpressionCache& cache, const std::string& decl){ - if (__signatures.count(expression.op)) { - const Expression &scheme = __signatures.at(expression.op); - - //TODO add possibility to specifi signature for a particular function -// if (expression.op == Operator::CALL || expression.op == Operator::INDEX){ -// string caption = expression.getValueString(); -// operands.push_back(process(Expression(move(caption)), context, "")); -// } - - std::vector::iterator arg = cache.operands.begin(); - std::vector::const_iterator tag = ++scheme.getOperands().begin(); - - while (tag != scheme.getOperands().end()) { - if (tag->__state != Expression::INVALID) { - __context.graph->addAnnotation(*arg, Expression(*tag)); - } +SymbolNode +DFAPass::process(CodeScope* scope, PassContext context, const std::string& hintBlockDecl) { + if (!hintBlockDecl.empty()) { + Symbol symbRet{ScopedSymbol::RetSymbol, scope}; + transcend->pack(symbRet, hintBlockDecl + ":[ret]"); + } - ++arg; ++tag; - } + for(const std::string& binding : scope->__bindings) { + Symbol bindingSymb{scope->getSymbol(binding), scope}; + SymbolPacked bindingSymbP=transcend->pack(bindingSymb, binding); - //TODO represent RET connection -// Expression retTag = *scheme.getOperands().begin(); -// if (retTag.__state != Expression::INVALID) { -// __context.graph->addAnnotation(node, move(retTag)); -// } + getSymbolCache().setCachedValue(bindingSymb, SymbolNode(bindingSymbP)); + processAnnotations(scope->getDefinition(bindingSymb), context, SymbolNode(bindingSymbP)); } -} -void -DFAPass::applyInPlaceAnnotations(const Expression& expression, PassContext context, ExpressionCache& cache, const std::string& decl){ - // write down in-place expression tags: - for (pair tag: expression.tags) { - __context.graph->addAnnotation(cache.result, Expression(tag.second)); - } + return AbstractPass::process(scope, context, hintBlockDecl); } -void -DFAPass::run() -{ - init(); - return AbstractPass::run(); +SymbolNode +DFAPass::process(ManagedFnPtr function) { + transcend->pack(Symbol{ScopedSymbol::RetSymbol, function->getEntryScope()}, function->getName()+to_string(function.id())+":[ret]"); + SymbolNode result=AbstractPass::process(function); + + graph->printFunctionRet(function, result); + return result; } void -DFAPass::init() -{ - for (const Expression& scheme: man->root->__dfadata) - { - __signatures.emplace(scheme.op, scheme); - } -} +DFAPass::finish() { + transcend->registerReport(graph); + + //Declare symbols: + graph->printSymbols(transcend); -void DFAPass::finish() -{ - man->clasp->setDFAData(move(__context.graph)); + AbstractPass::finish(); } -template<> -SymbolNode defaultValue(){return SymbolInvalid();}; +} //end of namespace dfa +template<> +SymbolNode +defaultValue() { + assert(false); } +} //end of xreate namespace + +/** + * \class xreate::dfa::DFAPass + * \details Provides DFA, important analysis for reasoning. Iterates over AST and stores collected data in DFAGraph + */ diff --git a/cpp/src/pass/dfapass.h b/cpp/src/pass/dfapass.h index cc26e8c..0626a26 100644 --- a/cpp/src/pass/dfapass.h +++ b/cpp/src/pass/dfapass.h @@ -1,49 +1,52 @@ -// Data Flow Graph determination pass +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * Author: pgess + * + * dfapass.h + * Data Flow Graph building pass + */ #ifndef DFGPASS_H #define DFGPASS_H #include "abstractpass.h" #include "analysis/dfagraph.h" namespace xreate { + class TranscendLayer; +} -class ClaspLayer; - -class DFAPass : public AbstractPass { +namespace xreate { namespace dfa { + +struct ProcessingCache { + std::vector operands; + std::vector blocks; +}; + +/** \brief Data Flow Analysis Pass(%DFA) */ +class DFAPass: public AbstractPass { public: - xreate::analysis::SymbolNode process(CodeScope* scope, PassContext context, const std::string& hintBlockDecl="") override; - xreate::analysis::SymbolNode process(const Expression& expression, PassContext context, const std::string& varDecl="") override; - DFAPass(PassManager* manager); - - void init(); - void run(); - void finish(); -private: - struct - { - xreate::analysis::DFAGraph* graph; - } __context; - - struct ExpressionCache{ - std::vector operands; - std::vector blocks; - xreate::analysis::SymbolNode result; - }; +protected: + virtual void processAnnotations(const Expression& expression, PassContext context, const SymbolNode& ident); + virtual SymbolNode process(const Expression& expression, PassContext context, const std::string& varDecl="") override; + virtual SymbolNode process(CodeScope* scope, PassContext context, const std::string& hintBlockDecl="") override; + virtual SymbolNode process(ManagedFnPtr function) override; - std::map __signatures; //DFA data for particular operators - ClaspLayer* clasp; + void init(); + void finish() override; - void processCompoundOp(const Expression& expression, PassContext context, ExpressionCache& cache, const std::string& varDecl=""); - void processElementaryOp(const Expression& expression, PassContext context, ExpressionCache& cache, const std::string& varDecl=""); + DFAGraph* graph; + TranscendLayer* transcend; - void applyDependencies(const Expression& expression, PassContext context, ExpressionCache& cache, const std::string& decl); - void applyInPlaceAnnotations(const Expression& expression, PassContext context, ExpressionCache& cache, const std::string& decl); - void applySignatureAnnotations(const Expression& expression, PassContext context, ExpressionCache& cache, const std::string& decl); - void applyStaticAnnotations(const Expression& expression, PassContext context, ExpressionCache& cache, const std::string& decl); -}; +private: + void processCallInstance(const Expression& expr, PassContext context, const SymbolNode& result); + void processDependencies(const SymbolNode& node, const Expression& expression, PassContext context, ProcessingCache& cache); }; +}} //end of xreate::dfa namespace + #endif diff --git a/cpp/src/pass/interpretationpass.cpp b/cpp/src/pass/interpretationpass.cpp index b4d399e..2b440f8 100644 --- a/cpp/src/pass/interpretationpass.cpp +++ b/cpp/src/pass/interpretationpass.cpp @@ -1,406 +1,555 @@ -/* +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * * File: interpretationpass.cpp - * Author: pgess + * Author: pgess * * Created on July 5, 2016, 5:21 PM */ +/** + * \file interpretationpass.h + * \brief Interpretation analysis: determines what parts of code could be interpreted + */ + #include "pass/interpretationpass.h" -#include "compilation/transformations.h" #include +#include #include "ast.h" -//DEBT implement InterpretationPass purely in clasp +//DEBT implement InterpretationPass purely in transcend //DEBT represent InterpretationPass as general type inference using namespace std; -namespace xreate{ - -enum InterpretationQuery{QUERY_INTR_ONLY, QUERY_CMPL_ONLY}; +namespace xreate { template<> +interpretation::InterpretationResolution +defaultValue() { + return interpretation::CMPL_ONLY; +} + +namespace interpretation { + +enum InterpretationQuery { + QUERY_INTR_ONLY, QUERY_CMPL_ONLY +}; + +namespace details { + +template +bool +checkConstraints(InterpretationResolution flag) { + return( (flag==INTR_ONLY&&FLAG_REQUIRED==QUERY_INTR_ONLY) + ||(flag==CMPL_ONLY&&FLAG_REQUIRED==QUERY_CMPL_ONLY)); +} + InterpretationResolution -defaultValue(){ - return CMPL_ONLY; +recognizeTags(const map& tags) { + auto i=tags.find("interpretation"); + if(i==tags.end()){ + return ANY; + } + + assert(i->second.op==Operator::CALL); + const string& cmd=i->second.operands.at(0).getValueString(); + + //TODO make consistent names of annotation and resolution + if(cmd=="force"){ + return INTR_ONLY; + + } else if(cmd=="suppress"){ + return CMPL_ONLY; + } + + return ANY; +} } InterpretationResolution unify(InterpretationResolution flag) { return flag; } template InterpretationResolution unify(FLAG_A flagA, FLAG_B flagB, FLAGS... flags) { - if (flagA== ANY){ + if(flagA==ANY){ return unify(flagB, flags...); } - if (flagB == ANY) { + if(flagB==ANY){ return unify(flagA, flags...); } - assert(flagA == flagB); + assert(flagA==flagB); return flagA; } -namespace detail { - template - bool checkConstraints(InterpretationResolution flag) { - return ( (flag==INTR_ONLY && FLAG_REQUIRED == QUERY_INTR_ONLY) - || (flag==CMPL_ONLY && FLAG_REQUIRED == QUERY_CMPL_ONLY)); - } -} - template -bool checkConstraints(std::vector&& flags) { +bool +checkConstraints(std::vector&& flags) { assert(flags.size()); - InterpretationResolution flag = flags.front(); - return detail::checkConstraints(flag); + InterpretationResolution flag=flags.front(); + return details::checkConstraints(flag); } template -bool checkConstraints(std::vector&& flags) { +bool +checkConstraints(std::vector&& flags) { assert(flags.size()); - InterpretationResolution flag = flags.front(); + InterpretationResolution flag=flags.front(); flags.pop_back(); - if (detail::checkConstraints(flag)){ + if(details::checkConstraints(flag)){ return checkConstraints(move(flags)); } return false; } -namespace details { - InterpretationResolution - recognizeTags(const map& tags){ - auto i = tags.find("interpretation"); - if (i== tags.end()){ - return ANY; - } - - assert(i->second.op == Operator::CALL); - const string& cmd = i->second.operands.at(0).getValueString(); - - //TODO make consistent names of annotation and resolution - if (cmd == "force"){ - return INTR_ONLY; - - } else if (cmd == "suppress"){ - return CMPL_ONLY; - } - - return ANY; - } +bool +InterpretationData::isDefault() const { + return(resolution==ANY&&op==NONE); } - void -recognizeTags(const Expression& e){ +recognizeTags(const Expression& e) { InterpretationData tag{details::recognizeTags(e.tags), NONE}; - Attachments::put(e, tag); + if(!tag.isDefault()) + Attachments::put(e, tag); } InterpretationResolution -recognizeTags(const ManagedFnPtr& f){ +recognizeTags(const ManagedFnPtr& f) { return details::recognizeTags(f->getTags()); } InterpretationPass::InterpretationPass(PassManager* manager) - : AbstractPass(manager) {} +: AbstractPass(manager) { + + Attachments::init(); + Attachments::init(); +} -void InterpretationPass::run(){ - ManagedFnPtr f = man->root->begin(); - auto& visitedSymbols = getSymbolCache(); +void +InterpretationPass::run() { + ManagedFnPtr f=man->root->begin(); + auto& visitedSymbols=getSymbolCache(); - while (f.isValid()) { - const Symbol& symbolFunction{0, f->getEntryScope()}; + while(f.isValid()) { + const Symbol&symbolFunction{ScopedSymbol::RetSymbol, f->getEntryScope()}; - if (!visitedSymbols.isCached(symbolFunction)){ + if(!visitedSymbols.isCached(symbolFunction)){ visitedSymbols.setCachedValue(symbolFunction, process(f)); } ++f; } } InterpretationResolution -InterpretationPass::process(const Expression& expression, PassContext context, const std::string& decl){ +InterpretationPass::process(const Expression& expression, PassContext context, const std::string& decl) { recognizeTags(expression); - InterpretationResolution resolution = ANY; - InterpretationOperator op = NONE; + InterpretationResolution resolution=ANY; + InterpretationOperator opNo=NONE; - switch (expression.__state){ + switch(expression.__state) { - case Expression::NUMBER: - case Expression::STRING: { - break; - } + case Expression::NUMBER: + case Expression::STRING: + { + break; + } - case Expression::IDENT: { - resolution = Parent::processSymbol(expression.getValueString(), context); - break; - } + case Expression::IDENT: + { + resolution=Parent::processSymbol(Attachments::get(expression), context); + break; + } - case Expression::COMPOUND: - break; + case Expression::COMPOUND: + break; - default: { resolution = INTR_ONLY; break;} + default: + { + resolution=CMPL_ONLY; + break; + } } - if (expression.__state == Expression::COMPOUND) - switch(expression.op){ + if(expression.__state==Expression::COMPOUND) + switch(expression.op) { case Operator::EQU: - case Operator::NE: { - InterpretationResolution left = process(expression.operands[0], context); - InterpretationResolution right = process(expression.operands[1], context); + case Operator::NE: + { + InterpretationResolution left=process(expression.operands[0], context); + InterpretationResolution right=process(expression.operands[1], context); - resolution = unify(left, right); + resolution=unify(left, right); break; } - case Operator::LOGIC_AND: { - assert(expression.operands.size() == 1); - resolution = process (expression.operands[0], context); + case Operator::LOGIC_AND: + { + assert(expression.operands.size()==1); + resolution=process(expression.operands[0], context); break; } - case Operator::CALL: { + case Operator::CALL: + { + size_t sizeOperands = expression.operands.size(); + std::vector operands; + operands.reserve(sizeOperands); + + for(size_t opNo=0; opNo callees = man->root->getFunctionVariants(expression.getValueString()); - if (callees.size()!=1){ - resolution = CMPL_ONLY; + //TODO BUG here: if several variants they all are processed as CMPL regardless of signature + list callees=man->root->getFunctionSpecializations(expression.getValueString()); + if(callees.size()!=1){ + resolution=CMPL_ONLY; break; } - ManagedFnPtr callee = callees.front(); - const Symbol& symbCalleeFunc{0, callee->getEntryScope()}; + ManagedFnPtr callee=callees.front(); + const Symbol& symbCalleeFunc{ScopedSymbol::RetSymbol, callee->getEntryScope()}; //recursion-aware processing: // - skip self recursion - const Symbol& symbSelfFunc{0, context.function->getEntryScope()}; - if (!(symbSelfFunc == symbCalleeFunc)){ - InterpretationResolution resCallee = processFnCall(callee, context); - assert(resCallee != FUNC_POSTPONED && "Indirect recursion detected: can't decide on interpretation resolution"); + const Symbol&symbSelfFunc{ScopedSymbol::RetSymbol, context.function->getEntryScope()}; + if(!(symbSelfFunc==symbCalleeFunc)){ + InterpretationResolution resCallee=processFnCall(callee, context); + assert(resCallee!=FUNC_POSTPONED&&"Indirect recursion detected: can't decide on interpretation resolution"); - resolution = unify(resolution, resCallee); + resolution=unify(resolution, resCallee); } //check arguments compatibility - const FunctionInterpretationData& sig = FunctionInterpretationHelper::getSignature(callee); - for (size_t op=0, size = expression.operands.size(); op < size; ++op){ - const Expression &operand = expression.operands[op]; - InterpretationResolution argActual = process(operand, context); - if (argActual == ANY) continue; + const FunctionInterpretationData& calleeSignature=FunctionInterpretationHelper::getSignature(callee); + for(size_t opNo=0; opNo__identifiers.at(argName), versions::VERSION_NONE}, + exprBody + }; + getSymbolCache().setCachedValue(argS, INTR_ONLY); + Parent::process(expression.blocks.front(), context); + + resolution = CMPL_ONLY; + opNo=QUERY_LATE; + break; + } + + case Operator::SWITCH_LATE: + { + resolution = CMPL_ONLY; + opNo = SWITCH_LATE; + break; + } + + case Operator::IF: + { + InterpretationResolution flagCondition=process(expression.getOperands()[0], context); + InterpretationResolution flagScope1=Parent::process(expression.blocks.front(), context); + InterpretationResolution flagScope2=Parent::process(expression.blocks.back(), context); //special case: IF_INTERPRET_CONDITION - if (checkConstraints({flagCondition})){ - op= IF_INTERPRET_CONDITION; - flagCondition = ANY; + if(checkConstraints({flagCondition})){ + opNo=IF_INTERPRET_CONDITION; + flagCondition=ANY; } - resolution = unify(flagCondition, flagScope1, flagScope2); + resolution=unify(flagCondition, flagScope1, flagScope2); break; } - case Operator::FOLD: { - InterpretationResolution flagInput = process(expression.getOperands()[0], context); - InterpretationResolution flagAccumInit = process(expression.getOperands()[1], context); + case Operator::FOLD: + { + InterpretationResolution flagInput=process(expression.getOperands()[0], context); + InterpretationResolution flagAccumInit=process(expression.getOperands()[1], context); - CodeScope* scopeBody = expression.blocks.front(); - const std::string& nameEl = expression.bindings[0]; - getSymbolCache().setCachedValue(scopeBody->findSymbol(nameEl), InterpretationResolution(flagInput)); + CodeScope* scopeBody=expression.blocks.front(); + const std::string& nameEl=expression.bindings[0]; + Symbol symbEl{ScopedSymbol + {scopeBody->__identifiers.at(nameEl), versions::VERSION_NONE}, scopeBody}; + getSymbolCache().setCachedValue(symbEl, InterpretationResolution(flagInput)); - const std::string& nameAccum = expression.bindings[1]; - getSymbolCache().setCachedValue(scopeBody->findSymbol(nameAccum), InterpretationResolution(flagAccumInit)); + const std::string& nameAccum=expression.bindings[1]; + Symbol symbAccum{ScopedSymbol + {scopeBody->__identifiers.at(nameAccum), versions::VERSION_NONE}, scopeBody}; + getSymbolCache().setCachedValue(symbAccum, InterpretationResolution(flagAccumInit)); - InterpretationResolution flagBody = Parent::process(expression.blocks.front(), context); + InterpretationResolution flagBody=Parent::process(expression.blocks.front(), context); //special case: FOLD_INTERPRET_INPUT - if (checkConstraints({flagInput})){ - op= FOLD_INTERPRET_INPUT; - flagInput = ANY; + if(checkConstraints({flagInput})){ + opNo=FOLD_INTERPRET_INPUT; + flagInput=ANY; } - resolution = unify(flagInput, flagAccumInit, flagBody); + resolution=unify(flagInput, flagAccumInit, flagBody); break; } - case Operator::INDEX: { - resolution = unify( - process(expression.operands[0], context), - Parent::processSymbol(expression.getValueString(), context) - ); + case Operator::INDEX: + { + for(const Expression &opNo : expression.getOperands()) { + resolution=unify(resolution, process(opNo, context)); + } break; } - case Operator::SWITCH: { - InterpretationResolution flagCondition = process(expression.operands[0], context); - bool hasDefaultCase = expression.operands[1].op == Operator::CASE_DEFAULT; + case Operator::SWITCH: + { + InterpretationResolution flagCondition=process(expression.operands[0], context); + bool hasDefaultCase=expression.operands[1].op==Operator::CASE_DEFAULT; //determine conditions resolution - InterpretationResolution flagHeaders = flagCondition; - for (size_t size = expression.operands.size(), i= hasDefaultCase? 2: 1; i({flagHeaders})){ - op= SWITCH_INTERPRET_CONDITION; - flagHeaders = ANY; + if(checkConstraints({flagHeaders})){ + opNo=SWITCH_INTERPRET_CONDITION; + flagHeaders=ANY; } //determine body resolutions - resolution = flagHeaders; - for (size_t size = expression.operands.size(), i= 1; i({resolution})){ + opNo=SWITCH_VARIANT; + resolution=ANY; + } + + const string identCondition=expression.bindings.front(); + for(auto scope : expression.blocks) { + //set binding resolution + ScopedSymbol symbolInternal=scope->getSymbol(identCondition); + getSymbolCache().setCachedValue(Symbol{symbolInternal, scope}, InterpretationResolution(resolutionCondition)); + + resolution=unify(resolution, Parent::process(scope, context)); } + for(auto scope : expression.blocks) { + resolution=unify(resolution, Parent::process(scope, context)); + } break; } - default: { - resolution = CMPL_ONLY; - Parent::process(expression, context, decl); + case Operator::LIST: + case Operator::LIST_NAMED: + { + for(const Expression &opNo : expression.getOperands()) { + resolution=unify(resolution, process(opNo, context)); + } + break; } - } - InterpretationResolution resolutionExpected = Attachments::get(expression, {ANY, NONE}) - .resolution; + case Operator::VARIANT: + { + if(expression.getOperands().size()){ + resolution=process(expression.getOperands().front(), context); + } else { + resolution=ANY; + } - resolution = unify(resolution, resolutionExpected); - if (op!=NONE || resolution == INTR_ONLY ){ - Attachments::put(expression, {resolution, op}); - } + break; + } - if (resolution == INTR_ONLY){ - compilation::Transformations::subscribe(expression); - } + default: + { + resolution=CMPL_ONLY; - return resolution; -} + for(const Expression &opNo : expression.getOperands()) { + process(opNo, context); + } - InterpretationResolution - InterpretationPass::processFnCall(ManagedFnPtr function, PassContext context){ - const Symbol& symbolFunction{0, function->getEntryScope()}; - auto& visitedSymbols = getSymbolCache(); + for(CodeScope* scope : expression.blocks) { + Parent::process(scope, context); + } - if (visitedSymbols.isCached(symbolFunction)) - return visitedSymbols.getCachedValue(symbolFunction); + break; + } + } - PassContext context2; - context2.function = function; + InterpretationData dataExpected= + Attachments::get(expression,{ANY, NONE}); - return visitedSymbols.setCachedValue(symbolFunction, - Parent::process(function->getEntryScope(), context2)); + resolution=unify(resolution, dataExpected.resolution); + if(resolution!=dataExpected.resolution || opNo != dataExpected.op ){ + Attachments::put(expression,{resolution, opNo}); } - InterpretationResolution - InterpretationPass::process(ManagedFnPtr function){ - CodeScope* entry = function->getEntryScope(); - std::vector arguments = entry->__bindings; - const Symbol& symbSelfFunc{0, function->getEntryScope()}; - auto& cache = getSymbolCache(); + return resolution; +} - const FunctionInterpretationData& dataIntrpr = FunctionInterpretationHelper::getSignature(function); - InterpretationResolution resExpected = details::recognizeTags(function->getTags()); +InterpretationResolution +InterpretationPass::processFnCall(ManagedFnPtr function, PassContext context) { + return process(function); +} - //mark preliminary function resolution as expected - if (resExpected != ANY){ - cache.setCachedValue(symbSelfFunc, move(resExpected)); +InterpretationResolution +InterpretationPass::process(ManagedFnPtr function) { + CodeScope* entry=function->getEntryScope(); + std::vector arguments=entry->__bindings; + const Symbol&symbSelfFunc{ScopedSymbol::RetSymbol, function->getEntryScope()}; + auto& cache=getSymbolCache(); - } else { - // - in order to recognize indirect recursion mark this function resolution as POSTPONED - cache.setCachedValue(symbSelfFunc, FUNC_POSTPONED); - } + if(cache.isCached(symbSelfFunc)) + return cache.getCachedValue(symbSelfFunc); - //set resolution for function arguments as expected - for (int argNo = 0, size = arguments.size(); argNo< size; ++argNo){ - Symbol symbArg = entry->findSymbol(arguments[argNo]); - cache.setCachedValue(symbArg, InterpretationResolution(dataIntrpr.signature[argNo])); - } + const FunctionInterpretationData& fnSignature=FunctionInterpretationHelper::getSignature(function); + InterpretationResolution fnResolutionExpected=details::recognizeTags(function->getTags()); - InterpretationResolution resActual = Parent::process(function); - return unify(resActual, resExpected); + //mark preliminary function resolution as expected + if(fnResolutionExpected!=ANY){ + cache.setCachedValue(symbSelfFunc, move(fnResolutionExpected)); + + } else { + // - in order to recognize indirect recursion mark this function resolution as POSTPONED + cache.setCachedValue(symbSelfFunc, FUNC_POSTPONED); } - const FunctionInterpretationData - FunctionInterpretationHelper::getSignature(ManagedFnPtr function){ - const Symbol& symbFunc{0, function->getEntryScope()}; + //set resolution for function arguments as expected + for(int argNo=0, size=arguments.size(); argNo__identifiers.at(arguments[argNo]), versions::VERSION_NONE}, entry}; + cache.setCachedValue(symbArg, InterpretationResolution(fnSignature.signature[argNo])); + } - if (Attachments::exists(symbFunc)){ - return Attachments::get(symbFunc); - } + PassContext context; + context.function=function; + context.scope=entry; + InterpretationResolution resActual=process(CodeScope::getDefinition(symbSelfFunc), context); + resActual=unify(resActual, fnResolutionExpected); + return cache.setCachedValue(symbSelfFunc, move(resActual)); +} - FunctionInterpretationData&& data = recognizeSignature(function); - Attachments::put(symbFunc, data); - return data; +const FunctionInterpretationData +FunctionInterpretationHelper::getSignature(ManagedFnPtr function) { + if(Attachments::exists(function)){ + return Attachments::get(function); } - FunctionInterpretationData - FunctionInterpretationHelper::recognizeSignature(ManagedFnPtr function){ - CodeScope* entry = function->__entry; - FunctionInterpretationData result; - result.signature.reserve(entry->__bindings.size()); + FunctionInterpretationData&& data=recognizeSignature(function); + Attachments::put(function, data); + return data; +} - bool flagPartialInterpretation = false; - for(size_t no=0, size=entry->__bindings.size(); no < size; ++no){ - const std::string& argName = entry->__bindings[no]; - const Expression& arg = entry->findDeclaration(entry->findSymbol(argName)); +FunctionInterpretationData +FunctionInterpretationHelper::recognizeSignature(ManagedFnPtr function) { + CodeScope* entry=function->__entry; + FunctionInterpretationData result; + result.signature.reserve(entry->__bindings.size()); - InterpretationResolution argResolution = details::recognizeTags(arg.tags); - flagPartialInterpretation |= (argResolution == INTR_ONLY); + bool flagPartialInterpretation=false; + for(size_t no=0, size=entry->__bindings.size(); no__bindings[no]; + Symbol symbArg{ScopedSymbol + {entry->__identifiers.at(argName), versions::VERSION_NONE}, entry}; - result.signature.push_back(argResolution); - } - result.flagPartialInterpretation = flagPartialInterpretation; - return result; - } + const Expression& arg=CodeScope::getDefinition(symbArg); - bool FunctionInterpretationHelper::needPartialInterpretation(ManagedFnPtr function){ - const FunctionInterpretationData& data = getSignature(function); - return data.flagPartialInterpretation; + InterpretationResolution argResolution=details::recognizeTags(arg.tags); + flagPartialInterpretation|=(argResolution==INTR_ONLY); + + result.signature.push_back(argResolution); } + result.flagPartialInterpretation=flagPartialInterpretation; + return result; } -//if (res != INTR_ONLY){ -// argumentsActual.insert(no); -//} +bool +FunctionInterpretationHelper::needPartialInterpretation(ManagedFnPtr function) { + const FunctionInterpretationData& data=getSignature(function); + return data.flagPartialInterpretation; +} +} +} //end of namespace xreate::interpretation +/** \class xreate::interpretation::InterpretationPass + * + * Encapsulates *Interpretation Analysis* to support [Interpretation Concept](/w/concepts/dfa) + * + * Recognizes program functions, expressions, instructions eligible for interpretation + * and stores output in Attachments and Attachments + * + * There are number of instructions currently able to be interpreted: + * - Basic literals: numbers and strings + * - Compounds: lists, structs, variants + * - Non-versioned identifiers + * - Comparison and logic operators + * - %Function calls + * - `query` intrinsic function calls + * - Branching: `if`, `loop fold`, `switch`, `switch variant` statements + * + * Some of those instructions are eligibile for *late interpretation* to allow coupling + * of compiled instructions with interpreted ones, those are: + * - Partial function calls + * - Branching: `if`, `loop fold`, `switch`, `switch variant` statements + * + * \sa xreate::interpretation::TargetInterpretation, [Interpretation Concept](/w/concepts/dfa) + */ diff --git a/cpp/src/pass/interpretationpass.h b/cpp/src/pass/interpretationpass.h index 0d6ba84..1f47aa2 100644 --- a/cpp/src/pass/interpretationpass.h +++ b/cpp/src/pass/interpretationpass.h @@ -1,78 +1,96 @@ -/* +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * * File: interpretationpass.h - * Author: pgess + * Author: pgess * * Created on July 5, 2016, 5:21 PM */ #ifndef INTERPRETATIONPASS_H #define INTERPRETATIONPASS_H #include "abstractpass.h" #include -namespace xreate { - + +#ifndef FRIENDS_INTERPRETATION_TESTS +#define FRIENDS_INTERPRETATION_TESTS +#endif + +//TODO refactor interpretation. Get rid of InterpretationOperator, put only one operator - Hybrid/Late. + +namespace xreate{ namespace interpretation{ enum InterpretationResolution{ANY, INTR_ONLY, CMPL_ONLY, FUNC_POSTPONED}; - enum InterpretationOperator{NONE, IF_INTERPRET_CONDITION, FOLD_INTERPRET_INPUT, SWITCH_INTERPRET_CONDITION, CALL_INTERPRET_PARTIAL}; - + enum InterpretationOperator{ + NONE, IF_INTERPRET_CONDITION, FOLD_INTERPRET_INPUT, QUERY_LATE, + SWITCH_INTERPRET_CONDITION, SWITCH_VARIANT, SWITCH_LATE, + CALL_INTERPRET_PARTIAL + }; + struct InterpretationData{ InterpretationResolution resolution; InterpretationOperator op; + + bool isDefault() const; }; - template<> - InterpretationResolution - defaultValue(); - struct FunctionInterpretationData{ typedef std::vector Signature; Signature signature; bool flagPartialInterpretation; }; - template<> - struct AttachmentsDict - { - typedef FunctionInterpretationData Data; - static const unsigned int key = 5; - }; - class FunctionInterpretationHelper { public: static const FunctionInterpretationData getSignature(ManagedFnPtr function); static bool needPartialInterpretation(ManagedFnPtr function); private: static FunctionInterpretationData recognizeSignature(ManagedFnPtr function); }; - - template<> - struct AttachmentsDict - { - typedef InterpretationData Data; - static const unsigned int key = 3; - }; - + +/** \brief Determines parts of program eligible for Interpretation. */ class InterpretationPass: public AbstractPass { typedef AbstractPass Parent; public: InterpretationResolution process(const Expression& expression, PassContext context, const std::string& varDecl="") override; InterpretationResolution process(ManagedFnPtr function); InterpretationResolution processFnCall(ManagedFnPtr function, PassContext context); InterpretationPass(PassManager* manager); void run(); }; namespace details { InterpretationResolution recognizeTags(const std::map& tags); } -} +} //end of namespace interpretation + +template<> +interpretation::InterpretationResolution +defaultValue(); + +template<> +struct AttachmentsDict +{ + typedef interpretation::FunctionInterpretationData Data; + static const unsigned int key = 5; +}; + +template<> +struct AttachmentsDict +{ + typedef interpretation::InterpretationData Data; + static const unsigned int key = 3; +}; + +} //end of namespace xreate #endif /* INTERPRETATIONPASS_H */ diff --git a/cpp/src/pass/latereasoningpass.h b/cpp/src/pass/latereasoningpass.h new file mode 100644 index 0000000..6a9cde0 --- /dev/null +++ b/cpp/src/pass/latereasoningpass.h @@ -0,0 +1,182 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +/* + * Author: pgess + * Created on June 7, 2018, 7:20 PM + * + * \file latereasoningpass.h + * \brief latereasoningpass + */ + +#ifndef LATEREASONINGPASS_H +#define LATEREASONINGPASS_H + +#include "pass/dfapass.h" + +namespace xreate { namespace latereasoning { + +class LateReasoningScope{ +public: + LateReasoningScope(LateReasoningScope* parent): __parent(parent){ } + + boost::optional + recognizeIdentifier(const std::string& identifier){ + + //Search identifier in the current scope + if(__identifiers.count(identifier)){ + return make_pair(identifier, __identifiers.at(identifier)); + } + + //Search in the parent scope + if(__parent){ + return __parent->recognizeIdentifier(identifier); + } + + return boost::none; + } + + void + addIdentifier(std::string idenName, const SymbolPacked& identSymbol){ + __identifiers.emplace(idenName, identSymbol); + } + +private: + std::map __identifiers; + LateReasoningScope *__parent; +}; + +/** + * \note Limitation: Produces late annotation with target as a symbol to which annotation is attached + */ +template +class LateReasoningDFAPassDecorator: public Parent{ +public: + LateReasoningDFAPassDecorator(PassManager* manager): Parent(manager){ } + + void + registerLateScope(CodeScope* scope, LateReasoningScope* scopeLate){ + __dictScopes.emplace(scope, scopeLate); + } + +private: + LateReasoningScope* + liftScope(const CodeScope* scope){ + while(scope){ + if(__dictScopes.count(scope)) return __dictScopes.at(scope); + scope = scope->__parent; + } + + return nullptr; + } + + std::list + recognizeLateIdentifiers(const Expression& expression, LateReasoningScope* scope){ + std::list result; + + switch(expression.op){ + case Operator::CALL: + { + for(const auto& op: expression.operands){ + std::list opResult = recognizeLateIdentifiers(op, scope); + result.insert(result.end(), opResult.begin(), opResult.end()); + } + + if(!expression.operands.size()){ + if(auto symbolRecognized = scope->recognizeIdentifier(expression.getValueString())){ + result.push_back(*symbolRecognized); + } + } + break; + } + + case Operator::NEG: + { + assert(expression.operands.size() == 1); + + const Expression &op = expression.operands.at(0); + std::list opResult = recognizeLateIdentifiers(op, scope); + result.insert(result.end(), opResult.begin(), opResult.end()); + }; + + case Operator::INVALID: + { + switch(expression.__state){ + case Expression::NUMBER: + break; + + default: + assert(true); + } + break; + } + + default: break; + } + + return result; + } + +protected: + virtual SymbolNode process(const Expression& expression, PassContext context, const std::string& varDecl="") override{ + if(expression.__state == Expression::COMPOUND && expression.op == Operator::SWITCH_LATE){ + //Reserve late scope: + LateReasoningScope* scopeLate = new LateReasoningScope(liftScope(context.scope)); + CodeScope* scopeBody = expression.blocks.front(); + registerLateScope(scopeBody, scopeLate); + + //Assign late identifiers + for(const std::string& identLate: expression.bindings){ + ScopedSymbol identLateS = scopeBody->getSymbol(identLate); + SymbolPacked identLateSP = Parent::man->transcend->pack(Symbol{identLateS, scopeBody}); + + scopeLate->addIdentifier(identLate, identLateSP); + } + } + + return Parent::process(expression, context, varDecl); + } + + virtual void + processAnnotations(const Expression& expression, + PassContext context, + const SymbolNode& ident){ + + LateReasoningScope* scopeLate = liftScope(context.scope); + + if(!expression.tags.size() || !scopeLate) + return Parent::processAnnotations(expression, context, ident); + + for(const std::pair& tag: expression.tags){ + std::list symbols = recognizeLateIdentifiers(tag.second, scopeLate); + if(!symbols.size()){ + //Standard compilation + Parent::graph->printInplaceAnnotation(ident, tag.second); + + } else{ + //Late compilation + std::list domains; + for(const auto& symbol: symbols){ + Symbol symbolUnpacked = Parent::man->transcend->unpack(symbol.second); + ExpandedType typSymbol = Parent::man->root->getType(CodeScope::getDefinition(symbolUnpacked)); + assert(typSymbol->__operator == TypeOperator::SLAVE); + + domains.push_back(typSymbol->__valueCustom); + } + + Parent::graph->printLateAnnotation(ident, tag.second, symbols, domains); + } + } + } + +private: + std::unordered_map __dictScopes; +}; + +}} + +#endif /* LATEREASONINGPASS_H */ + diff --git a/cpp/src/pass/loggerpass.cpp b/cpp/src/pass/loggerpass.cpp deleted file mode 100644 index f4471c8..0000000 --- a/cpp/src/pass/loggerpass.cpp +++ /dev/null @@ -1,108 +0,0 @@ -/* - * logging.cpp - * - * Created on: Jun 23, 2015 - * Author: pgess - */ - -#include -#include "compilation/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)); - - Attachments::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 (Attachments::get(v, false)){ - compilation::FunctionUnit* func = compiler->getFunctionUnit(context.function); - compilation::CodeScopeUnit* scope = func->getScopeUnit(context.scope); - - compilation::Context compilationContext{scope, func, compiler}; - inject(v, compilationContext); - } - } - - return AbstractPass::process(expression, context, varDecl); -} - -void LoggerPass::inject(const Symbol& symbol, const compilation::Context& context){ - //TODO fix log injection - -// llvm::Value* source = context.scope->compileSymbol(symbol); -// ExpandedType typSource = man->root->expandType(CodeScope::findDefinition(symbol).type); -// 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"); -// } -// -// xreate::compilation::Advanced instructions(context); -// -// LLVMLayer* llvm = context.pass->man->llvm; -// llvm->builder.SetInsertPoint(llvm->builder.GetInsertBlock(), *source->use_begin()); -// llvm::Value* formatRaw = instructions.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 deleted file mode 100644 index 252e9c8..0000000 --- a/cpp/src/pass/loggerpass.h +++ /dev/null @@ -1,44 +0,0 @@ -/* - * 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 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 = 2; -}; - -} /* namespace xreate */ - -#endif /* SRC_LOGGING_H_ */ diff --git a/cpp/src/pass/rulespass.cpp b/cpp/src/pass/rulespass.cpp deleted file mode 100644 index a30c100..0000000 --- a/cpp/src/pass/rulespass.cpp +++ /dev/null @@ -1,16 +0,0 @@ -#include "rulespass.h" - -using namespace xreate; - -RulesPass::RulesPass(PassManager* manager) - : ASTPass(manager) -{ - man->registerFilter(this, PassFilter::RULE); -} - -void -RulesPass::process(MetaRuleAbstract* rule, PassContext context) -{ - rule->compile(*man->clasp); -} - diff --git a/cpp/src/pass/rulespass.h b/cpp/src/pass/rulespass.h deleted file mode 100644 index fefd760..0000000 --- a/cpp/src/pass/rulespass.h +++ /dev/null @@ -1,13 +0,0 @@ -#ifndef RULESPASS_H -#define RULESPASS_H -#include "passmanager.h" - -namespace xreate { -class RulesPass : public ASTPass -{ -public: - void process(MetaRuleAbstract* rule, PassContext context); - RulesPass(PassManager* manager); -}; } - -#endif // RULESPASS_H diff --git a/cpp/src/pass/versionspass.cpp b/cpp/src/pass/versionspass.cpp new file mode 100644 index 0000000..8129686 --- /dev/null +++ b/cpp/src/pass/versionspass.cpp @@ -0,0 +1,376 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * versionspass.cpp + * + * Author: pgess + * Created on January 4, 2017, 3:13 PM + */ + +/** \class xreate::versions::VersionsPass + * Has two parts: + * - Validates correctness of versioned variables with regard to variables lifespan + * - Determines versioned variables computation order + * \sa VersionsScopeDecorator, VersionsGraph, [Versions Concept](/w/concepts/versions) + */ + +#include +#include "pass/versionspass.h" + +namespace std{ + std::size_t + hash::operator()(xreate::versions::SymbolOrPlaceholder const& s) const + {return std::hash()(s.symbol) + (s.flagEndOfLifePlaceholder? 9849 : 1);} + + bool + equal_to::operator()(const xreate::versions::SymbolOrPlaceholder& __x, const xreate::versions::SymbolOrPlaceholder& __y) const + { return __x.flagEndOfLifePlaceholder == __y.flagEndOfLifePlaceholder && __x.symbol == __y.symbol; } +} + +using namespace std; + +namespace xreate { + template<> + std::list + defaultValue>(){ + return std::list(); + }; +} +namespace xreate{ namespace versions{ + +inline std::string +printSymbol(const SymbolOrPlaceholder& s){ + switch(s.flagEndOfLifePlaceholder){ + case SYMBOL: return string("(") + std::to_string(s.symbol.identifier.id) + ", "+ std::to_string(s.symbol.identifier.version) + ")"; + case PLACEHOLDER: return string("(") + std::to_string(s.symbol.identifier.id) + ", "+ std::to_string(s.symbol.identifier.version) + ")+"; + } + + return ""; +} + +void +VersionsGraph::__debug_print(std::ostream& output) const{ + for(auto entry: __inferiors){ + output << printSymbol(entry.second) << " <-" << printSymbol(entry.first) << "\n"; + } +} + +void +VersionsGraph::defineEndOfLife(const Symbol& symbol, const Symbol& symbolSuccessor){ + if(__dictSuccessors.count(symbol)){ + assert("No version branches allowed yet" && false); + } + + const SymbolOrPlaceholder& placeholder = getEndOfLife(symbol); + + auto inferiorsDeferred = __inferiors.equal_range(placeholder); + std::unordered_multimap inferiorsReassigned; + + for (const auto& inf: boost::make_iterator_range(inferiorsDeferred)){ + inferiorsReassigned.emplace(SymbolOrPlaceholder{SYMBOL, symbolSuccessor}, inf.second); + } + + __inferiors.erase(placeholder); + __inferiors.insert(inferiorsReassigned.begin(), inferiorsReassigned.end()); + __inferiors.emplace(SymbolOrPlaceholder{SYMBOL, symbolSuccessor}, SymbolOrPlaceholder{SYMBOL, symbol}); + + __dictSuccessors.emplace(symbol, symbolSuccessor); +} + +SymbolOrPlaceholder +VersionsGraph::getEndOfLife(const Symbol& s){ + if (__dictSuccessors.count(s)){ + return SymbolOrPlaceholder{SYMBOL, __dictSuccessors.at(s)}; } + + + return SymbolOrPlaceholder{PLACEHOLDER, s}; +} + +void +VersionsGraph::applyNatualDependencies(const Symbol& symbol, const std::list& dependencies){ + for (const Symbol& right: dependencies){ + __inferiorsNatural.emplace(symbol, right); + } +} + +void +VersionsGraph::applyDependentEndOfLife(const SymbolOrPlaceholder& symbol, const list& dependencies){ + for (const Symbol& right: dependencies){ + auto rightEOF = getEndOfLife(right); + + __inferiors.emplace(rightEOF, symbol); + } +} + +bool +VersionsGraph::tryEliminateEofAliases(const std::list& aliases){ + + if (aliases.size()==1){ + return true; + } + + boost::optional symbolActualEoF; + for(const SymbolOrPlaceholder alias: aliases){ + switch(alias.flagEndOfLifePlaceholder){ + case SYMBOL: + if(symbolActualEoF){ + return false; + } + + symbolActualEoF = alias.symbol; + break; + + case PLACEHOLDER: + continue; + } + } + + if(!symbolActualEoF){ + return false; + } + + for(const SymbolOrPlaceholder alias: aliases){ + switch(alias.flagEndOfLifePlaceholder){ + case SYMBOL: + continue; + + case PLACEHOLDER: + defineEndOfLife(alias.symbol, symbolActualEoF.get()); + break; + } + } + + return true; +} + +std::list +VersionsGraph::extractCycle(const Path& path, const SymbolOrPlaceholder& symbolBeginning){ + unsigned int posBeginning = path.at(symbolBeginning); + + std::list result; + + auto i=path.begin(); + while(true){ + i = std::find_if(i, path.end(), [&posBeginning](const auto& el){return el.second >=posBeginning;}); + + if (i!= path.end()){ + result.push_back(i->first); + ++i; + + } else {break; } + } + + return result; +} + +bool +VersionsGraph::validateCycles(const SymbolOrPlaceholder& s, + std::unordered_multimap& graph, + std::unordered_set& symbolsVisited, + Path& path) +{ + if (symbolsVisited.count(s)) return true; + + symbolsVisited.insert(s); + path.emplace(s, path.size()); + + if (graph.count(s)){ + //iterate over imposed dependencies + auto candidates = graph.equal_range(s); + for (auto candidate = candidates.first; candidate != candidates.second; ++candidate){ + if (path.count(candidate->second)) { + std::list cycle = extractCycle(path, candidate->second); + if (!tryEliminateEofAliases(cycle)) return false; + continue; + } + + if(!validateCycles(candidate->second, graph, symbolsVisited, path)) return false; + } + } + + //iterate over natural dependencies + if (s.flagEndOfLifePlaceholder == SYMBOL) { + auto candidates = __inferiorsNatural.equal_range(s.symbol); + for (auto candidate = candidates.first; candidate != candidates.second; ++candidate){ + if (path.count(SymbolOrPlaceholder{SYMBOL, candidate->second})){ + return false; + } + + if(!validateCycles(SymbolOrPlaceholder{SYMBOL,candidate->second}, graph, symbolsVisited, path)) return false; + } + } + + //check previous version + if (s.flagEndOfLifePlaceholder == PLACEHOLDER){ + const Symbol& candidate = s.symbol; + + if (path.count(SymbolOrPlaceholder{SYMBOL, candidate})){ + std::list cycle = extractCycle(path, SymbolOrPlaceholder{SYMBOL, candidate}); + if (!tryEliminateEofAliases(cycle)) return false; + } + + if(!validateCycles(SymbolOrPlaceholder{SYMBOL,candidate}, graph, symbolsVisited, path)) return false; + } + + path.erase(s); + return true; +} + +bool +VersionsGraph::validateCycles(){ + std::unordered_set symbolsVisited; + Path path; + std::unordered_multimap graph(__inferiors); + + std::unordered_multimap::const_iterator s; + for (s = graph.begin(); s != graph.end(); ++s){ + if(!validateCycles(s->first, graph, symbolsVisited, path)) return false; + } + + return true; +} + +bool +VersionsGraph::validate(){ + return validateCycles(); +} + +std::list +VersionsGraph::expandPlaceholder(const SymbolOrPlaceholder& symbol, const Symbol& symbolPrev) const{ + std::list result; + + switch (symbol.flagEndOfLifePlaceholder){ + case SYMBOL: + //skip self-loops + if (symbol.symbol == symbolPrev) return {}; + + return {symbol.symbol}; + + case PLACEHOLDER: + for (const auto& entry: boost::make_iterator_range(__inferiors.equal_range(symbol))){ + list&& childResult = expandPlaceholder(entry.second, symbolPrev); + result.insert(result.end(), childResult.begin(), childResult.end()); + } + + if (__dictSuccessors.count(symbol.symbol)){ + Symbol knownSuccessor = __dictSuccessors.at(symbol.symbol); + + //skip alias loop + if (knownSuccessor == symbolPrev) return {}; + + for (const auto& entry: boost::make_iterator_range(__inferiors.equal_range(SymbolOrPlaceholder{SYMBOL, knownSuccessor}))){ + list&& childResult = expandPlaceholder(entry.second, knownSuccessor); + result.insert(result.end(), childResult.begin(), childResult.end()); + } + } + + break; + } + + return result; +} + +AttachmentsContainerDefault>* +VersionsGraph::representAsAttachments() const { + AttachmentsContainerDefault>* container = new AttachmentsContainerDefault>(); + + std::map> containerData; + + for(const auto& entry: __inferiors){ + if(entry.first.flagEndOfLifePlaceholder == PLACEHOLDER) continue; + + list& infs = containerData[entry.first.symbol]; + list&& infsExpanded = expandPlaceholder(entry.second, entry.first.symbol); + infs.insert(infs.begin(), infsExpanded.begin(), infsExpanded.end()); + } + + for(const auto& entry: containerData){ + container->put(entry.first, entry.second); + } + + return container; +} + +std::list +VersionsPass::process(const Expression& expression, PassContext context, const std::string& hintSymbol){ + if (expression.__state == Expression::COMPOUND){ + std::list resultDependencies; + + for (const Expression &op: expression.getOperands()) { + std::list deps = process(op, context); + + resultDependencies.insert(resultDependencies.end(), deps.begin(), deps.end()); + } + + for (CodeScope* scope: expression.blocks) { + std::list deps = Parent::process(scope, context); + + resultDependencies.insert(resultDependencies.end(), deps.begin(), deps.end()); + } + + return resultDependencies; + } + + if (expression.__state == Expression::IDENT){ + const Symbol symb = Attachments::get(expression); + + return processSymbol(symb, context, expression.getValueString()); + } + + return {}; +} + +//TODO versions, check (declaration.isDefined()) before processing declaration +list +VersionsPass::processSymbol(const Symbol& symbol, PassContext context, const std::string& hintSymbol){ + list result{symbol}; + + if (__symbolsVisited.exists(symbol)){ + return result; + } + enum {MODE_ALIAS, MODE_COPY } mode = MODE_ALIAS; + + const Expression& declaration = CodeScope::getDefinition(symbol); + + if (declaration.op == Operator::CALL_INTRINSIC){ + if (declaration.getValueString() == "copy"){ + mode = MODE_COPY; + } + } + + if (symbol.identifier.version != VERSION_NONE){ + mode = MODE_COPY; + + if (symbol.identifier.version > 0){ + Symbol versionPrev = Symbol{ScopedSymbol{symbol.identifier.id, symbol.identifier.version-1}, symbol.scope}; + __graph.defineEndOfLife(versionPrev, symbol); + } + } + + PassContext context2 = context.updateScope(symbol.scope); + std::list dependencies = process(declaration, context2, hintSymbol); + + switch (mode) { + case MODE_COPY: __graph.applyDependentEndOfLife(SymbolOrPlaceholder{SYMBOL, symbol}, dependencies); break; + case MODE_ALIAS: __graph.applyDependentEndOfLife(__graph.getEndOfLife(symbol), dependencies); break; + } + + __graph.applyNatualDependencies(symbol, dependencies); + __symbolsVisited.put(symbol, true); + return list{symbol}; +} + +VersionsGraph& +VersionsPass::getResultGraph(){ + return __graph; +} + +void +VersionsPass::finish(){ + assert(__graph.validate() && "Can't validate versions graph"); + + Attachments::init(__graph.representAsAttachments()); +} + +}} //end of namespace xreate::versions diff --git a/cpp/src/pass/versionspass.h b/cpp/src/pass/versionspass.h new file mode 100644 index 0000000..2ce01b6 --- /dev/null +++ b/cpp/src/pass/versionspass.h @@ -0,0 +1,119 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * File: versionspass.h + * Author: v.melnychenko@xreate.org + * + * Created on January 4, 2017, 3:09 PM + */ + +/** + * \file versionspass.h + * \brief Versions analysis: validates versioned variables' usage and lifespan + */ + +#ifndef VERSIONSPASS_H +#define VERSIONSPASS_H + +#include "pass/abstractpass.h" +#include +#include + +namespace xreate { namespace versions { + struct SymbolOrPlaceholder; +}} + +namespace std { + template<> + struct hash{ + std::size_t operator()(xreate::versions::SymbolOrPlaceholder const& s) const; + }; + + template<> + struct equal_to{ + bool operator()(const xreate::versions::SymbolOrPlaceholder& __x, const xreate::versions::SymbolOrPlaceholder& __y) const; + }; +} + +namespace xreate { namespace versions { + +enum PlaceholderFlag {SYMBOL, PLACEHOLDER}; + +struct SymbolOrPlaceholder { + PlaceholderFlag flagEndOfLifePlaceholder; + Symbol symbol; +}; + +struct VersionImposedDependency{}; + +/** \brief Represents results of Versions Analysis + * \sa VersionsPass + */ +class VersionsGraph{ + public: + //processing API: + void applyNatualDependencies(const Symbol& symbol, const std::list& dependencies); + void applyDependentEndOfLife(const SymbolOrPlaceholder& symbol, const std::list& dependencies); + + void defineEndOfLife(const Symbol& symbol, const Symbol& symbolSuccessor); + SymbolOrPlaceholder getEndOfLife(const Symbol& s); + + bool validate(); + + //examination API: + AttachmentsContainerDefault>* representAsAttachments() const; + void __debug_print(std::ostream& output) const; + + private: + typedef std::unordered_map Path; + + std::unordered_multimap __inferiorsNatural; + std::unordered_multimap __inferiors; + std::unordered_map __dictSuccessors; + + std::list expandPlaceholder(const SymbolOrPlaceholder& symbol, const Symbol& symbolPrev) const; + std::list extractCycle(const Path& path, const SymbolOrPlaceholder& symbolBeginning); + bool tryEliminateEofAliases(const std::list& aliases); + bool validateCycles(); + bool validateCycles(const SymbolOrPlaceholder& s, + std::unordered_multimap& graph, + std::unordered_set& symbolsVisited, + Path& path); +}; + +/** \brief Provides Versions Analysis and stores results in VersionsGraph */ +class VersionsPass: public AbstractPass> { + typedef AbstractPass> Parent; + +public: + VersionsPass(PassManager* manager): AbstractPass>(manager){} + std::list process(const Expression& expression, PassContext context, const std::string& hintSymbol="") override; + VersionsGraph& getResultGraph(); + virtual void finish(); + +protected: + std::list processSymbol(const Symbol& symbol, PassContext context, const std::string& hintSymbol="") override; + +private: + VersionsGraph __graph; + + AttachmentsContainerDefault __symbolsVisited; +}; + +}} //end of xreate::versions + +namespace xreate{ + template<> + std::list + defaultValue>(); + + template<> + struct AttachmentsDict + { + typedef std::list Data; + static const unsigned int key = 8; + }; +} +#endif /* VERSIONSPASS_H */ + diff --git a/cpp/src/passmanager.cpp b/cpp/src/passmanager.cpp deleted file mode 100644 index ccc9338..0000000 --- a/cpp/src/passmanager.cpp +++ /dev/null @@ -1,120 +0,0 @@ -#include -#include -#include "query/containers.h" -#include "passmanager.h" -#include "pass/compilepass.h" -#include "pass/adhocpass.h" - -#include "Parser.h" -#include "pass/cfapass.h" -#include "pass/dfapass.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); -} - -PassManager* -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); - - 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]; -} - -bool -PassManager::isPassRegistered(const PassId& id){ - return __passes.count(id); -} - -void -PassManager::executePasses(){ - 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(); - } -} - -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; - - CFAPass* passCFG = new CFAPass(this); - - //TODO is it really DFGPass needs CFGpass? - this->registerPass(new DFAPass(this), PassId::DFGPass, passCFG); - this->registerPass(passCFG, PassId::CFGPass); - this->registerPass(new AdhocPass(this), PassId::AdhocPass); - - this->executePasses(); - clasp->run(); - flagIsProcessed = true; -} - -PassManager::~PassManager(){} diff --git a/cpp/src/passmanager.h b/cpp/src/passmanager.h deleted file mode 100644 index cb55967..0000000 --- a/cpp/src/passmanager.h +++ /dev/null @@ -1,56 +0,0 @@ -#ifndef PASSMANAGER_H -#define PASSMANAGER_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, - InterpretationPass -}; - -class PassManager -{ -public: - ~PassManager(); - void*run(); - void runWithoutCompilation(); - void executePasses(); - void registerPass(AbstractPassBase* pass, const PassId& id, AbstractPassBase* prerequisite=nullptr); - AbstractPassBase* getPassById(const PassId& id); - bool isPassRegistered(const PassId& id); - static PassManager* prepareForCode(std::string&& code); - 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/containers.cpp b/cpp/src/query/containers.cpp index 8f37165..543fc00 100644 --- a/cpp/src/query/containers.cpp +++ b/cpp/src/query/containers.cpp @@ -1,164 +1,119 @@ -// -// Created by pgess on 3/14/15. -// - -#include +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * Author: pgess + * + * containers.cpp + * Created on 3/14/15. + */ + +/** + * \file query/containers.h + * \brief Represents reasoner's solution on [Container implementations](/w/concepts/containers) + */ + +#include #include "query/containers.h" using namespace std; using namespace xreate::containers; using namespace xreate; - - Implementation Query::queryImplementation(xreate::Symbol const &s) { - typedef Attachments attach; - - if (attach::exists(s)) + if (Attachments::exists(s)) { - return attach::get(s); + return Attachments::get(s); } return Implementation::create(s); } -void -Query::init(ClaspLayer* clasp) -{ - if (flagIsDataLoaded) return; - map prototypes; - map roots; - - //read all proto data - auto range = clasp->query(Config::get("containers.id.prototypes")); - if (range) - for(ClaspLayer::ModelIterator atom = range->first; atom != range->second; ++atom) { - auto data = ClaspLayer::parse(atom->second); - Symbol root = clasp->unpack(get<0> (data)); - Symbol prototype = clasp->unpack(get<1> (data)); +Query::Query(){ + Attachments::init(); +} - prototypes[root] = prototype; - } +void +Query::init(TranscendLayer* transcend) +{ + if (flagDataIsLoaded) return; - // fill implementation data for a data sources: - range = clasp->query(Config::get("containers.id.implementations")); - if (range) - for(ClaspLayer::ModelIterator atom = range->first; atom != range->second; ++atom) + //Fill implementation data for a data sources: + auto range = transcend->query(Config::get("containers.id.implementations")); + if (range.size()) + for(auto atom: range) { - auto data = ClaspLayer::parse(atom->second); + auto data = TranscendLayer::parse(atom.second); - Symbol var = clasp->unpack(get<0>(data)); - string implSerialized = get<1>(data); + Symbol var = transcend->unpack(get<0>(data)); + string implStr = get<1>(data).name().c_str(); - //data source, has no prototypes: - if (!prototypes.count(var)) + if (implStr == Config::get("containers.impl.solid")) { - Implementation impl = Implementation::create(var); - Attachments::put(var, move(impl)); - continue; - } - - roots.emplace(move(var), move(implSerialized)); - } - - //fill implementation data for a cluster roots - for (const pair & root: roots) - { - Symbol prototype = prototypes[root.first]; + auto size = TranscendLayer::parse(get<1>(data)); + Attachments::put(var, {SOLID, ImplementationRec{get<0>(size)}}); - while (prototypes.count(prototype)) { - prototype = prototypes.at(prototype); - } - - Attachments::put(root.first, Implementation(Attachments::get(prototype))); - } - - // read cluster data and fill implementation data for cluster members - range = clasp->query(Config::get("containers.id.clusters")); - if (range) - for(ClaspLayer::ModelIterator atom = range->first; atom != range->second; ++atom) - { - auto info = ClaspLayer::parse(atom->second); - - Symbol root = clasp->unpack(get<0>(info)); - Symbol child = clasp->unpack(get<1>(info)); + } else if (implStr == Config::get("containers.impl.onthefly")) { + Attachments::put(var, {ON_THE_FLY, ImplementationRec{var}}); - if (!(child == root)) { - Implementation rootImpl = Attachments::get(root); - Attachments::put(child, move(rootImpl)); + } else { + assert(false && "Unable to determine proper implementation for the symbol"); } } - flagIsDataLoaded = true; + flagDataIsLoaded = true; } -//static ImplementationData* create(Symbol var, std::string implSerialized, const ImplementationData* implPrototype); - Implementation Implementation::create(const Symbol &var) { //TODO review implementation determination strategy - Expression varDecl = CodeScope::findDeclaration(var); + Expression varDecl = CodeScope::getDefinition(var); switch (varDecl.op) { case Operator::LIST_RANGE: { ImplementationRec rec{var}; return {ON_THE_FLY, rec}; } case Operator::LIST: { return {SOLID, ImplementationRec {varDecl.getOperands().size()}}; } default: break; }; ImplementationLinkedList ill(var); if (ill){ return ill.getImplementationData(); } assert(false && "Unable to determine proper implementation for the symbol"); + return Implementation(); } -Implementation -Implementation::create(const Symbol& var, const std::string& implSerialized) -{ - Expression varDecl = CodeScope::findDeclaration(var); - if (implSerialized == Config::get("containers.impl.solid")) - { - return {SOLID, ImplementationRec{varDecl.operands.size()}}; - - } else if (implSerialized == Config::get("containers.impl.onthefly")) { - return {ON_THE_FLY, ImplementationRec{var}}; - } - - assert(false && "unable to determine proper implementation for the symbol"); -} - - ImplementationLinkedList::ImplementationLinkedList(const Symbol& source) : flagIsValid(false), s(source){ - const Expression& sourceExpr = CodeScope::findDeclaration(source); + const Expression& sourceExpr = CodeScope::getDefinition(source); if (sourceExpr.tags.count(Config::get("containers.id.linkedlist"))){ flagIsValid = true; Expression tagLinkedlist = sourceExpr.tags.at(Config::get("containers.id.linkedlist")); assert(tagLinkedlist.operands.size() == 2); fieldPointer = tagLinkedlist.operands.at(0).getValueString(); terminator = tagLinkedlist.operands.at(1); } } ImplementationLinkedList:: operator bool () const{ return flagIsValid; } Implementation ImplementationLinkedList::getImplementationData() const { return {ON_THE_FLY, ImplementationRec{s}}; } diff --git a/cpp/src/query/containers.h b/cpp/src/query/containers.h index ec474d0..ab8de85 100644 --- a/cpp/src/query/containers.h +++ b/cpp/src/query/containers.h @@ -1,83 +1,92 @@ -// -// Created by pgess on 3/14/15. -// +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * Author: pgess + * + * containers.h + * Created on 3/14/15. + */ #ifndef _XREATE_CONTAINERSQUERY_H_ #define _XREATE_CONTAINERSQUERY_H_ -#include "passmanager.h" -#include "clasplayer.h" +#include "xreatemanager.h" +#include "transcendlayer.h" #include namespace xreate { namespace containers { enum ImplementationType {SOLID, ON_THE_FLY, LINKED_LIST}; template struct ImplementationRec; template<> struct ImplementationRec { size_t size; }; template<> struct ImplementationRec{ Symbol source; }; struct Implementation; struct ImplementationLinkedList { bool flagIsValid; std::string fieldPointer; Expression terminator; ImplementationLinkedList(const Symbol& source); operator bool() const; Implementation getImplementationData() const; private: Symbol s; }; struct Implementation { typedef boost::variant, ImplementationRec> Variant; - const ImplementationType impl; + ImplementationType impl; Variant data; static Implementation create(const Symbol &var); static Implementation create(const Symbol& var, const std::string &implSerialized); - static Implementation create(const Symbol& var, const Implementation& proto); template const ImplementationRec& extract() const{ const ImplementationRec& rec = boost::get>(data); return rec; } }; + /** \brief Extracts solution about container implementation + * \sa xreate::containers::Iterator + */ class Query : public xreate::IQuery { public: static Implementation queryImplementation(xreate::Symbol const &s); - void init(ClaspLayer* clasp); + void init(TranscendLayer* transcend); + Query(); ~Query(){} private: - bool flagIsDataLoaded = false; + bool flagDataIsLoaded = false; PassManager *man; }; } template<> struct AttachmentsDict { typedef containers::Implementation Data; static const unsigned int key = 1; }; } #endif //_XREATE_CONTAINERSQUERY_H_ diff --git a/cpp/src/query/context.cpp b/cpp/src/query/context.cpp deleted file mode 100644 index 76d7b05..0000000 --- a/cpp/src/query/context.cpp +++ /dev/null @@ -1,207 +0,0 @@ -/* - * adhoc.cpp - * - * Created on: Dec 1, 2015 - * Author: pgess - */ - -#include -#include -#include - -using namespace std; -namespace xreate { - -const Domain domainEmpty; -const Decisions decisionsEmpty; -const FunctionDemand functionDemandEmpty; - -ContextQuery::ContextQuery(){} - - -const Domain& -ContextQuery::getContext(const ScopePacked& scopeId) const{ - if (!__modelContext.count(scopeId)){ - return domainEmpty; - } - - return __modelContext.at(scopeId); -} - -const Domain& -ContextQuery::getContext(CodeScope* const scope) const{ - return getContext(clasp->pack(scope)); -} - -//DEBT compatibility of forced context with context resolution for interpretation -void -ContextQuery::forceContext(const ScopePacked& scopeId, std::list context){ - // TODO remove forced context of the same class/type only, possibly - //remove any previous forced context for this 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& atomBinding = Config::get("clasp.bindings.scope"); - - this->clasp = clasp; - ClaspLayer::ModelFragment query = clasp->query(atomBinding); - - //static context - if (query){ - map> dictContext; - - for (auto i = query->first; i!=query->second; ++i){ - ScopePacked idScope; - Expression context; - std::string link; - tie(idScope, context, link) = ClaspLayer::parse(i->second); - if (link == "strong") { - dictContext[idScope].push_back(context); - } - } - - for (map>::value_type& entry: dictContext){ - __modelContext.insert(move(entry)); - } - } - - prepareFunctionDemandModel(); - prepareDecisionModels(); -} - - - -void -ContextQuery::prepareFunctionDemandModel(){ - 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; - Expression topic; - tie(function, topic) = ClaspLayer::parse(i->second); - - FunctionDemand& demand = __modelFunctionDemand[function]; - demand.left.insert(make_pair(demand.left.size(), topic)); - } -} - -void -ContextQuery::prepareDecisionModels(){ - const std::string& atomDecision = Config::get("clasp.bindings.scope_decision"); - const std::string& atomDependentDecision = Config::get("clasp.context.decisions.dependent"); - - std::multimap modelDomains; - - - ClaspLayer::ModelFragment query = clasp->query(atomDecision); - if (query){ - for (auto i = query->first; i!=query->second; ++i){ - ScopePacked scopeId; - Expression topic; - Expression decision; - - std::tie(scopeId, topic, decision) = ClaspLayer::parse(i->second); - - if (decision.getValueString() == atomDependentDecision) { - assert(decision.operands.size() == 2); - - const Expression& decisionGuard = decision.operands[1]; - const Expression& decisionValue = decision.operands[0]; - - __modelDependentDecisions[scopeId][topic].emplace(decisionGuard, decisionValue); - modelDomains.emplace(topic, decisionValue); - - } else { - Decisions& decisionsOfScope = __modelStaticDecisions[scopeId]; - assert(decisionsOfScope.emplace(topic, decision).second && "Possibly more than one decision"); - modelDomains.emplace(topic, decision); - } - } - } - - - //populate topic domains: - auto adapter = [](const std::pair& p){ return p.second; }; - - auto iBegin = modelDomains.begin(); - while (iBegin!=modelDomains.end()){ - const Expression topic = iBegin->first; - auto iEnd = modelDomains.upper_bound(topic); - auto iBeginAdapted = boost::make_transform_iterator(iBegin,adapter); - auto iEndAdapted = boost::make_transform_iterator(iEnd,adapter); - Domain dom(iBeginAdapted, iEndAdapted); - __modelTopicDomains.emplace(topic, move(dom)); - iBegin = iEnd; - } -} - -const FunctionDemand& -ContextQuery::getFunctionDemand(const std::string& name) const { - if (__modelFunctionDemand.count(name)){ - return __modelFunctionDemand.at(name); - } - - return functionDemandEmpty; -} - -const Decisions& -ContextQuery::getFinalDecisions(const ScopePacked& scopeId) const{ - if (__modelStaticDecisions.count(scopeId)){ - return __modelStaticDecisions.at(scopeId); - } - - return decisionsEmpty; -} - -const Domain& -ContextQuery::getTopicDomain(const Expression& topic) const{ - if (__modelTopicDomains.count(topic)){ - return __modelTopicDomains.at(topic); - } - - return domainEmpty; -} - -const DependentDecision& -ContextQuery::getDependentDecision(ScopePacked scope, const Expression& topic) const{ - auto itDecisionsAllTopics = __modelDependentDecisions.find(scope); - if (itDecisionsAllTopics != __modelDependentDecisions.end()){ - auto itDecisions = itDecisionsAllTopics->second.find(topic); - - if (itDecisions != itDecisionsAllTopics->second.end()){ - return itDecisions->second; - } - } - - return decisionsEmpty; -} - -// 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 deleted file mode 100644 index 8dd6858..0000000 --- a/cpp/src/query/context.h +++ /dev/null @@ -1,95 +0,0 @@ -/* - * 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 "serialization.h" -#include - -#include -#include -#include -#include -#include - -namespace xreate { - -typedef ExpressionSerialization::Serializer Domain; -typedef boost::bimap FunctionDemand; -typedef std::map Decisions; -typedef std::map DependentDecision; - -class ContextQuery: public IQuery { - //AdhocQuery(); -public: - const Domain& getContext(const ScopePacked& scopeId) const; - const Domain& getContext(CodeScope* const scope) const; - void forceContext(const ScopePacked& scopeId, std::list context); - const Domain& getTopicDomain(const Expression& topic) const; - const DependentDecision& getDependentDecision(ScopePacked scope, const Expression& topic) const; - const FunctionDemand& getFunctionDemand(const std::string& name) const; - const Decisions& getFinalDecisions(const ScopePacked& scopeId) const; - - virtual void init(ClaspLayer* clasp); - ContextQuery(); - virtual ~ContextQuery(){}; -private: - ClaspLayer* clasp; - std::map __modelContext; - std::map __modelFunctionDemand; - std::map __modelStaticDecisions; - std::map __modelTopicDomains; - std::map> __modelDependentDecisions; - - void prepareFunctionDemandModel(); - void prepareDecisionModels(); -}; - -} /* 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 ; -*/ - -#endif /* SRC_QUERY_CONTEXT_H_ */ diff --git a/cpp/src/query/latex.cpp b/cpp/src/query/latex.cpp new file mode 100644 index 0000000..6970cc7 --- /dev/null +++ b/cpp/src/query/latex.cpp @@ -0,0 +1,101 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +/* + * Author: pgess + * Created on June 25, 2018, 12:14 PM + * + * \file latex.cpp + * \brief latex + */ + +#include "query/latex.h" +#include "aux/transcend-decorators.h" + +using namespace std; +using namespace xreate::latereasoning; + +namespace xreate{ +namespace latex{ + +void +LatexQuery::init(TranscendLayer* transcend) { + __transcend = transcend; + + //schema: latex_fn_demand(Fn, Subject) + StaticModel data = __transcend->query("latex_fn_demand_ordered"); + for(const auto& entry : data) { + string fnName, subject; size_t id; + tie(fnName, subject, id) = __transcend->parse(entry.second); + __demand[fnName].resize(std::max(__demand[fnName].size(), id+1)); + __demand[fnName][id] = subject; + } + + //schema: latex_registered_subjects(Subject, Decision) + data = __transcend->query("latex_registered_subjects"); + for(const auto& entry : data) { + string subject; + Gringo::Symbol decision; + + tie(subject, decision) = __transcend->parse(entry.second); + __domains[subject].push_back(decision); + } + + //schema: latex_decision(Scope, Subject, Decision) + data = __transcend->query("latex_decision"); + for(const auto& entry : data) { + ScopePacked scope; + string subject; + Gringo::Symbol decision; + + tie(scope, subject, decision) = __transcend->parse(entry.second); + __decisions[make_pair(scope, subject)] = entry.second; + } + + //schema: latex_parameters_offset(int) + //Override parameter from transcend + data = __transcend->query("latex_parameters_offset"); + if(data.size()) { + LatexParametersOffset = std::get<0>(__transcend->parse(data.begin()->second)); + } + + auto transcendLate = + Decorators::getInterface(__transcend); + + //Later decisions. schema: Scope, Subject, Decision + LateAnnotationsGroup group = transcendLate->queryLate("latex_decision"); + for (auto entry: group.annotations) { + auto key = __transcend->parse(entry.first); + __decisionsLate.emplace(make_pair(get<0>(key), get<1>(key)), entry.second); + } +} + +Demand +LatexQuery::getFnDemand(const std::string& fnName) { + if (!__demand.count(fnName)) return Demand(); + return __demand.at(fnName); +} + +latereasoning::LateAnnotation +LatexQuery::getDecision(const std::string& subject, const CodeScope* scopeCaller) { + ScopePacked scopeP = __transcend->pack(scopeCaller); + + if(__decisions.count(make_pair(scopeP, subject))){ + //found static decision + return LateAnnotation(__decisions.at(make_pair(scopeP, subject))); + } + + return __decisionsLate.at(make_pair(scopeP, subject)); +} + +std::list +LatexQuery::getSubjectDomain(const std::string& subject) { + assert(__domains.count(subject)); + return __domains.at(subject); +} + +} +} diff --git a/cpp/src/query/latex.h b/cpp/src/query/latex.h new file mode 100644 index 0000000..42e5d9e --- /dev/null +++ b/cpp/src/query/latex.h @@ -0,0 +1,46 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +/** + * \file query/context.h + * \brief Represents reasoner's solution on [Context](/w/concepts/context) + * + * \class xreate::latex::LatexQuery + */ + +#ifndef LATEXQUERY_H +#define LATEXQUERY_H + +#include "transcendlayer.h" +#include "aux/latereasoning.h" +#include + +namespace xreate{ +namespace latex{ + +typedef std::vector Demand; + +class LatexQuery: public IQuery{ +public: + VNameId LatexParametersOffset = 1000; //Default value. Overriden by `latex_parameters_offset` from transcend + + Demand getFnDemand(const std::string& fnName); + latereasoning::LateAnnotation getDecision(const std::string& subject, const CodeScope* scopeCaller); + std::list getSubjectDomain(const std::string& subject); + void init(TranscendLayer* transcend); + +private: + TranscendLayer* __transcend; + std::map __demand; + std::map, Gringo::Symbol> __decisions; + std::map, latereasoning::LateAnnotation> __decisionsLate; + std::map> __domains; +}; + +} +} + +#endif diff --git a/cpp/src/query/polymorph.cpp b/cpp/src/query/polymorph.cpp new file mode 100644 index 0000000..52f6aa0 --- /dev/null +++ b/cpp/src/query/polymorph.cpp @@ -0,0 +1,71 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * File: polymorph.cpp + * Author: pgess + * + * Created on November 9, 2017, 12:14 PM + */ + +#include "polymorph.h" +#include "aux/transcend-decorators.h" +using namespace std; +namespace xreate{ +namespace polymorph{ + +const std::string atomPolymorph = "dfa_callguard"; + +void +PolymorphQuery::init(TranscendLayer* transcend) { + __transcend = transcend; + + StaticModel queryResult = transcend->query(atomPolymorph); + if (queryResult.size()) { + for (auto entry : queryResult) { + auto answer = TranscendLayer::parse(entry.second); + SymbolNode symbCaller = std::get<0>(answer); + SymbolGeneralized symbCallerUnpacked = transcend->unpack(symbCaller); + + __cacheEarlyReasoning.emplace(symbCallerUnpacked, entry.second); + } + } + + auto transcendLate = + Decorators::getInterface(__transcend); + latereasoning::LateAnnotationsGroup group = transcendLate->queryLate(atomPolymorph); + + for(auto entry : group.annotations) { + auto targetWrapper = Gringo::Symbol::createTuple(Gringo::SymSpan{&entry.first, 1}); + auto targetSP = __transcend->parse(targetWrapper); + SymbolGeneralized targetS = __transcend->unpack(std::get<0>(targetSP)); + __cacheLateReasoning.emplace(targetS, entry.second); + } +} + +latereasoning::LateAnnotation +PolymorphQuery::get(const Expression& e) const { + SymbolGeneralized targetS = Attachments::exists(e) ? + SymbolGeneralized(Attachments::get(e)) + : SymbolGeneralized(SymbolAnonymous{e.id}); + + if (__cacheEarlyReasoning.count(targetS)) { + return latereasoning::LateAnnotation(__cacheEarlyReasoning.at(targetS)); + } + + if (__cacheLateReasoning.count(targetS)) { + return __cacheLateReasoning.at(targetS); + } + + assert(false && "Can't find a guard"); +} + +Expression +PolymorphQuery::getValue(const Gringo::Symbol& symbol) const { + auto result = __transcend->parse(symbol); + return std::get<1>(result); +} + +} +} //end of xreate::polymorph diff --git a/cpp/src/query/polymorph.h b/cpp/src/query/polymorph.h new file mode 100644 index 0000000..f708fe6 --- /dev/null +++ b/cpp/src/query/polymorph.h @@ -0,0 +1,35 @@ +/* + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * File: polymorph.h + * Author: pgess + * + * Created on November 9, 2017, 12:14 PM + */ + +#ifndef POLYMORPHQUERY_H +#define POLYMORPHQUERY_H + +#include "transcendlayer.h" +#include "aux/latereasoning.h" +#include + +namespace xreate { namespace polymorph { +class PolymorphQuery: public IQuery { +public: + latereasoning::LateAnnotation get(const Expression& e) const; + Expression getValue(const Gringo::Symbol& s) const; + virtual void init(TranscendLayer* transcend) override; + +private: + std::unordered_map __cacheEarlyReasoning; + std::unordered_map __cacheLateReasoning; + TranscendLayer* __transcend = nullptr; +}; + +}}//end of xreate::polymorph + +#endif /* POLYMORPHQUERY_H */ + diff --git a/cpp/src/serialization.h b/cpp/src/serialization.h index 08425af..c50d932 100644 --- a/cpp/src/serialization.h +++ b/cpp/src/serialization.h @@ -1,30 +1,38 @@ -/* +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * * serialization.h * - * Created on: 13 февр. 2016 - * Author: pgess + * Created on: 03/13. 2016 + * Author: pgess + */ + +/** + * \file + * \brief Serialization: mechanism to represent expressions in compact form for efficient processing */ #ifndef SRC_SERIALIZATION_SERIALIZATION_H_ #define SRC_SERIALIZATION_SERIALIZATION_H_ -#include "serialization/expressionserializer.h" +#include "aux/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/serialization/expressionserializer2.cpp b/cpp/src/serialization/expressionserializer2.cpp deleted file mode 100644 index 5c63641..0000000 --- a/cpp/src/serialization/expressionserializer2.cpp +++ /dev/null @@ -1,98 +0,0 @@ -/* - * 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 deleted file mode 100644 index 3b29756..0000000 --- a/cpp/src/serialization/expressionserializer2.h +++ /dev/null @@ -1,25 +0,0 @@ -/* - * 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/src/transcendlayer.cpp b/cpp/src/transcendlayer.cpp new file mode 100644 index 0000000..26ced04 --- /dev/null +++ b/cpp/src/transcendlayer.cpp @@ -0,0 +1,496 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * Author: pgess + * File: transcendlayer.cpp + */ + +/** + * \file transcendlayer.h + * \brief Reasoner. Wrapper over the external Clasp reasoner library + */ + +#include "transcendlayer.h" +#include "analysis/utils.h" +#include "utils.h" + +#include +#include +#include +#include +#include +#include + +using namespace std; + +//TODO escape identifiers started with upper case symbol + +namespace xreate{ + +bool operator==(const SymbolAnonymous& s1, const SymbolAnonymous& s2) { + return s1.id == s2.id && s1.flagIsUsed == s2.flagIsUsed; +} + +struct VisitorSymbolNodeHash : public boost::static_visitor{ + + std::size_t operator()(const xreate::SymbolPacked& node) const noexcept { + return 2 * (node.identifier + 3 * node.scope + 5 * std::abs(node.version)); + } + + std::size_t operator()(const xreate::SymbolAnonymous& node) const noexcept { + return 7 * node.id; + } +} ; +} + +namespace std{ + +std::size_t +hash::operator()(xreate::SymbolNode const& s) const noexcept { + return boost::apply_visitor(xreate::VisitorSymbolNodeHash(), s); +} + +std::size_t +hash::operator()(xreate::SymbolGeneralized const& s) const noexcept { + return xreate::AttachmentsId::getId(s); +} +} + +namespace xreate{ + +void +TranscendLayer::printWarnings(std::ostream& out) { + const std::string warningTag = "warning"; + + auto warningsModel = query(warningTag); + + if(warningsModel.size()) + for(auto warning : warningsModel) { + unsigned int warningId; + + Gringo::Symbol params; + std::tie(warningId, params) = parse(warning.second); + + cout << "Warning: " << __warnings.at(warningId) << " "; + params.print(out); + out << params; + } +} + +bool +TranscendLayer::processSolution(Gringo::Model const &model) { + cout << "Model: " << endl; + + const string& atomBindVar = Config::get("transcend.bindings.variable"); + const string& atomBindFunc = Config::get("transcend.bindings.function"); + const string& atomBindScope = Config::get("transcend.bindings.scope"); + + for(Gringo::Symbol atom : model.atoms(clingo_show_type_atoms)) { + atom.print(cout); + cout << " | " << endl; + + string atomName(atom.name().c_str()); + if(atomName == atomBindVar || atomName == atomBindFunc || atomName == atomBindScope) { + string atomAlias = std::get<1>(parse(atom)).name().c_str(); + __model.emplace(atomAlias, atom); + continue; + } + + __model.emplace(atomName, atom); + } + + return true; +} + +void +TranscendLayer::registerReport(IAnalysisReport * report) { + __reports.push_back(report); +} + +void +TranscendLayer::runReports() { + for(IAnalysisReport* report : __reports) { + report->print(__partGeneral); + delete report; + } + + __reports.clear(); +} + +void +TranscendLayer::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 xreate::analysis::compile(guard); + }); + + const list& guards = xreate::analysis::multiplyLists(std::move(guardsRaw)); + list &&branches = xreate::analysis::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, ", ")) + << endl; + } +} + +unsigned int +TranscendLayer::registerWarning(std::string && message) { + static int warningId = 0; + __warnings.emplace(warningId, message); + return warningId++; +} + +void +TranscendLayer::involveImports() { + ostream &out = __partGeneral; + + if(ast) + for(string fn : ast->__rawImports) { + std::ifstream file(fn); + if(!file) { + std::cout << "Can't process script file: " << fn << std::endl; + assert(false); + } + + while(!file.eof()) { + string line; + std::getline(file, line); + out << line << endl; + } + } +} + +void +TranscendLayer::addRawScript(std::string && script) { + __partGeneral << script; +} + +void +TranscendLayer::run() { + involveImports(); + runReports(); + + 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(), { }, 0); + + ctl.add("base",{}, program.str()); + ctl.ground({ + {"base", + {}} + }, nullptr); + + // solve + Gringo::SolveResult result = ctl.solve([this](Gringo::Model const &model) { + this->processSolution(model); + return true; + }, + { + }); + + if(result.satisfiable() == Gringo::SolveResult::Satisfiable) { + cout << FGRN("SUCCESSFULLY") << endl; + } else { + cout << FRED("UNSUCCESSFULLY") << endl; + } + + // invoke all query plugins to process solution + for(auto q : __queries) { + q.second->init(this); + } +} + +TranscendLayer::TranscendLayer() : ast(nullptr) { } + +StaticModel +TranscendLayer::query(const std::string & atom) const { + StaticModel result; + + if (! __model.count(atom)) { + return result; + } + + auto currentDataRange = __model.equal_range(atom); + std::copy(currentDataRange.first, currentDataRange.second, std::inserter(result, result.end())); + return result; +} + +ScopePacked +TranscendLayer::pack(const CodeScope * const scope) { + auto pos = __indexScopes.emplace(scope, __indexScopes.size()); + if(pos.second) + __registryScopes.push_back(scope); + + return pos.first->second; +} + +size_t +TranscendLayer::getScopesCount() const { + return __registryScopes.size(); +} + +SymbolPacked +TranscendLayer::pack(const Symbol& symbol, std::string hintSymbolName) { + SymbolPacked result(symbol.identifier.id, symbol.identifier.version, pack(symbol.scope)); + __indexSymbolNameHints.emplace(result, hintSymbolName); + + return result; +} + +Symbol +TranscendLayer::unpack(const SymbolPacked & symbol) const { + return Symbol{ScopedSymbol + {symbol.identifier, symbol.version}, __registryScopes[symbol.scope]}; +}; + +std::string +TranscendLayer::getHintForPackedSymbol(const SymbolPacked & symbol) { + auto result = __indexSymbolNameHints.find(symbol); + return(result == __indexSymbolNameHints.end()) ? "" : result->second; +} + +IQuery * +TranscendLayer::registerQuery(IQuery *query, const QueryId & id) { + return __queries.emplace(id, query).first->second; +} + +IQuery * +TranscendLayer::getQuery(const QueryId & id) { + assert(__queries.count(id) && "Undefined query"); + return __queries.at(id); +} + +class VisitorUnpackSymbol : public boost::static_visitor{ +public: + + VisitorUnpackSymbol(const TranscendLayer* transcend) : __transcend(transcend) { } + + SymbolGeneralized operator()(const SymbolPacked& symbol) const { + return __transcend->unpack(symbol); + } + + SymbolGeneralized operator()(const SymbolAnonymous& symbol) const { + return symbol; + } + +private: + const TranscendLayer* __transcend; +} ; + +class VisitorPackSymbol : public boost::static_visitor{ +public: + + VisitorPackSymbol(TranscendLayer* transcend, const std::string& hintSymbolName) + : __transcend(transcend), __hint(hintSymbolName) { } + + SymbolNode operator()(const Symbol& symbol) const { + return __transcend->pack(symbol, __hint); + } + + SymbolNode operator()(const SymbolAnonymous& symbol) const { + return symbol; + } + +private: + TranscendLayer* __transcend; + std::string __hint; +} ; + +SymbolNode +TranscendLayer::pack(const SymbolGeneralized& symbol, const std::string & hintSymbolName) { + return boost::apply_visitor(VisitorPackSymbol(this, hintSymbolName), symbol); +} + +SymbolGeneralized +TranscendLayer::unpack(const SymbolNode & symbol) const { + return boost::apply_visitor(VisitorUnpackSymbol(this), symbol); +} + +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); +} + +Expression +ParseImplAtom +::get(const Gringo::Symbol & atom) { + switch(atom.type()) { + case Gringo::SymbolType::Num: return Expression(atom.num()); + case Gringo::SymbolType::Str: return Expression(Atom(std::string(atom.string().c_str()))); + + case Gringo::SymbolType::Fun: + { + //FUNC + Expression result(Operator::CALL,{Expression(Atom(std::string(atom.name().c_str())))}); + for(const Gringo::Symbol& arg : atom.args()) { + result.addArg(ParseImplAtom::get(arg)); + } + + return result; + } + + default: + { + assert(false); + } + } +} + +int +ParseImplAtom +::get(const Gringo::Symbol & atom) { + switch(atom.type()) { + case Gringo::SymbolType::Num: return atom.num(); + default: break; + } + + assert(false && "Inappropriate symbol type"); +} + +std::string +ParseImplAtom +::get(const Gringo::Symbol & atom) { + switch(atom.type()) { + case Gringo::SymbolType::Str: return atom.string().c_str(); + case Gringo::SymbolType::Fun: return atom.name().c_str(); + + default: break; + } + + assert(false && "Inappropriate symbol type"); +} + +SymbolPacked +ParseImplAtom +::get(const Gringo::Symbol & atom) { + auto result = TranscendLayer::parse(atom); + return SymbolPacked(std::get<0>(result), std::get<1>(result), std::get<2>(result)); +}; + +Gringo::Symbol +ParseImplAtom +::get(const Gringo::Symbol & atom) { + return atom; +} + +SymbolNode +ParseImplAtom +::get(const Gringo::Symbol & atom) { + assert(atom.type() == Gringo::SymbolType::Fun + && "Inappropriate symbol type"); + + if(atom.name() == "a") { + return SymbolAnonymous{(unsigned int) std::get<0>(TranscendLayer::parse(atom))}; + + } else if(atom.name() == "s") { + return ParseImplAtom::get(atom); + } + + assert(false && "Wrong symbol format"); +} + +class VisitorSymbolId : public boost::static_visitor{ +public: + + unsigned int operator()(const Symbol& symbol) const { + return AttachmentsId::getId(symbol); + } + + unsigned int operator()(const SymbolAnonymous& symbol) const { + return symbol.id; + } +} ; + +unsigned int +AttachmentsId +::getId(const SymbolGeneralized & symbol) { + return boost::apply_visitor(VisitorSymbolId(), symbol); +} + +} //end of xreate namespace + +/** + * \class xreate::TranscendLayer + * \brief Reasoning and logic Solver. + * + * Wraps external brilliant fantastic tool [Clasp solver](https://potassco.org/clasp/) + * + * For building *logic program* for reasoning TranscendLayer takes input from: + * - Raw scripts. Client could append arbitrary ASP script to _logic program_. \ref addRawScript() + * - Includes. There is possibility to specify external files with ASP scripts + * to append to _logic program_. \ref involveImports() (private member) + * - Diagnostic rules. Rules that produce diagnostic messages during + * compilation(warnings) or even able to halt compilation with errors. + * addRuleWarning(), \ref registerWarning() + * - DFA data. \ref setDFAData() + * - CFA data. \ref setCFAData() + * - Dominators Analysis. See xreate::dominators::DominatorsAnalysisProvider. + * Executed by \ref run() + * - Context rules. See xreate::ContextRule and general [Context Explanation](/w/concepts/context) + * + * Data sources implement xreate::IAnalysisReport. Generally, input could be loosely divided into three categories: + * - *Internally derived* data. CFA, DFA, Dominators analyses *automatically* feed reasoner by + * useful insights about data, structure and algorithms of a program + * - *User provided* data. CFA, DFA, Diagnostic/Context rules feed reasoner by + * annotations Developer specifically provides manually + * - *External* data. Raw scripts and includes feed reasoner with third-party data + * related to a different aspects of a program possibly produced by external analyzers + * + * Once TranscendLayer got input from all providers and logic program is fully constructed + * it runs external Clasp reasoner and receives back desired solutions. + * + * Output of the external Clasp reasoner is recognized and accessed via *queries*. + * IQuery represents an interface between reasoner's output and rest of Xreate. + * Each query inherits xreate::IQuery interface. Currently there are queries as follows: + * - xreate::containers::Query to catch solutions regarding Containers implementation. See [Containers Explanation](/w/concepts/containers) + * - xreate::context::ContextQuery to catch solution regarding Context. See [Context Explanation](/w/concepts/context) + * + * \sa See xreate::dfa::DFAPass, xreate::cfa::CFAPass, xreate::IQuery, xreate::IAnalysisReport, xreate::dominators::DominatorsAnalysisProvider + */ diff --git a/cpp/src/transcendlayer.h b/cpp/src/transcendlayer.h new file mode 100644 index 0000000..e657c1c --- /dev/null +++ b/cpp/src/transcendlayer.h @@ -0,0 +1,283 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * Author: pgess + * File: transcendlayer.h + */ + +#ifndef transcendLAYER_H +#define transcendLAYER_H + +#include "ast.h" +#include "contextrule.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace xreate { + +typedef unsigned int ScopePacked; +const ScopePacked SCOPE_ABSTRACT_GLOBAL = std::numeric_limits::max(); + +struct SymbolPacked { + SymbolPacked(){} + SymbolPacked(ScopedSymbol i, ScopePacked s): identifier(i.id), version(i.version), scope(s){} + SymbolPacked(VNameId symbolId, versions::VariableVersion symbolVersion, ScopePacked symbolScope) + : identifier(symbolId), version(symbolVersion), scope(symbolScope){} + + VNameId identifier; + versions::VariableVersion version; + ScopePacked scope; +}; + + +bool operator==(const SymbolPacked& s1, const SymbolPacked& s2); +bool operator<(const SymbolPacked& s1, const SymbolPacked& s2); + +struct SymbolAnonymous { + unsigned int id; + bool flagIsUsed = false; +}; + +bool operator==(const SymbolAnonymous& s1, const SymbolAnonymous& s2); + +typedef boost::variant SymbolNode; + +//DEBT use SymbolGeneralized communicating with Analysis rather than Symbol +typedef boost::variant SymbolGeneralized; + +template<> +struct AttachmentsId{ + static unsigned int getId(const SymbolGeneralized& symbol); +}; + +} namespace std { + + template<> + struct hash { + std::size_t operator()(xreate::SymbolNode const& s) const noexcept; + }; + + template<> + struct hash { + std::size_t operator()(xreate::SymbolGeneralized const& s) const noexcept; + }; +} + +namespace xreate { + +enum class DFGConnection { + STRONG, WEAK, PROTOTYPE +}; + +/** \brief Designated to mark analysis results that can be composed as *logic program* */ +class IAnalysisReport { +public: + /** \brief Composes *logic program* based on analysis data into ASP format and appends to a stream*/ + virtual void print(std::ostringstream& output) const = 0; + virtual ~IAnalysisReport(){}; +}; + +/** \brief Logic program query interface */ +class IQuery { +public: + virtual void init(TranscendLayer* transcend) = 0; + virtual ~IQuery() {} +}; + +enum class QueryId { + ContainersQuery, + PolymorphQuery, + LatexQuery +}; + +namespace dfa{ + class DFAGraph; +} + +namespace cfa { + class CFAGraph; +} + +typedef std::multimap StaticModel; +typedef StaticModel::const_iterator StaticModelIterator; + +class TranscendLayer { +friend class ContextRule; + + /**\name Data Providers Management */ +///@{ +public: + void registerReport(IAnalysisReport* report); + void runReports(); + + /** \brief Appends arbitrary string to *logic program* + */ + void addRawScript(std::string&& script); + +private: + std::list __reports; + + /** Includes external text files to a *logic program* */ + void involveImports(); +///@} + + /**\name Queries Management */ +///@{ +public: + /** \brief Adds query. See xreate::IQuery */ + IQuery* registerQuery(IQuery* query, const QueryId& id); + + /** \brief Returns particular query. See xreate::IQuery */ + IQuery* getQuery(const QueryId& id); + + template + static std::tuple parse(const Gringo::Symbol& atom); + StaticModel query(const std::string& atom) const; + size_t getScopesCount() const; + SymbolPacked pack(const Symbol& symbol, std::string hintSymbolName = ""); + ScopePacked pack(const CodeScope * const scope); + Symbol unpack(const SymbolPacked& symbol) const; + SymbolNode pack(const SymbolGeneralized& symbol, const std::string& hintSymbolName); + SymbolGeneralized unpack(const SymbolNode& symbol) const; + std::string getHintForPackedSymbol(const SymbolPacked& symbol); +///@} + +private: + std::map __queries; + std::map __indexSymbolNameHints; + std::unordered_map __indexScopes; + std::vector __registryScopes; + + /**\name Diagnostic */ +///@{ +//TODO diagnostic move over to separate provider/query +public: + /** \brief Adds diagnostic rule */ + void addRuleWarning(const RuleWarning &rule); + + /** \brief Registers diagnostic messages */ + unsigned int registerWarning(std::string &&message); + +private: + std::map __warnings; + void printWarnings(std::ostream& out); +///@} + +///@{ +public: + TranscendLayer(); + + /** \brief Executes reasoning */ + void run(); +///@} + AST *ast; + +protected: + virtual bool processSolution(Gringo::Model const &model); + +private: + StaticModel __model; + std::ostringstream __partTags; + std::ostringstream __partGeneral; +}; + +template +struct ParseImplAtom { + static typ get(const Gringo::Symbol& atom) { + return atom.num(); + } +}; + +template<> +struct ParseImplAtom { + static int get(const Gringo::Symbol& atom); +}; + +template<> +struct ParseImplAtom { + static std::string get(const Gringo::Symbol& atom); +}; + +template<> +struct ParseImplAtom { + static SymbolPacked get(const Gringo::Symbol& atom); +}; + +template<> +struct ParseImplAtom { + static SymbolNode get(const Gringo::Symbol& atom); +}; + +template<> +struct ParseImplAtom { + static Gringo::Symbol get(const Gringo::Symbol& atom); +}; + +template +struct ParseImplAtom>{ + static std::list + get(const Gringo::Symbol& atom){ + bool flagIsList = (atom.type() == Gringo::SymbolType::Fun) && atom.name().empty(); + std::list result; + + if(!flagIsList) { + //treat as degenerate case: list with a single element + result.push_back(ParseImplAtom::get(atom)); + return result; + } + + for (const Gringo::Symbol& arg: atom.args()) { + result.push_back(ParseImplAtom::get(arg)); + } + + return result; + } +}; + +template<> +struct ParseImplAtom { + static Expression get(const Gringo::Symbol& atom); +}; + +template +struct Parse_Impl { + static void parse(Tuple& tup, Gringo::SymSpan::iterator arg) { + const size_t tupleSize = std::tuple_size::value; + typedef typename std::tuple_element < tupleSize - index, Tuple>::type ElType; + + ElType& el = std::get < tupleSize - index > (tup); + + Gringo::Symbol atom = *arg; + el = ParseImplAtom::get(atom); + + Parse_Impl ::parse(tup, ++arg); + } +}; + +template +struct Parse_Impl { + static void parse(Tuple& tup, Gringo::SymSpan::iterator arg) { + } +}; + +template +std::tuple +TranscendLayer::parse(const Gringo::Symbol& atom) { + typedef std::tuple < Types...> Tuple; + Tuple tup; + Parse_Impl::value>::parse(tup, atom.args().first); + + return tup; +} +} //end of xreate namespace +#endif diff --git a/cpp/src/utils.cpp b/cpp/src/utils.cpp index 693a00e..b138bff 100644 --- a/cpp/src/utils.cpp +++ b/cpp/src/utils.cpp @@ -1,9 +1,38 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * utils.cpp + * + * Author: pgess + */ + +/** + * \file utils.h + * \brief Auxiliary code + */ + #include "utils.h" +#include using namespace xreate; Config Config::__self = Config(); Config::Config() : __storage{json_file{ "config/default.json" }} {} + +using boost::locale::conv::utf_to_utf; + +std::wstring +utf8_to_wstring(const std::string& str) +{ + return utf_to_utf(str.c_str(), str.c_str() + str.size()); +} + +std::string +wstring_to_utf8(const std::wstring& str) +{ + return utf_to_utf(str.c_str(), str.c_str() + str.size()); +} diff --git a/cpp/src/utils.h b/cpp/src/utils.h index a2f9b28..b45173b 100644 --- a/cpp/src/utils.h +++ b/cpp/src/utils.h @@ -1,134 +1,167 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * utils.cpp + * + * Author: pgess + */ + #ifndef UTILS_H #define UTILS_H #include "jeayeson/jeayeson.hpp" -//TODO use type mark to mark dirty/mutable members +namespace xreate { + +template +struct AddTag { -/* -template -struct DdesctructableClass { + explicit + AddTag(const Source &src) + : __src(src) { } -} -*/ -/* -template -struct TagUpdatable{ - TagUpdatable(const OriginalType& source) - : __source(source) - {} + explicit + AddTag(Source &&src) + : __src(std::move(src)) { } - TagUpdatable() = delete; + operator const Source&() const{ + return __src; + } - const OriginalType& __source; -}; + const Source& get() const{ + return __src; + } + const Source* + operator->() const { + return &__src; + } -struct Updatable; +private: + Source __src; +}; -template -struct TagsDictionary -{}; +struct Expand_t{}; +template +using Expanded = AddTag; + +//DEBT move to resources compiler. https://github.com/markusfisch/cpprc +class Config { +private: + json_map __storage; + static Config __self; + Config(); + +public: + static std::string get(std::string key) { + return __self.__storage.get_for_path(key).get(); + } +}; -template -struct TagsDictionary -{ - typedef TagUpdatable TagName; +/** \brief Decorators support */ +template +struct DecoratorsDict{ + //typedef ConcreteDecoratorForTag result; }; -template -struct awareOf -{ - awareOf(OT& dest) - : __dest(dest) - {} - - awareOf& - operator= (const typename TagsDictionary::TagName& source) - { - __dest = source.__source; - } +template +struct Decorators{ + typedef typename DecoratorsDict::result Instance; -private: - OT& __dest; + template + static Instance* getInterface(Base* obj){ + Instance* result = dynamic_cast< Instance* > (obj); + assert(result); + + return result; + } }; -template> -const OT& -awareOf(const Tag& holder) -{ - return std::forward(holder.__source); -} +template +struct ManagedPtr { + static ManagedPtr Invalid() { + return ManagedPtr(); + } - */ + ManagedPtr() : __storage(0) { + } -namespace xreate { - template - struct AddTag { + ManagedPtr(unsigned int id, const std::vector* storage) + : __id(id), __storage(storage) { + } - explicit - AddTag(const Source &src) - : __src(src) { } + Target& + operator*() const { + assert(isValid() && "Invalid Ptr"); + return *__storage->at(__id); + } - explicit - AddTag(Source &&src) - : __src(std::move(src)) { } + void operator=(const ManagedPtr& other) { + __id = other.__id; + __storage = other.__storage; + } - operator const Source&() const{ - return __src; - } + bool + operator==(const ManagedPtr& other) { + return isValid() && (__id == other.__id); + } + + Target* + operator->() const noexcept { + assert(isValid() && "Invalid Ptr"); + return __storage->at(__id); + } - const Source& get() const{ - return __src; - } + inline bool isValid() const { + return (__storage) && (0 <= __id) && (__id < __storage->size()); + } - const Source* - operator->() const { - return &__src; - } + inline operator bool() const { + return isValid(); + } - private: - Source __src; - }; + ManagedPtr& operator++() { + ++__id; + return *this; + } - struct Expand_t{}; - template - using Expanded = AddTag; - + inline unsigned int id() const { + return __id; + } +private: + unsigned int __id = 0; + const std::vector * __storage = 0; +}; - //DEBT move to resources compiler. https://github.com/markusfisch/cpprc - class Config { - private: - json_map __storage; - static Config __self; - Config(); - - public: - static std::string get(std::string key) { - return __self.__storage.get_for_path(key).get(); - } - }; } +std::wstring +utf8_to_wstring(const std::string& str); + +std::string +wstring_to_utf8(const std::wstring& str); + + #define RST "\x1B[0m" #define KRED "\x1B[31m" #define KGRN "\x1B[32m" #define KYEL "\x1B[33m" #define KBLU "\x1B[34m" #define KMAG "\x1B[35m" #define KCYN "\x1B[36m" #define KWHT "\x1B[37m" #define FRED(x) KRED << x << RST #define FGRN(x) KGRN < + * Created on July 3, 2017, 6:03 PM + */ + +#include "xreatemanager.h" +#include "pass/abstractpass.h" +#include "aux/transcend-decorators.h" +#include "aux/xreatemanager-decorators.h" +#include "llvmlayer.h" +#include +#include + +namespace xreate { +void +PassManager::registerPass(IPass* pass, const PassId& id, IPass* parent) +{ + __passes.emplace(id, pass); + __passDependencies.emplace(parent, pass); +} + +IPass* +PassManager::getPassById(const PassId& id){ + assert(__passes.count(id)); + return __passes[id]; +} + +bool +PassManager::isPassRegistered(const PassId& id){ + return __passes.count(id); +} + +void +PassManager::executePasses(){ + std::list passes{nullptr}; + while (passes.size()){ + IPass* parent = passes.front(); + + auto range = __passDependencies.equal_range(parent); + + for (auto i=range.first; i!=range.second; ++i){ + IPass* pass = i->second; + + pass->run(); + pass->finish(); + + passes.push_back(pass); + } + + passes.pop_front(); + } +} + +void +PassManager::prepare(AST* ast){ + root = ast; + transcend = new DefaultTranscendLayerImpl(); + transcend->ast = ast; + llvm = new LLVMLayer(ast); +} + +PassManager::~PassManager(){} + +typedef XreateManagerDecoratorFull XreateManagerDecoratorDefault; + +namespace details{ namespace tier2{ + +XreateManager* +XreateManager::prepare(std::string&& code){ + auto man = new XreateManagerImpl; + + man->prepareCode(std::move(code)); + return man; +} + +XreateManager* +XreateManager::prepare(FILE* code){ + auto man = new XreateManagerImpl; + + man->prepareCode(code); + return man; +} +}} + +namespace details { namespace tier1 { + +XreateManager* +XreateManager::prepare(std::string&& code){ + auto man = new XreateManagerImpl; + + man->prepareCode(std::move(code)); + return man; +} + +XreateManager* +XreateManager::prepare(FILE* code){ + auto man = new XreateManagerImpl; + + man->prepareCode(code); + return man; +} + +}} + +/** + * \class xreate::XreateManager + * \brief Entry point of Xreate API + * + * Manages whole Xreate's internal workflow. There are 4 distinctive stages covered by XreateManager: + * - initPasses() To init passes + * - executePasses() To execute passes + * - analyse() To run reasoner + * - run() To run compiler + * + * For adaptability manager comes with several *Frontends*: + * - xreate::details::tier2::XreateManager has all stages accessible by client for full control + * - xreate::details::tier1::XreateManager has only analyse() and run(), where analyse() combines execution of all previous stages + * - xreate::XreateManager has only run() to combine all stages for convenient use + * + * Moreover there are *Backends*: + * - xreate::XreateManagerDecoratorBase Simple backend intended for inheritance without much functionality + * - XreateManagerDecoratorFull Backend intended to initialize all builtin passes + * + * Thus, client's code could combine desired frontend and desired backend as see fit. + * Default xreate::XreateManager connects full backend to init all builtin passes + * to a simplest frontend with only run() available to execute all stages at once + */ + +/** + *\brief Constructs XreateManager for a given code + */ +XreateManager* +XreateManager::prepare(std::string&& code) { + auto man = new XreateManagerImpl; + + man->prepareCode(std::move(code)); + return man; +} + +/** + *\brief Constructs XreateManager for a given script file + */ +XreateManager* +XreateManager::prepare(FILE* code){ + auto man = new XreateManagerImpl; + + man->prepareCode(code); + return man; +} + +} diff --git a/cpp/src/xreatemanager.h b/cpp/src/xreatemanager.h new file mode 100644 index 0000000..5609a31 --- /dev/null +++ b/cpp/src/xreatemanager.h @@ -0,0 +1,141 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * xreatemanager.h + * + * Author: pgess + * Created on July 3, 2017, 6:03 PM + */ + +/** + * \file + * \brief Entry point of Xreate API. + * + */ + +#ifndef PASSMANAGER_H +#define PASSMANAGER_H + +#include +#include + +//stdio external +struct _IO_FILE; +typedef struct _IO_FILE FILE; + +namespace xreate { namespace grammar { namespace main { + class Scanner; +}}} + +namespace xreate { +class IPass; +class TranscendLayer; +class LLVMLayer; +class AST; + +enum class PassId { + CFAPass, + CompilePass, + DFAPass, + EnvironmentTestsPass, + LoggerPass, + RulesPass, + InterpretationPass, + VersionsPass +}; + +/** + * \class PassManager + * \brief Base class to control passes + */ +class PassManager{ +public: + void prepare(AST* ast); + void registerPass(IPass* pass, const PassId& id, IPass* prerequisite=nullptr); + IPass* getPassById(const PassId& id); + bool isPassRegistered(const PassId& id); + void executePasses(); + + virtual ~PassManager(); + + TranscendLayer* transcend; + LLVMLayer* llvm; + AST* root; + +private: + std::map __passes; + std::multimap __passDependencies; +}; + +namespace details{ namespace tier2{ +class XreateManager: public virtual PassManager{ +public: + virtual ~XreateManager(){}; + + virtual void initPasses()=0; +// virtual void executePasses()=0; + virtual void analyse()=0; + virtual void* run()=0; + + static XreateManager* prepare(std::string&& code); + static XreateManager* prepare(FILE* code); +}; + +template +class XreateManagerImpl: public Decorator { +public: +}; + +}} //namespace details::tier2 + +namespace details{ namespace tier1{ +class XreateManager: public virtual PassManager{ +public: + virtual void analyse()=0; + virtual void* run()=0; + + static XreateManager* prepare(std::string&& code); + static XreateManager* prepare(FILE* code); +}; + +template +class XreateManagerImpl: public XreateManager, public details::tier2::XreateManagerImpl { + typedef details::tier2::XreateManagerImpl PARENT; + + public: + void analyse(){ + PARENT::initPasses(); + PARENT::executePasses(); + PARENT::analyse(); + } + + void* run(){ + return PARENT::run(); + } +}; + +}} //namespace details::tier1 + +class XreateManager: public virtual PassManager{ +public: + virtual void* run()=0; + + static XreateManager* prepare(std::string&& code); + static XreateManager* prepare(FILE* code); +}; + +template +class XreateManagerImpl: public XreateManager, public details::tier1::XreateManagerImpl{ + typedef details::tier1::XreateManagerImpl PARENT; + +public: + void* run(){ + PARENT::analyse(); + return PARENT::run(); + } +}; + +} //namespace xreate + +#endif diff --git a/cpp/tests/CMakeLists.txt b/cpp/tests/CMakeLists.txt index 25f9a64..2d220d4 100644 --- a/cpp/tests/CMakeLists.txt +++ b/cpp/tests/CMakeLists.txt @@ -1,25 +1,56 @@ cmake_minimum_required(VERSION 2.8.11) project(xreate-tests) find_package(GTest REQUIRED) INCLUDE_DIRECTORIES(${GTEST_INCLUDE_DIRS}) INCLUDE_DIRECTORIES("/usr/include/libxml2") INCLUDE_DIRECTORIES($) # TESTS #========================= FIND_PACKAGE (LLVM REQUIRED) message("LLVM_LIBRARY_DIRS: " ${LLVM_LIBRARY_DIRS}) link_directories(${LLVM_LIBRARY_DIRS}) set (LIBCLASP_PATH ${POTASSCO_PATH}/build/debug) link_directories(${LIBCLASP_PATH}) -aux_source_directory(. TEST_FILES) +#aux_source_directory(. TEST_FILES) +set(TEST_FILES + cfa.cpp + latex.cpp + polymorph.cpp + transcend.cpp +# latereasoning.cpp + virtualization.cpp + exploitation.cpp + effects-communication.cpp + association.cpp + main.cpp + modules.cpp + attachments.cpp + ast.cpp + dfa.cpp + compilation.cpp + ExpressionSerializer.cpp + externc.cpp + types.cpp + #vendorsAPI/clangAPI.cpp + #vendorsAPI/xml2.cpp + #vendorsAPI/json.cpp + + containers.cpp + interpretation.cpp + loops.cpp + + #supplemental/versions-algorithm-data_dependency.cpp + effects-versions.cpp +) + add_executable(${PROJECT_NAME} ${TEST_FILES}) target_link_libraries(${PROJECT_NAME} xreate ${GTEST_LIBRARIES} pthread xml2 gcov) add_custom_target (coverage COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/src/code-coverage.sh WORKING_DIRECTORY ${CMAKE_BINARY_DIR}) diff --git a/cpp/tests/ExpressionSerializer.cpp b/cpp/tests/ExpressionSerializer.cpp index c5dc128..bc940f0 100644 --- a/cpp/tests/ExpressionSerializer.cpp +++ b/cpp/tests/ExpressionSerializer.cpp @@ -1,65 +1,68 @@ -/* +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ + * * testExpressionSerializer.cpp * * Created on: Jan 4, 2016 - * Author: pgess + * Author: pgess */ -#include "serialization/expressionserializer.h" +#include "aux/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"))}); + + Expression a(Operator::CALL, {Atom("a"), Atom("a")}); + Expression b(Operator::CALL, {Atom("a"), Atom("b")}); ExpressionSerializer serializer(vector{a, b}); 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 a(Operator::CALL, {Atom("a"), Atom("a")}); + Expression b(Operator::CALL, {Atom("a"), Atom("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/adhoc.cpp b/cpp/tests/adhoc.cpp deleted file mode 100644 index eb9bafb..0000000 --- a/cpp/tests/adhoc.cpp +++ /dev/null @@ -1,160 +0,0 @@ -/* - * adhoc-exceptions.cpp - - * - * Created on: Nov 19, 2015 - * Author: pgess - */ - -class Adhoc_pass_Adhoc1_Test; -#define FRIEND_ADHOC_UNITTESTS \ - friend class ::Adhoc_pass_Adhoc1_Test; - - -#include "ast.h" -#include "passmanager.h" - -#include "gtest/gtest.h" -#include -#include -#include -#include - - -#include "pass/adhocpass.h" -#include "pass/compilepass.h" -#include "llvmlayer.h" - -using namespace xreate; -using namespace std; - -TEST(Adhoc, ast_operatorAdhoc1){ - PassManager* man = PassManager::prepareForCode ( - " test = " - "function:: int {\n" - " ad hoc Exception(NonImplemented)\n" - " }" - ); - - Expression subject = man->root->findFunction("test")->getEntryScope()->getBody(); - ASSERT_EQ(Operator::ADHOC, subject.op); - ASSERT_EQ(1, subject.getOperands().size()); - - Expression exception = subject.getOperands()[0]; - ASSERT_EQ("Exception", exception.getValueString()); -} - -TEST(Adhoc, ast_schemeAdhoc1){ - PassManager* man = PassManager::prepareForCode ( - "interface(adhoc){\n" - " pre function expectNoErrors:: bool {\n" - " case Error {false}\n" - " case Success {true}\n" - " }\n" - " }"); - - assert(man->root->__interfacesData.count(ASTInterface::Adhoc)); - Expression adhocData = man->root->__interfacesData.find(ASTInterface::Adhoc)->second; - ASSERT_EQ(Operator::SWITCH, adhocData.operands[0].op); -} - -TEST(Adhoc, pass_Adhoc1){ - PassManager* man = PassManager::prepareForCode ( - "interface(adhoc){\n" - " pre function expectNoErrors:: bool {\n" - " case Error {false}\n" - " case Success {true}\n" - " }\n" - "}\n" - - "main = function::int; entry {0} \n" - ); - - man->runWithoutCompilation(); - AdhocPass* pass = reinterpret_cast(man->getPassById(PassId::AdhocPass)); - EXPECT_TRUE(pass->__schemes.size() > 0); - - AdhocScheme* scheme = pass->__schemes.begin()->second; - EXPECT_EQ("expectNoErrors", scheme->getContext()); -} - -TEST(Adhoc, full_1){ - PassManager* man = PassManager::prepareForCode ( - " import raw (\"core/control-context.lp\")" - - " interface(adhoc){\n" - " pre function expectNoErrors:: bool {\n" - " case Error {0}\n" - " case Success {1}\n" - " }\n" - " }" - - " test1 = pre function {\n" - " context:: expectNoErrors." - " ad hoc \"Success\"\n" - " }" - - "main = function::bool;entry {\n" - " test1()\n" - " }"); - - bool (*main)() = (bool (*)()) man->run(); - bool result = main(); - ASSERT_EQ(true, result); -} - -TEST(Adhoc, full_contextExpectNoErrrors){ - PassManager* man = PassManager::prepareForCode ( - "import raw (\"core/control-context.lp\")\n" - - "interface(extern-c){\n" - " xml2 = library:: pkgconfig(\"libxml-2.0\").\n" - " \n" - " include {\n" - " xml2 = [\"stdlib.h\"]\n" - " }.\n" - "}" - - "interface(adhoc){\n" - " pre function expectNoErrors:: bool {\n" - " case Error {0}\n" - " case Success {1}\n" - " }\n" - "}\n" - - "expectErrorCode = pre function(x::int){\n" - " if (x==0)::bool {ad hoc \"Success\"}\n" - " else {ad hoc \"Error\"}\n" - "}\n" - - "main = function::bool; entry {\n" - " context:: expectNoErrors." - " expectErrorCode(system(\"ls -la\"))\n" - "}" ); - - int (*main)() = (int (*)()) man->run(); - ASSERT_EQ(1, main()); -} - -TEST(Adhoc, ast_switchAdhoc1){ - PassManager* man = PassManager::prepareForCode ( - "test1 = function:: bool {\n" - " switch ad hoc (x:: errors)\n" - " case ERROR {0}\n" - " case SUCCESS {1}\n" - " \n" - " }" - ); - - Expression eSwitch = man->root->findFunction("test1")->getEntryScope()->getBody(); - EXPECT_EQ(Operator::SWITCH_ADHOC, eSwitch.op); - EXPECT_EQ(3, eSwitch.operands.size()); - - EXPECT_EQ(1, eSwitch.tags.size()); - EXPECT_EQ("errors", eSwitch.tags.begin()->first); - - Expression eCondition = eSwitch.getOperands()[0]; - EXPECT_EQ("x", eCondition.getValueString()); -} - - diff --git a/cpp/tests/association.cpp b/cpp/tests/association.cpp new file mode 100644 index 0000000..ce5964e --- /dev/null +++ b/cpp/tests/association.cpp @@ -0,0 +1,124 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ + * + * association.cpp + * + * Author: pgess + * Created on August 12, 2017, 9:28 PM + */ +#include "xreatemanager.h" +#include "transcendlayer.h" +#include "pass/interpretationpass.h" +#include + +using namespace xreate::interpretation; +using namespace xreate; +using namespace std; + +TEST(Association, TypedQuery_1) { + auto man = ::xreate::details::tier1::XreateManager::prepare(R"Code( + AtomNumT = type slave atomNumT. + AtomStrT = type slave atomStrT. + CompListT = type slave compListT. + CompArithT = type slave compArithT. + + test = function:: num; entry + { + query1 = intrinsic query("atomNumT")::[AtomNumT]. + query2 = intrinsic query("atomStrT")::[AtomStrT]. + query3 = intrinsic query("compListT")::[CompListT]. + query4 = intrinsic query("compArithT")::[CompArithT]. + test1 = query1[0] == 5:: bool. + test2 = query2[1] == "y":: bool. + test3 = query3[0, 1] == "x" :: bool. + test4 = query4[0, 0, 0] == 1:: bool. + + test1 + test2 + test3 + test4 + } + )Code"); + + man->transcend->addRawScript(R"RAW( + atomNumT(5; 8). + atomStrT("x"; "y"). + compListT(5, "x"). + compListT(8, "y"). + compArithT(add(1, 2)). + compArithT(mul(5, 6)). + )RAW"); + + man->analyse(); + int (*test)() = (int (*)())man->run(); + int result = test(); + ASSERT_EQ(4, result); +} + +TEST(Association, QueryLate_ast_1){ + auto man = XreateManager::prepare( +R"Code( + test = function:: num; entry + { + intrinsic query late("dict"->x:: bool)::bool + { + (x == true) + } + } +)Code"); +} + +TEST(Association, QueryLate_pass_1){ + auto man = ::xreate::details::tier1::XreateManager::prepare( +R"Code( + test = function:: num; entry + { + intrinsic query late("dict"->x:: bool)::bool + { + (x == true) + } + } +)Code"); + man->analyse(); + + Expression instructionE = man->root->findFunction("test")->getEntryScope()->getBody(); + InterpretationData instructionData = Attachments::get(instructionE); + ASSERT_EQ(QUERY_LATE, instructionData.op); +} + +TEST(Association, QueryLate_target_1){ + auto man = ::xreate::details::tier1::XreateManager::prepare( +R"Code( + Equipment = type variant {dresser, sink, stove}. + Room = type variant{kitchen, bedroom, bathroom}. + + test = function:: num; entry + { + room = bedroom() :: Room; room. + equipment = intrinsic query late("whatshere"->x:: Equipment)::int; equipment + { if (x == dresser()):: int {1} else {0} }. + + equipment + (room::int) + } +)Code"); + + man->transcend->addRawScript( +R"RAW( + room(kitchen; bedroom; bathroom). + equipment(dresser;sink;stove). + interior(kitchen, stove). + interior(bedroom, dresser). + interior(bathroom, sink). + + late(VarTarget, VarRoom, Room, whatshere(Equipment)):- + bind(VarTarget, equipment); + bind(VarRoom, room); + interior(Room, Equipment); + equipment(Equipment); + room(Room). +)RAW"); + + man->analyse(); + int (*result)() = (int (*)()) man->run(); + ASSERT_EQ(2, result()); +} + + + diff --git a/cpp/tests/ast.cpp b/cpp/tests/ast.cpp index 46c637d..17bee50 100644 --- a/cpp/tests/ast.cpp +++ b/cpp/tests/ast.cpp @@ -1,48 +1,90 @@ -/* +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ + * * ast.cpp * * Created on: Jun 11, 2015 - * Author: pgess + * Author: pgess */ #include "gtest/gtest.h" -#include "passmanager.h" -#include "Parser.h" +#include "xreatemanager.h" +#include "main/Parser.h" using namespace std; using namespace xreate; +using namespace xreate::grammar::main; TEST(AST, Containers1){ - FILE* input = fopen("scripts/testspass/Containers_Implementation_LinkedList1.xreate","r"); - Scanner scanner(input); + FILE* input = fopen("scripts/containers/Containers_Implementation_LinkedList1.xreate","r"); + Scanner scanner(input); Parser parser(&scanner); parser.Parse(); assert(!parser.errors->count && "Parser errors"); fclose(input); } TEST(AST, InterfacesDataCFA) { - PassManager* man = PassManager::prepareForCode + XreateManager* man = XreateManager::prepare ("interface(cfa){\n" " operator map :: annotation1.\n" "}"); auto answer = man->root->__interfacesData.equal_range(CFA); EXPECT_EQ(1, std::distance(answer.first, answer.second)); Expression&& scheme = move(answer.first->second); EXPECT_EQ(Operator::MAP, scheme.op); EXPECT_EQ("annotation1", scheme.getOperands().at(0).getValueString()); } +TEST(AST, syntax_recognizeIdentifiers){ + XreateManager* man = XreateManager::prepare(R"Code( + test= function(a:: num):: num; entry { + a = b:: int. + b = 8:: int. + + a + } + )Code"); +} + +TEST(AST, syntax_operatorIndex){ + XreateManager* man = XreateManager::prepare(R"Code( + test= function(a:: num):: num; entry { + b = a[1]. + b + } + )Code"); +} + +TEST(AST, Variants_switch){ +XreateManager* man = XreateManager::prepare(R"Code( + Color = type variant{Blue, White, Green}. + + main = function:: int { + x = White()::Color. + + switch variant(x)::int + case (Green) {0} + case (White) {1} + case (Blue){2} + } +)Code"); + + Expression e= man->root->findFunction("main")->getEntryScope()->getBody(); + ASSERT_EQ(4, e.getOperands().size()); + ASSERT_EQ(3, e.blocks.size()); +} + TEST(AST, DISABLED_InterfacesDataDFA){ } TEST(AST, DISABLED_InterfacesDataExtern){ } //TODO xreate.atg: replace all Type<> as ExprAnnotations<> diff --git a/cpp/tests/attachments.cpp b/cpp/tests/attachments.cpp new file mode 100644 index 0000000..8655137 --- /dev/null +++ b/cpp/tests/attachments.cpp @@ -0,0 +1,26 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ + * + * attachments.cpp + * + * Author: pgess + * Created on January 22, 2017, 12:16 PM + */ + +#include "attachments.h" +#include "ast.h" + +#include "gtest/gtest.h" + +using namespace xreate; + +TEST(Attachments, basic1){ + AttachmentsContainerDefault* c = new AttachmentsContainerDefault(); + + Expression expTest(Atom(10)); + c->put(expTest, true); + + Expression expTest2(Atom(11)); + + ASSERT_FALSE(c->exists(expTest2)); +} diff --git a/cpp/tests/basic.cpp b/cpp/tests/basic.cpp deleted file mode 100644 index 0deb63b..0000000 --- a/cpp/tests/basic.cpp +++ /dev/null @@ -1,26 +0,0 @@ - -#include "gtest/gtest.h" -#include "passmanager.h" -#include "Scanner.h" -#include "Parser.h" -#include -#include - -using namespace std; -using namespace xreate; - -TEST(Basic, functionEntry1){ - std::unique_ptr program(PassManager::prepareForCode( - "func1 = function(a:: int):: int {a+8} \ - func2 = function::int; entry {12 + func1(4)} \ - ")); - - void* entryPtr = program->run(); - int (*entry)() = (int (*)())(intptr_t)entryPtr; - - int answer = entry(); - ASSERT_EQ(24, answer); -} - - - diff --git a/cpp/tests/cfa.cpp b/cpp/tests/cfa.cpp index f01028c..fff0a97 100644 --- a/cpp/tests/cfa.cpp +++ b/cpp/tests/cfa.cpp @@ -1,119 +1,248 @@ -/* - * testsCFG.cpp +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ + * + * cfa.cpp * * Created on: Jul 17, 2015 - * Author: pgess + * Author: pgess */ -#include "passmanager.h" +#include "xreatemanager.h" #include "pass/dfapass.h" #include "pass/cfapass.h" +#include "analysis/DominatorsAnalysisProvider.h" +#include "analysis/cfagraph.h" -#include "analysis/DominatorsTreeAnalysisProvider.h" +#include "pass/compilepass.h" +#include "compilation/scopedecorators.h" #include "gtest/gtest.h" - +#include "aux/xreatemanager-decorators.h" #include #include +#include using namespace xreate; +using namespace xreate::cfa; using namespace std; -TEST(CFA, testFunctionAnnotationsClasp){ +TEST(CFA, testFunctionAnnotations) { string&& program = "f2 = function::int; annotationF2 {\n" " 0\n" "}\n" "\n" "f1 = function:: int; entry; annotationF1 {\n" " f2() + 10\n" "}"; - PassManager* man = PassManager::prepareForCode(move(program)); - man->runWithoutCompilation(); - - ClaspLayer::ModelFragment answer = man->clasp->query("annotationF1"); - int countNoneValue = 0; - if (answer) countNoneValue = std::distance(answer->first, answer->second); - EXPECT_EQ(1, countNoneValue); + details::tier1::XreateManager* man = details::tier1::XreateManager::prepare(move(program)); + man->analyse(); - answer = man->clasp->query("annotationF2"); - countNoneValue = 0; - if (answer) countNoneValue = std::distance(answer->first, answer->second); + StaticModel answer = man->transcend->query("annotationF1"); + EXPECT_EQ(1, answer.size()); - EXPECT_EQ(1, countNoneValue); + answer = man->transcend->query("annotationF2"); + EXPECT_EQ(1, answer.size()); } -TEST(CFA, testLoopContextExists){ - PassManager* man = PassManager::prepareForCode ( +TEST(CFA, testLoopContextExists) { + details::tier1::XreateManager* man = details::tier1::XreateManager::prepare ( "interface(cfa){\n" " operator fold:: annotation1.\n" "}\n" "\n" "main = function:: int; entry {\n" " x = [1..10]:: [int].\n" " sum = loop fold (x->el:: int, 0->sum):: int {\n" " el + sum + f1()\n" " }. \n" " sum\n" "}" - "case context:: annotation1 {" + "guard:: annotation1 {" " f1 = function::int {\n" " x = 0:: int. " " x\n" " }" "}" - ); + ); - man->runWithoutCompilation(); - ClaspLayer::ModelFragment model = man->clasp->query("annotation1"); - ScopePacked scopeIdActual = std::get<0>(ClaspLayer::parse(model->first->second)); + man->analyse(); + StaticModel model = man->transcend->query("annotation1"); + ScopePacked scopeIdActual = std::get<0>(TranscendLayer::parse(model.begin()->second)); CodeScope* scopeEntry = man->root->findFunction("main")->getEntryScope(); - Symbol symbSum = man->root->findFunction("main")->getEntryScope()->findSymbol("sum"); - CodeScope* scopeExpected = scopeEntry->findDeclaration(symbSum).blocks.front(); + const Expression& exprSum = scopeEntry->getDefinition(scopeEntry->getSymbol("sum")); + CodeScope* scopeExpected = exprSum.blocks.front(); - ScopePacked scopeIdExpected = man->clasp->pack(scopeExpected); + ScopePacked scopeIdExpected = man->transcend->pack(scopeExpected); ASSERT_EQ(scopeIdExpected, scopeIdActual); } -TEST(CFA, CFGRoots){ - std::string program = -R"CODE( - main = function::int{a()+ b()} - a= function::int {c1() + c2()} - b= function::int {c2()} - c1=function::int{0} - c2=function::int{0} -)CODE"; +TEST(CFA, DependenciesFnCall) { + details::tier2::XreateManager* man = details::tier2::XreateManager::prepare( + R"Code( + a = function::int{ + seq + {x = 0:: int. x} + {x = b():: int. x}::int + } + + b = function::int {y = 0. y} + )Code"); - boost::scoped_ptr manager - (PassManager::prepareForCode(move(program))); + CodeScope* scopeSeq1 = man->root->findFunction("a")->getEntryScope()->getBody().blocks.front(); + CodeScope* scopeSeq2 = *(++man->root->findFunction("a")->getEntryScope()->getBody().blocks.begin()); + CodeScope* scopeB = man->root->findFunction("b")->getEntryScope(); - manager->registerPass(new CFAPass(manager.get()) , PassId::CFGPass); - manager->executePasses(); - manager->clasp->run(); + ScopePacked psSeq1 = man->transcend->pack(scopeSeq1); + ScopePacked psSeq2 = man->transcend->pack(scopeSeq2); + ScopePacked psB = man->transcend->pack(scopeB); - DominatorsTreeAnalysisProvider domProvider; - domProvider.run(manager->clasp); + CFAPass* pass = new CFAPass(man); - DominatorsTreeAnalysisProvider::Dominators expectedFDom= { + man->registerPass(pass, PassId::CFAPass); + man->executePasses(); + const CFAGraph* report = dynamic_cast (man->getPassById(PassId::CFAPass))->getReport(); + auto dependencies = report->__dependencyRelations; + delete pass; + + ASSERT_EQ(1, dependencies.count(psSeq2)); + ASSERT_EQ(1, dependencies.count(psB)); +} + +TEST(CFA, DependenciesChildScope) { + details::tier2::XreateManager* man = details::tier2::XreateManager::prepare( + R"Code( + a = function::int{ + seq + {x = 0:: int. x} + {x=0::int. if(x>0)::int{1} else {0}}::int + } + )Code"); + + CodeScope* scopeSeq1 = man->root->findFunction("a")->getEntryScope()->getBody().blocks.front(); + CodeScope* scopeSeq2 = *(++man->root->findFunction("a")->getEntryScope()->getBody().blocks.begin()); + CodeScope* scopeIf1 = scopeSeq2->getBody().blocks.front(); + CodeScope* scopeIf2 = *(++scopeSeq2->getBody().blocks.begin()); + + ScopePacked psSeq1 = man->transcend->pack(scopeSeq1); + ScopePacked psSeq2 = man->transcend->pack(scopeSeq2); + ScopePacked psIf1 = man->transcend->pack(scopeIf1); + ScopePacked psIf2 = man->transcend->pack(scopeIf2); + + CFAPass* pass = new CFAPass(man); + + man->registerPass(pass, PassId::CFAPass); + man->executePasses(); + const CFAGraph* report = dynamic_cast (man->getPassById(PassId::CFAPass))->getReport(); + auto dependencies = report->__dependencyRelations; + delete pass; + + ASSERT_EQ(0, dependencies.count(psSeq1)); + ASSERT_EQ(1, dependencies.count(psSeq2)); + ASSERT_EQ(1, dependencies.count(psIf1)); + ASSERT_EQ(1, dependencies.count(psIf2)); + + for(auto rec : dependencies) { + std::cout << rec.first << " " << rec.second << std::endl; + } +} + +TEST(CFA, Dominators1){ + std::multimap dataScopes = { + {1, 0}, {2, 0}, {3, 1}, {4, 1}, {4, 2} + }; + + dominators::DominatorsAnalysisProvider domProvider; + boost::scoped_ptr adapter(dominators::CFAGraphAdapter::build(dataScopes)); + domProvider.run(adapter.get()); + + dominators::DominatorsAnalysisProvider::Dominators expectedFDom= { {0, {0, 9}} ,{1, {1, 4}} ,{2, {7, 8}} ,{3, {2, 3}} ,{4, {5, 6}} }; - DominatorsTreeAnalysisProvider::Dominators expectedPostDom= { + dominators::DominatorsAnalysisProvider::Dominators expectedPostDom= { {0, {5, 6}} ,{1, {3, 4}} ,{2, {8, 9}} ,{3, {1, 2}} ,{4, {7, 10}} }; ASSERT_EQ(expectedFDom, domProvider.getForwardDominators()); ASSERT_EQ(expectedPostDom, domProvider.getPostDominators()); } + +TEST(CFA, Dominators2) { + std::string program = + R"CODE( + a = function:: int; entry{ + seq + {x = 0:: int. x} + {x = 1:: int. x}::int + } +)CODE"; + + std::unique_ptr man(details::tier2::XreateManager::prepare(move(program))); + + CFAPass* pass = new CFAPass(man.get()); + man->registerPass(pass, PassId::CFAPass); + pass->run(); + + ScopePacked scope1 = man->transcend->pack(man->root->findFunction("a")->getEntryScope()->getBody().blocks.front()); + ScopePacked scope2 = man->transcend->pack(*++man->root->findFunction("a")->getEntryScope()->getBody().blocks.begin()); + + dominators::DominatorsAnalysisProvider* providerDomAnalysis = new dominators::DominatorsAnalysisProvider(); + boost::scoped_ptr adapter(dominators::CFAGraphAdapter::build(pass->getReport())); + providerDomAnalysis->run(adapter.get()); + + dominators::DominatorsAnalysisProvider::Dominators expectedFDom = { + {1, {0, 3}}, + {2, {1, 2}} + }; + + dominators::DominatorsAnalysisProvider::Dominators expectedPostDom = { + {2, {1, 4}}, + {1, {2, 3}} + }; + + auto actualFDom = providerDomAnalysis->getForwardDominators(); + auto actualPostDom = providerDomAnalysis->getPostDominators(); + + ASSERT_EQ(expectedFDom, actualFDom); + ASSERT_EQ(expectedPostDom, actualPostDom); + + delete providerDomAnalysis; + delete pass; +} + +TEST(CFA, ASTCorrespondence_Scope_Bindings_1){ + std::string program = +R"CODE( + test = function(x::int, y::int):: int; entry{ + x + y + } +)CODE"; + + std::unique_ptr man(details::tier2::XreateManager::prepare(move(program))); + CFAPass* pass = new CFAPass(man.get()); + man->registerPass(pass, PassId::CFAPass); + man->executePasses(); + + testing::internal::CaptureStdout(); + man->analyse(); + std::string outputActual = testing::internal::GetCapturedStdout(); + cout << outputActual << endl; + + string outputExpected = "ast_scope_binding(0,0,\"x\")"; + ASSERT_NE(std::string::npos, outputActual.find(outputExpected)); + + outputExpected = "ast_scope_binding(0,1,\"y\")"; + ASSERT_NE(std::string::npos, outputActual.find(outputExpected)); +} diff --git a/cpp/tests/compilation.cpp b/cpp/tests/compilation.cpp index e5371df..11cef99 100644 --- a/cpp/tests/compilation.cpp +++ b/cpp/tests/compilation.cpp @@ -1,80 +1,228 @@ -#include "passmanager.h" +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ + * + * compilation.cpp + * + * Created on: - + * Author: pgess + */ + +#include "xreatemanager.h" #include "gtest/gtest.h" using namespace xreate; //DEBT implement no pkgconfig ways to link libs - //TOTEST FunctionUnit::compileInline -TEST(Compilation, DISABLED_functionInline1){ + +TEST(Compilation, functionEntry1){ + std::unique_ptr program(XreateManager::prepare( + "func1 = function(a:: int):: int {a+8} \ + func2 = function::int; entry {12 + func1(4)} \ + ")); + + void* entryPtr = program->run(); + int (*entry)() = (int (*)())(intptr_t)entryPtr; + + int answer = entry(); + ASSERT_EQ(24, answer); } -TEST(Compilation, 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" - " ]" - "}" +TEST(Compilation, full_IFStatementWithVariantType){ + XreateManager* man = XreateManager::prepare( + "Color = type variant {RED, BLUE, GREEN}.\n" + "\n" + " main = function(x::int):: bool; entry {\n" + " color = if (x == 0 )::Color {RED()} else {BLUE()}.\n" + " if (color == BLUE())::bool {true} else {false}\n" + " }" ); + bool (*main)(int) = (bool (*)(int)) man->run(); + ASSERT_FALSE(main(0)); + ASSERT_TRUE(main(1)); +} + +TEST(Compilation, full_Variant1){ + XreateManager* man = XreateManager::prepare(R"Code( + OneArgument = type{x::int}. + TwoArguments = type{x::int, y::int}. + + Command= type variant{ + Add::TwoArguments, + Dec::OneArgument + }. + + main = function::Command; entry { + Dec({x=2})::Command + } + )Code"); + + void (*main)() = (void (*)()) man->run(); +} + +TEST(Compilation, full_SwitchVariant1){ + XreateManager* man = XreateManager::prepare(R"Code( + OneArgument = type{x::int}. + TwoArguments = type{x::int, y::int}. + + Command= type variant{ + Add::TwoArguments, + Dec::OneArgument + }. + + main = function::int; entry { + //command = Dec({x = 8}):: Command. + command = Add({x= 3, y= 5}):: Command. + + switch variant(command)::int + case(Add){command["x"] + command["y"]} + case(Dec){command["x"]} + } + )Code"); + + int (*mainFn)() = (int (*)()) man->run(); + int result = mainFn(); + ASSERT_EQ(8, result); +} + +TEST(Compilation, full_SwitchVariantNoArguments2){ + XreateManager* man = XreateManager::prepare(R"Code( + Command= type variant{Add, Dec}. + + main = function::int; entry { + command = Dec():: Command. + + switch variant(command)::int + case(Add){0} + case(Dec){1} + } + )Code"); + + int (*mainFn)() = (int (*)()) man->run(); + int result = mainFn(); + ASSERT_EQ(1, result); +} + +TEST(Compilation, full_SwitchVariantMixedArguments3){ + XreateManager* man = XreateManager::prepare(R"Code( + TwoArguments = type{x::int, y::int}. + Command= type variant{ + Add::TwoArguments, + Dec + }. + + main = function(arg::int):: int; entry { + command = if (arg > 0)::Command {Dec()} else {Add({x=1,y=2})}. + + switch variant(command)::int + case(Add){0} + case(Dec){1} + } + )Code"); + + int (*mainFn)(int) = (int (*)(int)) man->run(); + int result = mainFn(5); + ASSERT_EQ(1, result); +} + +TEST(Compilation, full_StructUpdate){ + XreateManager* man = XreateManager::prepare( + R"Code( + + Rec = type { + a :: int, + b:: int + }. + + test= function:: int; entry { + a = {a = 18, b = 20}:: Rec. + + b = a + {a = 11}:: Rec. + b["a"] + } + )Code"); + int (*main)() = (int (*)()) man->run(); + int result = main(); - testing::internal::CaptureStdout(); - main(); - std::string output = testing::internal::GetCapturedStdout(); + ASSERT_EQ(11, result); +} - ASSERT_STREQ("FIRST->SECOND", output.c_str()); +TEST(Compilation, AnonymousStruct_init_index){ + std::string code = +R"Code( + + main = function:: int; entry { + x = {10, 15} :: {int, int}. + x[1] + } + +)Code"; + + std::unique_ptr man(XreateManager::prepare(move(code))); + int (*main)() = (int (*)()) man->run(); + + EXPECT_EQ(15, main()); } -TEST(Compilation, Sequence2){ - 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" - " context:: expectNoErrors. " - " buf1 = \"aaaaa\"::string.\n" - " buf2 = \"aaaaa\"::string.\n" - " sequence [" - " sprintf(buf1, \"%d\", system(\"bazaar --version\"))," - " sprintf(buf2, \"%d\", system(\"svn --version\"))," - " printf(buf1),\n" - " printf(buf2)\n" - "]" - "}" - ); +TEST(Compilation, AnonymousStruct_init_update){ + std::string code = +R"Code( + + main = function:: int; entry { + x = {10, 15} :: {int, int}. + y = x + {6}:: {int, int}. + y[0] + } +)Code"; + + std::unique_ptr man(XreateManager::prepare(move(code))); int (*main)() = (int (*)()) man->run(); - main(); + + EXPECT_EQ(6, main()); } +TEST(Compilation, BugIncorrectScopes1){ + std::string code = +R"Code( -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" - " }" - ); + init = function:: int {10} + main = function(cmd:: int):: int; entry { + x = init():: int. + if(cmd > 0):: int { x + 1 } else { x } + } +)Code"; + + std::unique_ptr man(XreateManager::prepare(move(code))); + int (*mainFn)(int) = (int (*)(int)) man->run(); - int (*main)(int) = (int (*)(int)) man->run(); - ASSERT_EQ(0, main(0)); - ASSERT_EQ(1, main(1)); + EXPECT_EQ(11, mainFn(1)); } +TEST(Compilation, Sequence1){ + std::string code = +R"Code( + interface(extern-c){ + libbsd = library:: pkgconfig("libbsd"). + + include { + libbsd = ["bsd/stdlib.h", "string.h"] + }. + } + + start = function:: i32; entry { + seq { + nameNew = "TestingSequence":: string. + setprogname(nameNew) + + } {strlen(getprogname())}::i32 + } +)Code"; + + std::unique_ptr man(XreateManager::prepare(move(code))); + int (*startFn)() = (int (*)()) man->run(); + + int nameNewLen = startFn(); + ASSERT_EQ(15, nameNewLen); +} diff --git a/cpp/tests/containers.cpp b/cpp/tests/containers.cpp index 9d044d5..a68b8cd 100644 --- a/cpp/tests/containers.cpp +++ b/cpp/tests/containers.cpp @@ -1,96 +1,103 @@ -/* +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ + * * containers.cpp * * Created on: Jun 9, 2015 - * Author: pgess + * Author: pgess */ -#include "passmanager.h" +#include "xreatemanager.h" #include "query/containers.h" -#include "Parser.h" +#include "main/Parser.h" #include "gtest/gtest.h" using namespace std; +using namespace xreate::grammar::main; +using namespace xreate::containers; using namespace xreate; -using namespace containers; TEST(Containers, ListAsArray){ - PassManager* man = PassManager::prepareForCode( + XreateManager* man = XreateManager::prepare( R"Code( main = function(x:: int):: int;entry { a = [1, 2, 3]:: [int]. a[x] } )Code" ); void* mainPtr = man->run(); int (*main)(int) = (int (*)(int))mainPtr; ASSERT_EQ(2, main(1)); delete man; } TEST(Containers, ListAsArray2){ - PassManager* man = PassManager::prepareForCode( + XreateManager* man = XreateManager::prepare( R"Code( + // CONTAINERS + import raw("scripts/dfa/ast-attachments.lp"). + import raw("scripts/containers/containers.lp"). + main = function:: int;entry { a= [1, 2, 3]:: [int]. b= loop map(a->el:: int):: [int]{ 2 * el }. sum = loop fold(b->el:: int, 0->acc):: int { acc + el }. sum } -)Code" ); +)Code"); void* mainPtr = man->run(); int (*main)() = (int (*)())mainPtr; - ASSERT_EQ(0, main()); + ASSERT_EQ(12, main()); delete man; } TEST(Containers, ContanierLinkedList1){ - FILE* input = fopen("scripts/testspass/Containers_Implementation_LinkedList1.xreate","r"); + FILE* input = fopen("scripts/containers/Containers_Implementation_LinkedList1.xreate","r"); assert(input != nullptr); Scanner scanner(input); Parser parser(&scanner); parser.Parse(); - AST& ast = parser.root; - CodeScope* body = ast.findFunction("test")->getEntryScope(); - Symbol symb_chilrenRaw = body->findSymbol("childrenRaw"); + AST* ast = parser.root->finalize(); + CodeScope* body = ast->findFunction("test")->getEntryScope(); + const Symbol symb_chilrenRaw{body->getSymbol("childrenRaw"), body}; containers::ImplementationLinkedList iLL(symb_chilrenRaw); ASSERT_EQ(true, static_cast(iLL)); ASSERT_EQ("next", iLL.fieldPointer); Implementation impl = Implementation::create(symb_chilrenRaw); ASSERT_NO_FATAL_FAILURE(impl.extract()); ImplementationRec recOnthefly = impl.extract(); ASSERT_EQ(symb_chilrenRaw, recOnthefly.source); } TEST(Containers, Implementation_LinkedListFull){ - FILE* input = fopen("scripts/testspass/Containers_Implementation_LinkedList1.xreate","r"); + FILE* input = fopen("scripts/containers/Containers_Implementation_LinkedList1.xreate","r"); assert(input != nullptr); - std::unique_ptr program(PassManager::prepareForCode(input)); + std::unique_ptr program(XreateManager::prepare(input)); void* mainPtr = program->run(); int (*main)() = (int (*)())(intptr_t)mainPtr; int answer = main(); ASSERT_EQ(17, answer); fclose(input); } diff --git a/cpp/tests/context.cpp b/cpp/tests/context.cpp deleted file mode 100644 index 847dab1..0000000 --- a/cpp/tests/context.cpp +++ /dev/null @@ -1,495 +0,0 @@ -/* - * frame-context.cpp - * - * Created on: Dec 3, 2015 - * Author: pgess - */ - -#include "passmanager.h" -#include "query/context.h" - -#include "gtest/gtest.h" -#include -#include - -using namespace xreate; - -TEST(Context, frame_Context1){ - PassManager* man = PassManager::prepareForCode( - " import raw (\"core/control-context.lp\")\n" - " compute = function::int {\n" - " 0\n" - " }\n" - - " computeFast = function:: int {\n" - " context:: computation(fast).\n" - - " compute()\n" - " }\n" - - " computePrecisely = function:: int {\n" - " context:: computation(precise). \n" - - " compute()\n" - " }\n" - - "test = function(cmnd:: int):: int; entry {\n" - " context:: arithmetic(iee754). \n" - - " if (cmnd > 0)::int {computePrecisely()} else {computeFast()} \n" - "}\n" - ); - - ContextQuery* query = (ContextQuery*) man->clasp->registerQuery(new ContextQuery(), QueryId::ContextQuery); - man->runWithoutCompilation(); - - CodeScope* scopeTestC = man->root->findFunction("compute")->getEntryScope(); - const Domain& context = query->getContext(man->clasp->pack(scopeTestC)); - - int contextSize = context.size(); - EXPECT_EQ(1, contextSize); //arithmetic(iee754) -} - -TEST(Context, contextAsRequirementSuccessful1){ - PassManager* man = PassManager::prepareForCode( - " import raw (\"core/control-context.lp\")\n" - - " case context::safe {\n" - " funcSensitive = function::int {\n" - " 0\n" - " }}\n" - - " test = function:: int; entry {\n" - " context:: safe; test.\n" - - " funcSensitive()\n" - " }\n" - ); - - int (*main)() = (int (*)()) man->run(); - ASSERT_EQ(0, main()); -} - -TEST(Context, contextAsRequirementFailed){ - PassManager* man = PassManager::prepareForCode( - " import raw (\"core/control-context.lp\")\n" - - " case context::safe {\n" - " funcSensitive = function::int {\n" - " 0\n" - " }}\n" - - " test = function:: int; entry {\n" - " context:: non_safe; test.\n" - - " funcSensitive()\n" - " }\n" - ); - - ASSERT_DEATH(man->run(), "findFunction"); -} - -TEST(Context, ContextPropagationNested){ - PassManager* man = PassManager::prepareForCode( - " import raw (\"core/control-context.lp\")\n" - - " case context::safe {\n" - " square = function(x:: int) ::int {\n" - " x * x\n" - " }}\n" - - " test = function:: int; entry {\n" - " context:: safe; test.\n" - - " range = [1..10]:: [int]. \n" - " loop fold(range->x::int, 0->acc):: int { \n" - " acc + square(x) \n" - " } \n" - " }\n" - ); - - int (*main)() = (int (*)()) man->run(); - ASSERT_EQ(385, main()); -} - -TEST(Context, ContextPropagationNestedInterfunction){ - - PassManager* man = PassManager::prepareForCode( - " import raw (\"core/control-context.lp\")\n" - " case context::toMillimeters {\n" - " convertConcrete = function(source:: num)::num {\n" - " 10 * source \n" - " }\n" - " }\n" - - " case context::toInches {\n" - " convertConcrete = function(source:: num)::num {\n" - " 2 * source \n" - " }\n" - " }\n" - - "convert= function(source:: num):: num { \n" - "convertConcrete(source) \n" - "} \n" - - "test = function(source:: num):: num; entry {\n" - " context:: toMillimeters.\n" - " convert(1)\n" - "}\n" ); - - int (*main)(int) = (int (*)(int)) man->run(); - ASSERT_EQ(10, main(1)); -} - -TEST(Context, full_ContextBasedFunctionSpecialization){ - - PassManager* man = PassManager::prepareForCode( - " import raw (\"core/control-context.lp\")\n" - " 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)); -} - -//TOODO recover context loop and enable the test -TEST(Context, full_LoopContext){ - - PassManager* man = PassManager::prepareForCode( - " import raw (\"core/control-context.lp\")\n" - " 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( - " import raw (\"core/control-context.lp\")\n" - " 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->getBody(); - CodeScope* blockDefault = man->root->findFunction("main")->__entry->getBody().operands[1].blocks.front(); - ScopePacked blockDefaultId = man->clasp->pack(blockDefault); - const Domain& 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 FunctionDemand& demMain = queryContext->getFunctionDemand("main"); - ASSERT_EQ(0, demMain.size()); - - const FunctionDemand& demCalculate = queryContext->getFunctionDemand("calculate"); - ASSERT_EQ(1, demCalculate.size()); - - int (*entry)(int) = (int (*)(int)) man->run(); - ASSERT_EQ(1000, entry(0)); - ASSERT_EQ(100, entry(1)); -} - -TEST(Context, loopContextExists){ - PassManager* man = PassManager::prepareForCode ( - "import raw (\"core/control-context.lp\")\n" - - "interface(cfa){\n" - " operator fold:: annotation1.\n" - "}\n" - "\n" - "main = function:: int; entry {\n" - " x = [1..10]:: [int].\n" - " sum = loop fold (x->el:: int, 0->sum):: int {\n" - " el + sum + f1()\n" - " }. \n" - " sum\n" - "}" - "case context:: annotation1 {" - " f1 = function::int {\n" - " x = 0:: int. " - " x\n" - " }" - "}" - ); - - man->run(); -} - -TEST(Context, pathDependentContext){ - std::string program = -R"CODE( -import raw("core/control-context.lp") - -convert = function(length:: num) :: num { - 0 -} - -case context:: convert(milli, meters) { - convert = function(length:: num) :: num { - 1000 * length - } -} - -case context:: convert(centi, meters) { - convert = function(length:: num) :: num { - 100 * length - } -} - -case context:: convert(centi, kilo) { - convert = function(length:: num) :: num { - 100000 * length - } -} - -case context:: convert(milli, kilo) { - convert = function(length:: num) :: num { - 1000000 * length - } -} - -main = function(value::num, unitsInput::num, unitsOutput::num)::num; entry{ - switch (unitsInput)::num - case 0 { - test_fromMilli(value, unitsOutput) - } - case 1 { - test_fromCenti(value, unitsOutput) - } - - case default {0} -} - -test_fromCenti = function(value::num, output::num)::num{ - context:: input(centi). - - switch(output):: num - case 0 { - toMeters(value) - } - - case 1 { - toKilo(value) - } - - case default {0} -} - -test_fromMilli = function(value::num, output::num)::num{ - context:: input(milli). - - switch(output):: num - case 0 { - toMeters(value) - } - - case 1 { - toKilo(value) - } - - case default {0} -} - -toMeters = function(value::num)::num { - rule context:: convert(X, meters) case input(X) {true} - - doConvert(value) -} - -toKilo = function(value::num)::num { - rule context:: convert(X, kilo) case input(X) {true} - - doConvert(value) -} - -doConvert = function(value::num)::num{ - convert(value) -})CODE"; - - boost::scoped_ptr man(PassManager::prepareForCode(move(program))); - man->runWithoutCompilation(); - - int (*test)(int, int, int) = (int (*)(int, int, int))man->run(); - - enum {INPUT_MILLI, INPUT_CENTI}; - enum {OUTPUT_METERS, OUTPUT_KILO}; - - ASSERT_EQ(1000000, test(1, INPUT_MILLI, OUTPUT_KILO)); - ASSERT_EQ(200, test(2, INPUT_CENTI, OUTPUT_METERS)); -} - diff --git a/cpp/tests/dfa.cpp b/cpp/tests/dfa.cpp index f9a4fb8..a695b02 100644 --- a/cpp/tests/dfa.cpp +++ b/cpp/tests/dfa.cpp @@ -1,12 +1,32 @@ -/* +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ + * * DFGtests.cpp * * Created on: Jul 23, 2015 - * Author: pgess + * Author: pgess */ -#include "passmanager.h" +#include "xreatemanager.h" #include "pass/dfapass.h" #include "gtest/gtest.h" using namespace xreate; -using namespace std; \ No newline at end of file +using namespace std; + +//DEBT dfa tests: dfa scheme, dfa scheme + return value annoation (example: script/testpass/containers...) + +TEST(DFA, CallInstance1) { + std::string program= + R"CODE( + main = function::int{ + a(5, 8) + } + + a= function(x::int, y::int)::int;entry { x + y} +)CODE"; + + std::unique_ptr manager + (XreateManager::prepare(move(program))); + + manager->run(); +} \ No newline at end of file diff --git a/cpp/tests/effects-communication.cpp b/cpp/tests/effects-communication.cpp new file mode 100644 index 0000000..652b88b --- /dev/null +++ b/cpp/tests/effects-communication.cpp @@ -0,0 +1,73 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ + * + * communication.cpp + * + * Author: pgess + * Created on October 14, 2017, 5:24 PM + */ + +#include "xreatemanager.h" +#include "gtest/gtest.h" +using namespace xreate; + +TEST(Communication, ast_Basic1){ + FILE* script = fopen("scripts/effects-communication/example1-wr.xreate", "r"); + std::unique_ptr program(XreateManager::prepare(script)); + + ASSERT_TRUE(true); + fclose(script); +} + +TEST(Communication, analysis_Basic1){ + FILE* script = fopen("scripts/effects-communication/example1-wr.xreate", "r"); + std::unique_ptr program(details::tier1::XreateManager::prepare(script)); + fclose(script); + + program->analyse(); + ASSERT_TRUE(true); +} + +TEST(Communication, full_Basic1){ + FILE* script = fopen("scripts/effects-communication/example1-wr.xreate", "r"); + std::unique_ptr program(XreateManager::prepare(script)); + fclose(script); + + int (*programEntry)() = (int (*)())program->run(); + int result = programEntry(); + + ASSERT_EQ(1, result); +} + +TEST(Communication, full_Basic2){ + FILE* script = fopen("scripts/effects-communication/example2-wr.xreate", "r"); + std::unique_ptr program(XreateManager::prepare(script)); + fclose(script); + + int (*programEntry)() = (int (*)())program->run(); + int result = programEntry(); + + ASSERT_EQ(1, result); +} + +TEST(Communication, analysis_Weak1){ + FILE* script = fopen("scripts/effects-communication/example3-wrwr.xreate", "r"); + + std::unique_ptr program(details::tier1::XreateManager::prepare(script)); + fclose(script); + + program->analyse(); + ASSERT_TRUE(true); +} + +TEST(Communication, full_Weak1){ + FILE* script = fopen("scripts/effects-communication/example3-wrwr.xreate", "r"); + + std::unique_ptr program(XreateManager::prepare(script)); + fclose(script); + + int (*programEntry)(int) = (int (*)(int))program->run(); + + ASSERT_EQ(1, programEntry(1)); + ASSERT_EQ(-1, programEntry(0)); +} \ No newline at end of file diff --git a/cpp/tests/effects-versions.cpp b/cpp/tests/effects-versions.cpp new file mode 100644 index 0000000..2f18544 --- /dev/null +++ b/cpp/tests/effects-versions.cpp @@ -0,0 +1,279 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ + * + * Created on: Dec 16, 2016 + * Author: pgess + */ + +#include "pass/versionspass.h" +#include "xreatemanager.h" + +#include "gtest/gtest.h" + +using namespace xreate; +using namespace xreate::versions; + +TEST(Effects, syntax_versions_1){ + XreateManager* man = XreateManager::prepare(R"Code( + test= function(a:: num):: num; entry { + x= b[8]. + b = 5:: num. + x{1} = a:: num. + + x{1} + a + } + )Code"); +} + +TEST(Effects, analysis_versions_1){ + XreateManager* man = XreateManager::prepare( + R"Code( + test= function:: num; entry { + x{0}= 3:: int. + x{1} = x{0} + 1. + + x{1} + } + )Code"); + + VersionsPass* pass = new VersionsPass(man); + pass->run(); + + VersionsGraph graph = pass->getResultGraph(); + ASSERT_TRUE(graph.validate()); +} + +TEST(Effects, analysis_versions_2){ + XreateManager* man = XreateManager::prepare( + R"Code( + test= function(a:: num):: num; entry { + x{0}= 3:: int. + b = [1, 2, x{0}]. + x{1} = b[2]. + + x{1} + a + } + )Code"); + + VersionsPass* pass = new VersionsPass(man); + pass->run(); + + VersionsGraph graph = pass->getResultGraph(); + ASSERT_TRUE(graph.validate()); +} + +TEST(Effects, analysis_versions_2_1_fail){ + XreateManager* man = XreateManager::prepare( + R"Code( + test= function(a:: num):: num; entry { + x{0}= 5:: int. + b = x{0}. + x{1} = 2. + + b + x{1} + } + )Code"); + + VersionsPass* pass = new VersionsPass(man); + pass->run(); + + VersionsGraph graph = pass->getResultGraph(); + graph.__debug_print(std::cout); + ASSERT_FALSE(graph.validate()); +} + +TEST(Effects, analysis_versions_2_2){ + XreateManager* man = XreateManager::prepare( + R"Code( + test= function(a:: num):: num; entry { + x{0}= 5:: int. + b = intrinsic copy(x{0}). + x{1} = 2. + + b + x{1} + } + )Code"); + + VersionsPass* pass = new VersionsPass(man); + pass->run(); + + VersionsGraph graph = pass->getResultGraph(); + graph.__debug_print(std::cout); + ASSERT_TRUE(graph.validate()); +} + +TEST(Effects, analysis_versions_3){ + XreateManager* man = XreateManager::prepare( + R"Code( + test= function:: num; entry { + x{0}= 3:: int. + a = x{0}:: int. + b = a :: int. + x{1} = b. + + x{1} + } + )Code"); + + VersionsPass* pass = new VersionsPass(man); + pass->run(); + + VersionsGraph graph = pass->getResultGraph(); + graph.__debug_print(std::cout); + ASSERT_TRUE(graph.validate()); + std::cout << "========================\n"; + graph.__debug_print(std::cout); + AttachmentsContainerDefault>* attachmentsDependency = graph.representAsAttachments(); + + CodeScope* scope = man->root->findFunction("test")->getEntryScope(); + const std::list& dependenciesX1 = attachmentsDependency->get(Symbol{ScopedSymbol{1, 1}, scope}); + ASSERT_EQ(3, dependenciesX1.size()); +} + +TEST(Effects, compilation_versions_1){ + details::tier1::XreateManager* man = details::tier1::XreateManager::prepare( + R"Code( + test= function:: num; entry { + x{1} = b. + b = a :: int. + a = x{0}:: int. + x{0}= 3:: int. + + x{1} + } + )Code"); + + man->analyse(); + if (!man->isPassRegistered(PassId::VersionsPass)){ + VersionsPass* pass = new VersionsPass(man); + pass->run(); + pass->finish(); + } + + int (*body)() = (int (*)())man->run(); + int answer = body(); + + ASSERT_EQ(3, answer); +} + +TEST(Effects, compilation_versions_versionInit1){ + details::tier1::XreateManager* man = details::tier1::XreateManager::prepare( + R"Code( + test= function:: num; entry { + x{0} = 3. + + x{0} + } + )Code"); + + man->analyse(); + if (!man->isPassRegistered(PassId::VersionsPass)){ + VersionsPass* pass = new VersionsPass(man); + pass->run(); + pass->finish(); + } + + int (*body)() = (int (*)())man->run(); + int answer = body(); + + ASSERT_EQ(3, answer); +} + +TEST(Effects, compilation_versions_versionNext1){ + details::tier1::XreateManager* man = details::tier1::XreateManager::prepare( + R"Code( + test= function:: num; entry { + x{0} = 5. + x{1} = x{0} - 2. + + x{1} + } + )Code"); + + man->analyse(); + if (!man->isPassRegistered(PassId::VersionsPass)){ + VersionsPass* pass = new VersionsPass(man); + pass->run(); + pass->finish(); + } + + int (*body)() = (int (*)())man->run(); + int answer = body(); + + ASSERT_EQ(3, answer); +} + +TEST(Effects, compilation_versions_IntrinsicCopy1){ + details::tier1::XreateManager* man = details::tier1::XreateManager::prepare( + R"Code( + test= function:: num; entry { + x{0} = 5. + b = intrinsic copy (x{0}). + x{1} = 2. + + b - x{1} + } + )Code"); + + man->analyse(); + if (!man->isPassRegistered(PassId::VersionsPass)){ + VersionsPass* pass = new VersionsPass(man); + pass->run(); + pass->finish(); + } + + int (*body)() = (int (*)())man->run(); + int answer = body(); + + ASSERT_EQ(3, answer); +} + +TEST(Effects, compilation_versions_varexchange){ + details::tier1::XreateManager* man = details::tier1::XreateManager::prepare( + R"Code( + test= function:: num; entry { + a{0} = 3. + b{0} = 5. + tmp = intrinsic copy (a{0}). + a{1} = b{0}. + b{1} = tmp. + + b{1} + } + )Code"); + + man->analyse(); + if (!man->isPassRegistered(PassId::VersionsPass)){ + VersionsPass* pass = new VersionsPass(man); + pass->run(); + pass->finish(); + } + + int (*body)() = (int (*)())man->run(); + int answer = body(); + + ASSERT_EQ(3, answer); +} + + + + + +/* +TEST(Effects, analysis_versions_copy){ + +} + +TEST(Effects, syntax_references1){ + +} + +TEST(Effects, syntax_scope_versions1){ + +} + +TEST(Effects, DynamicVersions_analysis){ + +} + */ + diff --git a/cpp/tests/exploitation.cpp b/cpp/tests/exploitation.cpp new file mode 100644 index 0000000..9ac2d1d --- /dev/null +++ b/cpp/tests/exploitation.cpp @@ -0,0 +1,25 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ + * + * exploitation.cpp + * + * Author: pgess + * Created on February 15, 2018, 6:17 PM + */ + +#include "xreatemanager.h" +#include "gtest/gtest.h" + +using namespace xreate; + +TEST(Exploitation, test1){ + FILE* input = fopen("scripts/exploitation/test1.xreate","r"); + assert(input != nullptr); + + std::unique_ptr man(XreateManager::prepare(input)); + + int (*main)() = (int (*)())man->run(); + int result = main(); + + ASSERT_EQ(1, result); +} \ No newline at end of file diff --git a/cpp/tests/externc.cpp b/cpp/tests/externc.cpp index 2542a4e..3686be8 100644 --- a/cpp/tests/externc.cpp +++ b/cpp/tests/externc.cpp @@ -1,108 +1,115 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ + * + * externc.cpp + * + * Created on: - + * Author: pgess + */ + #include "gtest/gtest.h" -#include "passmanager.h" -#include "Scanner.h" -#include "Parser.h" +#include "xreatemanager.h" +#include "main/Scanner.h" +#include "main/Parser.h" #include #include using namespace std; +using namespace xreate; TEST(InterfaceExternC, testAST) { std::string code = " \ interface(extern-c){ \ xml2 = library:: pkgconfig(\"libxml-2.0\"). \ \ include { \ xml2 = [\"libxml/tree.h\"] \ }. \ } \ "; - Scanner scanner(reinterpret_cast (code.c_str()), code.size()); - Parser parser(&scanner); + xreate::grammar::main::Scanner scanner(reinterpret_cast (code.c_str()), code.size()); + xreate::grammar::main::Parser parser(&scanner); parser.Parse(); - ASSERT_EQ(1, parser.root.__externdata.size()); + ASSERT_EQ(1, parser.root->__externdata.size()); - for (const ExternEntry& lib : parser.root.__externdata) { + for (const ExternEntry& lib : parser.root->__externdata) { ASSERT_EQ("libxml-2.0", lib.package); ASSERT_EQ(1, lib.headers.size()); ASSERT_EQ("libxml/tree.h", lib.headers.at(0)); } } TEST(InterfaceExternC, testfetchPackageHeaders) { ExternEntry entry{"libxml-2.0", {}}; vector args = ExternLayer::fetchPackageFlags(entry); ASSERT_EQ(1, args.size()); ASSERT_EQ("-I/usr/include/libxml2", args.at(0)); } TEST(InterfaceExternC, testfetchPackageLibs) { ExternEntry entry{"libxml-2.0", {}}; vector args = ExternLayer::fetchPackageLibs(entry); ASSERT_EQ(1, args.size()); ASSERT_EQ("xml2", args.at(0)); } TEST(InterfaceExternC, testLoadLib) { std::string msgErr; if (!llvm::sys::DynamicLibrary::LoadLibraryPermanently("-lpcre -lxml2", &msgErr)) { cout << msgErr; ASSERT_EQ("", msgErr); } ASSERT_TRUE(true); } TEST(InterfaceExternC, testBSD1) { std::string code = " \n\ interface(extern-c){ \n\ libbsd = library:: pkgconfig(\"libbsd\"). \n\ \n\ include { \n\ libbsd = [\"bsd/stdlib.h\"] \n\ }. \n\ } \n" "main= function:: int; entry{arc4random_uniform(24) }"; - std::unique_ptr program(PassManager::prepareForCode(move(code))); + std::unique_ptr program(XreateManager::prepare(move(code))); void* entryPtr = program->run(); int (*entry)() = (int (*)())(intptr_t) entryPtr; int answer = 24; answer = entry(); cout << answer; ASSERT_LT(answer, 24); } TEST(InterfaceExternC, testStructFields1) { - FILE* input = fopen("scripts/testspass/Containers_Implementation_LinkedList1.xreate", "r"); + FILE* input = fopen("scripts/containers/Containers_Implementation_LinkedList1.xreate", "r"); assert(input != nullptr); - Scanner scanner(input); - Parser parser(&scanner); + xreate::grammar::main::Scanner scanner(input); + xreate::grammar::main::Parser parser(&scanner); parser.Parse(); - AST& ast = parser.root; - CodeScope* body = ast.findFunction("test")->getEntryScope(); - - Symbol symbTree = body->findSymbol("tree"); + AST* ast = parser.root->finalize(); + CodeScope* body = ast->findFunction("test")->getEntryScope(); - const TypeAnnotation& tTree = CodeScope::findDeclaration(symbTree).type; - const ExpandedType& t2Tree = ast.expandType(tTree); - LLVMLayer llvm(&ast); + const ExpandedType& t2Tree = ast->getType(body->getDefinition(body->getSymbol("tree"))); + LLVMLayer llvm(ast); TypeUtils utils(&llvm); std::vectorfields = utils.getStructFields(t2Tree); auto field = std::find(fields.begin(), fields.end(), "children"); ASSERT_TRUE(field != fields.end()); } diff --git a/cpp/tests/interpretation.cpp b/cpp/tests/interpretation.cpp index 615ad92..516fc7f 100644 --- a/cpp/tests/interpretation.cpp +++ b/cpp/tests/interpretation.cpp @@ -1,340 +1,532 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ + * + * interpretation.cpp + * + * Created on: - + * Author: pgess + */ + #include "attachments.h" using namespace xreate; -#include "passmanager.h" +#include "xreatemanager.h" #include "compilation/targetinterpretation.h" +#include "analysis/interpretation.h" #include "gtest/gtest.h" #include "boost/scoped_ptr.hpp" -#define private public -#include "Parser.h" +//#define FRIENDS_INTERPRETATION_TESTS \ +// friend class ::Modules_AST2_Test; \ +// friend class ::Modules_Discovery1_Test; \ +// friend class ::Modules_Solve1_Test; + #include "pass/interpretationpass.h" -using namespace xreate; -using namespace xreate::compilation; +using namespace xreate::grammar::main; +using namespace xreate::interpretation; TEST(Interpretation, Analysis_StatementIF_1){ - PassManager* man = PassManager::prepareForCode( + XreateManager* man = XreateManager::prepare( R"Code( - main = function::int { + main = function::bool { x = "a":: string. - y = if (x=="b"):: string; interpretation(force) { - 1 + y = if (x=="b"):: bool; interpretation(force) { + true } else { - 0 + false }. y } )Code" ); - InterpretationPass* pass; - if (man->isPassRegistered(PassId::InterpretationPass)){ - pass = (InterpretationPass*) man->getPassById(PassId::InterpretationPass); - } else { - pass = new InterpretationPass(man); - pass->run(); - } - Symbol symbolY = man->root->findFunction("main")->__entry->findSymbol("y"); - InterpretationData& dataSymbolY = Attachments::get(symbolY); + InterpretationPass* pass = new InterpretationPass(man); + pass->run(); + + CodeScope* scopeEntry = man->root->findFunction("main")->getEntryScope(); + Symbol symbolY{scopeEntry->getSymbol("y"), scopeEntry}; + InterpretationData& dataSymbolY = Attachments::get(symbolY); ASSERT_EQ(INTR_ONLY, dataSymbolY.resolution); } TEST(Interpretation, Compilation_StatementIF_1){ - PassManager* man = PassManager::prepareForCode( + xreate::details::tier1::XreateManager* man = xreate::details::tier1::XreateManager::prepare( R"Code( main = function::int; entry { x = "a":: string. y = if (x=="b"):: string; interpretation(force) { 1 } else { 0 }. y } )Code" ); - man->runWithoutCompilation(); + man->analyse(); InterpretationPass* pass; if (man->isPassRegistered(PassId::InterpretationPass)){ pass = (InterpretationPass*) man->getPassById(PassId::InterpretationPass); } else { pass = new InterpretationPass(man); pass->run(); } int (*main)() = (int (*)())man->run(); int result = main(); ASSERT_EQ(0, result); } TEST(Interpretation, Analysis_StatementIF_InterpretCondition_1){ - PassManager* man = PassManager::prepareForCode( + XreateManager* man = XreateManager::prepare( R"Code( main = function(x:: int):: int { - comm= "inc":: string. + comm= "inc":: string; interpretation(force). - y = if (comm == "inc") {x+1} else {x}. - y + y = if (comm == "inc")::int {x+1} else {x}. + y } -)Code" ); +)Code" ); - InterpretationPass* pass; - if (man->isPassRegistered(PassId::InterpretationPass)){ - pass = (InterpretationPass*) man->getPassById(PassId::InterpretationPass); - } else { - pass = new InterpretationPass(man); - pass->run(); - } + InterpretationPass* pass = new InterpretationPass(man); + pass->run(); - Symbol symbolY = man->root->findFunction("main")->__entry->findSymbol("y"); - InterpretationData& dataSymbolY = Attachments::get(symbolY); + CodeScope* scopeEntry = man->root->findFunction("main")->getEntryScope(); + Symbol symbolY{scopeEntry->getSymbol("y"), scopeEntry}; + InterpretationData& dataSymbolY = Attachments::get(symbolY); - ASSERT_EQ(ANY, dataSymbolY.resolution); + ASSERT_EQ(CMPL_ONLY, dataSymbolY.resolution); ASSERT_EQ(IF_INTERPRET_CONDITION, dataSymbolY.op); } TEST(Interpretation, Compilation_StatementIF_InterpretCondition_1){ - PassManager* man = PassManager::prepareForCode( + xreate::details::tier1::XreateManager* man = xreate::details::tier1::XreateManager::prepare( R"Code( main = function(x:: int):: int; entry { comm= "inc":: string; interpretation(force). - y = if (comm == "inc") {x+1} else {x}. + y = if (comm == "inc")::int {x+1} else {x}. y } )Code" ); - man->runWithoutCompilation(); + man->analyse(); InterpretationPass* pass; if (man->isPassRegistered(PassId::InterpretationPass)){ pass = (InterpretationPass*) man->getPassById(PassId::InterpretationPass); } else { pass = new InterpretationPass(man); pass->run(); } int (*main)(int) = (int (*)(int))man->run(); int result = main(1); ASSERT_EQ(2, result); } TEST(Interpretation, Compilation_StatementFOLD_INTERPRET_INPUT_1){ - PassManager* man = PassManager::prepareForCode( + xreate::details::tier1::XreateManager* man = xreate::details::tier1::XreateManager::prepare( R"Code( main = function(x:: int):: int; entry { commands = ["inc", "double", "dec"]:: [string]; interpretation(force). loop fold(commands->comm::string, x->operand):: int{ switch(comm)::int case ("inc"){ operand + 1 } case ("dec"){ operand - 1 } case ("double"){ operand * 2 } } } )Code" ); - man->runWithoutCompilation(); + man->analyse(); InterpretationPass* pass; if (man->isPassRegistered(PassId::InterpretationPass)){ pass = (InterpretationPass*) man->getPassById(PassId::InterpretationPass); } else { pass = new InterpretationPass(man); pass->run(); } + const ManagedFnPtr& funcMain = man->root->findFunction("main"); + InterpretationData& dataBody = Attachments::get(funcMain); + ASSERT_EQ(FOLD_INTERPRET_INPUT, dataBody.op); + int (*main)(int) = (int (*)(int))man->run(); int result = main(10); ASSERT_EQ(21, result); } TEST(Interpretation, StatementCall_RecursionNo_1){ - PassManager* man = PassManager::prepareForCode( + xreate::details::tier1::XreateManager* man = xreate::details::tier1::XreateManager::prepare( R"Code( - unwrap = function(data::undef, keys::undef):: undef; interpretation(force){ - loop fold(keys->key::string, data->a):: undef { + unwrap = function(data::unknType, keys::unknType):: unknType; interpretation(force){ + loop fold(keys->key::string, data->a):: unknType { a[key] } } start = function::num; entry{ result = unwrap( { a = { b = { c = "core" } } - }, ["a", "b", "c"])::undef. + }, ["a", "b", "c"])::unknType. result == "core" } )Code" ); - man->runWithoutCompilation(); + man->analyse(); InterpretationPass* pass; if (man->isPassRegistered(PassId::InterpretationPass)){ pass = (InterpretationPass*) man->getPassById(PassId::InterpretationPass); } else { pass = new InterpretationPass(man); pass->run(); } int (*main)() = (int (*)())man->run(); int result = main(); ASSERT_EQ(1, result); } TEST(Interpretation, StatementCall_RecursionDirect_1){ - PassManager* man = PassManager::prepareForCode( + xreate::details::tier1::XreateManager* man = xreate::details::tier1::XreateManager::prepare( R"Code( unwrap = function(data:: X):: Y { if (data[0] == "a")::Y {0} else {unwrap(data[0])} } entry = function:: i8; entry { unwrap([[[["a"]]]]):: i8; interpretation(force) } )Code" ); - man->runWithoutCompilation(); + man->analyse(); InterpretationPass* pass; if (man->isPassRegistered(PassId::InterpretationPass)){ pass = (InterpretationPass*) man->getPassById(PassId::InterpretationPass); } else { pass = new InterpretationPass(man); pass->run(); } InterpretationResolution resolutionActual = pass->process(man->root->findFunction("unwrap")); ASSERT_EQ(ANY, resolutionActual); int (*main)() = (int (*)())man->run(); int result = main(); ASSERT_EQ(0, result); } TEST(Interpretation, StatementCall_RecursionIndirect_1){ - PassManager* man = PassManager::prepareForCode( + XreateManager* man = XreateManager::prepare( R"Code( funcA = function(data:: X):: Y { if (data == "a")::Y {0} else {funcB(data)} } funcB = function(data:: X):: Y { if (data == "b")::Y {1} else {funcA(data)} } entry = function:: i8; entry { funcA(""):: i8; interpretation(force) } )Code" ); InterpretationPass* pass = new InterpretationPass(man); ASSERT_DEATH(pass->run(), "Indirect recursion detected"); } TEST(Interpretation, PartialIntr_1){ - PassManager* man = PassManager::prepareForCode( + XreateManager* man = XreateManager::prepare( R"Code( evaluate= function(argument:: num, code:: string; interpretation(force)):: num { switch(code)::int case ("inc") {argument + 1} case ("dec") {argument - 1} case ("double") {argument * 2} } main = function::int; entry { commands= ["inc", "double", "dec"]:: [string]; interpretation(force). loop fold(commands->comm::string, 10->operand):: int{ evaluate(operand, comm) } } )Code" ); InterpretationPass* pass = new InterpretationPass(man); pass->run(); ManagedFnPtr fnEvaluate = man->root->findFunction("evaluate"); InterpretationResolution resFnEvaluate= pass->process(fnEvaluate); ASSERT_EQ(CMPL_ONLY, resFnEvaluate); ASSERT_TRUE(FunctionInterpretationHelper::needPartialInterpretation(fnEvaluate)); const Expression& exprLoop = man->root->findFunction("main")->__entry->getBody(); - Symbol symbCallEv{0, exprLoop.blocks.front()}; - InterpretationData dataCallEv = Attachments::get(symbCallEv); + Symbol symbCallEv{{0, versions::VERSION_NONE}, exprLoop.blocks.front()}; + InterpretationData dataCallEv = Attachments::get(symbCallEv); ASSERT_EQ(CMPL_ONLY, dataCallEv.resolution); ASSERT_EQ(CALL_INTERPRET_PARTIAL, dataCallEv.op); } -TEST(Interpretation, PartialIntr_2){ - PassManager* man = PassManager::prepareForCode( +TEST(Interpretation, Compilation_PartialIntr_2){ + xreate::details::tier1::XreateManager* man = xreate::details::tier1::XreateManager::prepare( R"Code( evaluate= function(argument:: num, code:: string; interpretation(force)):: num { switch(code)::int - case ("inc") {argument + 1} - case ("dec") {argument - 1} - case ("double") {argument * 2} - case default {argument} + case ("inc") {argument + 1} + case ("dec") {argument - 1} + case ("double") {argument * 2} + case default {argument} } main = function::int; entry { commands= ["inc", "double", "dec"]:: [string]; interpretation(force). loop fold(commands->comm::string, 10->operand):: int{ evaluate(operand, comm) } } )Code" ); - InterpretationPass* pass = new InterpretationPass(man); - pass->run(); + man->analyse(); + if (!man->isPassRegistered(PassId::InterpretationPass)){ + InterpretationPass* pass = new InterpretationPass(man); + pass->run(); + } int (*main)() = (int (*)())man->run(); int result = main(); ASSERT_EQ(21, result); } -//TOTEST call indirect recursion(w/o tags) -//TASK implement and test Loop Inf (fix acc types in coco grammar) +TEST(Interpretation, PartialIntr_3){ + xreate::details::tier1::XreateManager* man = xreate::details::tier1::XreateManager::prepare( +R"Code( + Command= type variant {INC, DEC, DOUBLE}. + + evaluate= function(argument:: num, code:: Command; interpretation(force)):: num { + switch variant(code)::int + case (INC) {argument + 1} + case (DEC) {argument - 1} + case (DOUBLE) {argument * 2} + } + + main = function::int; entry { + commands= [INC(), DOUBLE(), DEC()]:: [Command]; interpretation(force). + + loop fold(commands->comm::Command, 10->operand):: int{ + evaluate(operand, comm) + } + } +)Code" ); + + man->analyse(); + if (!man->isPassRegistered(PassId::InterpretationPass)){ + InterpretationPass* pass = new InterpretationPass(man); + pass->run(); + } + + int (*main)() = (int (*)())man->run(); + int result = main(); + + ASSERT_EQ(21, result); +} + +TEST(Interpretation, PartialIntr_4){ + xreate::details::tier1::XreateManager* man = xreate::details::tier1::XreateManager::prepare( +R"Code( + Command= type variant {INC, DEC, DOUBLE}. + + evaluate= function(argument:: num, code:: Command; interpretation(force)):: num { + switch variant(code)::num + case (INC) {argument + 1} + case (DEC) {argument - 1} + case (DOUBLE) {argument * 2} + } + + main = function::int; entry { + evaluate(4, DEC()) + } +)Code" ); + + man->analyse(); + if (!man->isPassRegistered(PassId::InterpretationPass)){ + InterpretationPass* pass = new InterpretationPass(man); + pass->run(); + } + + int (*main)() = (int (*)())man->run(); + int result = main(); + + ASSERT_EQ(3, result); +} + +TEST(Interpretation, SwitchVariant){ + xreate::XreateManager* man = xreate::XreateManager::prepare( +R"Code( +OneArgument = type{x::int}. +TWoArgument = type {x::int, y::int}. + +Command= type variant { + ADD::TwoArguments, + DEC:: OneArgument, + DOUBLE::OneArgument +}. + +main = function::int; entry{ + program = ADD({x=2, y=3})::Command; interpretation(force). + + switch variant(program)::int + case (ADD) {program["x"]+program["y"]} + case (DEC) {1} + case (DOUBLE) {2} +} +)Code" ); + + int (*main)() = (int (*)())man->run(); + int result = main(); + ASSERT_EQ(5, result); + +} + +TEST(Interpretation, SwitchVariantAlias){ + xreate::XreateManager* man = xreate::XreateManager::prepare( +R"Code( +OneArgument = type{x::int}. +TWoArgument = type {x::int, y::int}. + +Command= type variant { + ADD::TwoArguments, + DEC:: OneArgument, + DOUBLE::OneArgument +}. + +main = function::int; entry{ + program = [ADD({x=2, y=3}), DEC({x=8})]::[Command]; interpretation(force). + + switch variant(program[0]->program::Command)::int + case (ADD) {program["x"]+program["y"]} + case (DEC) {1} + case (DOUBLE) {2} +} +)Code" ); + + int (*main)() = (int (*)())man->run(); + int result = main(); + ASSERT_EQ(5, result); +} +TEST(Interpretation, Multiindex1){ + std::string script2= +R"Code( + extract = function(program::unknType)::int; interpretation(force){ + program["arguments"][1] + } + + main = function::int; entry { + x = {arguments = [10, 9, 8, 7]}:: unknType; interpretation(force). + extract(x) + } +)Code"; + + std::unique_ptr man(XreateManager::prepare(std::move(script2))); + + int (*main)() = (int (*)())man->run(); + int result = main(); + + ASSERT_EQ(9, result); +} + +TEST(InterpretationExamples, Regexp1){ + FILE* input = fopen("scripts/dsl/regexp.xreate","r"); + assert(input != nullptr); + + std::unique_ptr man(XreateManager::prepare(input)); + + int (*main)() = (int (*)())man->run(); + int result = main(); + ASSERT_EQ(4, result); +} + +TEST(Interpretation, Variant1){ + std::string script= +R"Code( +Data = type {Num:: [int], String::string}. + +DataPacked = type variant { + Var1:: Data, + Var2:: Data +}. +extractInt = function(data::DataPacked):: int { + resultWrong = 0 :: int. + switch variant(data)::int + case (Var1) {data["Num", 0]} + case (Var2) {resultWrong} +} + +main = function :: int; entry { + dataActual = 10. + dataPacked = Var1({Num = [dataActual], String = "whatever"}):: DataPacked. + + extractInt(dataPacked):: int; interpretation(force) +} +)Code"; + std::unique_ptr man(XreateManager::prepare(std::move(script))); + + int (*main)() = (int (*)())man->run(); + int result = main(); + + ASSERT_EQ(10, result); +} + +//TOTEST call indirect recursion(w/o tags) +//TASk implement and test Loop Inf (fix acc types in coco grammar) diff --git a/cpp/tests/latereasoning.cpp b/cpp/tests/latereasoning.cpp new file mode 100644 index 0000000..fbe8b45 --- /dev/null +++ b/cpp/tests/latereasoning.cpp @@ -0,0 +1,184 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ + * + * latereasoning.cpp + * + * Author: pgess + * Created on April 21, 2018, 5:10 PM + */ + +#include "xreatemanager.h" +#include "transcendlayer.h" +#include "pass/latereasoningpass.h" +#include "aux/latereasoning.h" +#include "pass/dfapass.h" +#include +#include "gtest/gtest.h" + +using namespace std; +using namespace xreate; +using namespace xreate::latereasoning; + +TEST(LateReasoning, Syntax1) { + XreateManager* man = XreateManager::prepare(R"Code( +test = function:: int { + x = 0::int. + y1= switch late (x)::int{0}. + y2= switch late(x+y1->a::int)::int{1}. + y1+y2 +} +)Code"); + + CodeScope* scope = man->root->findFunction("test")->getEntryScope(); + Expression y1 = scope->getDefinition(scope->getSymbol("y1")); + Expression y2 = scope->getDefinition(scope->getSymbol("y2")); + + ASSERT_EQ(1, y1.bindings.size()); + ASSERT_STRCASEEQ("x", y1.bindings.at(0).c_str()); + + ASSERT_EQ(1, y2.bindings.size()); + ASSERT_STRCASEEQ("a", y2.bindings.at(0).c_str()); +} + +TEST(LateReasoning, Pass_DFAPassDec_1){ + typedef LateReasoningTranscendDecorator LRTranscend; + + auto man = details::tier2::XreateManager::prepare(R"Code( +Dom = type slave dom. + +test = function:: int; entry +{ + LateIdent = 0:: Dom. + 0:: int; ann1(LateIdent) +} +)Code"); + + CodeScope* scopeEntry = man->root->findFunction("test")->getEntryScope(); + ScopedSymbol keyS = scopeEntry->getSymbol("LateIdent"); + SymbolPacked keySP = man->transcend->pack(Symbol{keyS, scopeEntry}); + + std::shared_ptr scopeLateEntry(new LateReasoningScope(nullptr)); + scopeLateEntry->addIdentifier("LateIdent", keySP); + + typedef LateReasoningDFAPassDecorator LRDFAPass; + LRDFAPass* dfaPass = new LRDFAPass(man); + dfaPass->registerLateScope(scopeEntry, scopeLateEntry.get()); + + man->transcend->addRawScript("dom(guard1; guard2).\n"); + + man->registerPass(dfaPass, PassId::DFAPass, nullptr); + man->executePasses(); + + testing::internal::CaptureStdout(); + man->analyse(); + std::string outputActual = testing::internal::GetCapturedStdout(); + cout << outputActual << endl; + + string outputExpected = "late(s(0,-2,0), (s(1,-2,0)), (LateIdent), ann1(LateIdent)):- dom(LateIdent)."; + ASSERT_NE(std::string::npos, outputActual.find(outputExpected)); +} + +TEST(LateReasoning, Transcend_LRTransDec_1) { + Attachments::init(); + typedef LateReasoningTranscendDecorator LRTranscend; + std::unique_ptr transcend(new LRTranscend()); + + std::unique_ptr scope(new CodeScope(nullptr)); + Symbol symbA = scope->addDefinition(Atom("a"), Expression()); + Symbol symbB = scope->addDefinition(Atom("b"), Expression()); + Symbol symbC = scope->addDefinition(Atom("c"), Expression()); + Symbol symbTarget1 = scope->addDefinition(Atom("target1"), Expression()); + Symbol symbTarget2 = scope->addDefinition(Atom("target2"), Expression()); + + SymbolPacked symbpA = transcend->pack(symbA, "a"); + SymbolPacked symbpB = transcend->pack(symbB, "b"); + SymbolPacked symbpC = transcend->pack(symbC, "c"); + SymbolPacked symbTarget1P = transcend->pack(symbTarget1, "target1"); + SymbolPacked symbTarget2P = transcend->pack(symbTarget2, "target2"); + + boost::format formatSymb("s(%1%,%2%,%3%)"); + boost::format formatLateAnnotation1("late(%1%, (%2%, %3%, %4%), (%5%, %6%, %7%), %8%)."); + boost::format formatLateAnnotation2("late(%1%, (%2%, %3%), (%4%, %5%), %6%)."); + #define FORMATSYMBOL(s) (formatSymb % s.identifier % s.version % s.scope).str() + + // Ann1, `variant1` + transcend->addRawScript((formatLateAnnotation1 + % FORMATSYMBOL(symbTarget1P) + % FORMATSYMBOL(symbpA) % FORMATSYMBOL(symbpB) % FORMATSYMBOL(symbpC) + % "guard1" % "guard1" % "guard1" + % "result(variant1)" + ). str()); + + //Ann1 `result2` variant + transcend->addRawScript((formatLateAnnotation1 + % FORMATSYMBOL(symbTarget1P) + % FORMATSYMBOL(symbpA) % FORMATSYMBOL(symbpB) % FORMATSYMBOL(symbpC) + % "guard2" % "guard2" % "guard2" + % "result(variant2)" + ). str()); + + //Ann2 `result3` variant + transcend->addRawScript((formatLateAnnotation2 + % FORMATSYMBOL(symbTarget2P) + % FORMATSYMBOL(symbpA) % FORMATSYMBOL(symbpB) + % "guard3" % "guard3" + % "result(variant3)" + ). str()); + + transcend->run(); + LateAnnotationsGroup group = transcend->queryLate("result"); + ASSERT_EQ(2, group.annotations.size()); + + for(const auto& annEntry: group.annotations){ + annEntry.first.print(cout); + cout <(transcend->parse(targetWrapped)); + if (targetSP == symbTarget1P){ + LateAnnotation ann = annEntry.second; + ASSERT_EQ(2, ann.guardedContent.size()); + + Expression selector(Operator::CALL, {Atom("guard2")}); + auto answer = ann.select({selector, selector, selector}man->root, man->transcend); + ASSERT_TRUE(answer); + string answerS = get<0>(transcend->parse(*answer)); + ASSERT_STREQ("variant2", answerS.c_str()); + + } else if (targetSP == symbTarget2P) { + LateAnnotation ann = annEntry.second; + ASSERT_EQ(1, ann.guardedContent.size()); + + Expression selector(Operator::CALL, {Atom("guard3")}); + auto answer = ann.select({selector, selector, selector}); + ASSERT_TRUE(answer); + ASSERT_STREQ("variant3", get<0>(transcend->parse(*answer)).c_str()); + + } else { + ASSERT_TRUE(false); + } + } +} + +TEST(LateReasoning, Compilation1){ + XreateManager* man = XreateManager::prepare(R"Code( +Color = type variant{RED, BLUE, GREEN}. + +test = function:: int; entry { + x = RED():: Color. + y1= switch late (x):: int + {0}. + y1 +} +)Code"); + + int (*program)() = (int (*)())man->run(); + int result = program(); + + ASSERT_EQ(0, result); +} + + diff --git a/cpp/tests/latex.cpp b/cpp/tests/latex.cpp new file mode 100644 index 0000000..54ceff8 --- /dev/null +++ b/cpp/tests/latex.cpp @@ -0,0 +1,298 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ + * + * Author: pgess + * Created on June 25, 2018, 5:42 PM + * + * \file latex.cpp + * \brief Testing of latex + */ + +#include "xreatemanager.h" +#include "pass/compilepass.h" +#include "transcendlayer.h" +#include "query/latex.h" +#include "compilation/latex.h" +#include "aux/xreatemanager-decorators.h" +#include "compilation/scopedecorators.h" +#include "llvmlayer.h" + +#include +#include + +using namespace xreate::latex; +using namespace xreate::latereasoning; +using namespace xreate::compilation; +using namespace xreate; +using namespace std; + +TEST(Latex, Script_NestedScopePropagation_1) { + std::string program = + R"CODE( + import raw("scripts/cfa/context.lp"). + fn = function:: int; entry + { + context:: test1. + if(1==11)::int {2} else {3} + } + )CODE"; + + std::unique_ptr man(details::tier1::XreateManager::prepare(move(program))); + + CodeScope* blockTrue = man->root->findFunction("fn")->getEntryScope()->getBody().blocks.front(); + auto blockTrueP = man->transcend->pack(blockTrue); + boost::format formatAlias("alias(%1%, %2%)."); + man->transcend->addRawScript((formatAlias % blockTrueP % "block1").str()); + man->transcend->addRawScript( + R"SCRIPT( + success1:- bind_scope(Block1, test1, strong); alias(Block1, block1). + )SCRIPT"); + man->analyse(); + + ASSERT_EQ(1, man->transcend->query("success1").size()); +} + +TEST(Latex, Script_DemAndDecision_1) { + std::string program = + R"CODE( + import raw("scripts/cfa/context.lp"). + + a = function:: int + { + context:: forC(a). + c() + } + + b = function:: int + { + context:: forC(b). + c() + } + + c = function:: int {0} + + main = function:: int; entry + { + a() + b() + } + )CODE"; + + std::unique_ptr man(details::tier1::XreateManager::prepare(move(program))); + + CodeScope* blockC = man->root->findFunction("c")->getEntryScope(); + auto blockCP = man->transcend->pack(blockC); + boost::format formatAlias("alias(%1%, %2%)."); + man->transcend->addRawScript((formatAlias % blockCP % "blockC").str()); + man->transcend->addRawScript( + R"SCRIPT( + latex_scope_demand(BlockC, forC):- alias(BlockC, blockC). + latex_registered_subjects(forC, Variant):- bind_scope(_, Variant, strong); Variant = forC(_). + )SCRIPT"); + man->analyse(); + + ASSERT_EQ(1, man->transcend->query("latex_fn_demand").size()); + ASSERT_EQ(2, man->transcend->query("latex_decision").size()); +} + +TEST(Latex, LatexQuery_getFnDemand_1){ + std::string program = + R"CODE( + import raw("scripts/cfa/context.lp"). + main = function:: int; entry + { + context:: alias(blockMain). + 0 + } + )CODE"; + + std::unique_ptr man(details::tier1::XreateManager::prepare(move(program))); + man->transcend->addRawScript( + R"SCRIPT( + latex_scope_demand(BlockC, forC):- bind_scope(BlockC, alias(blockMain), strong). + latex_registered_subjects(forC, decisionSome). + )SCRIPT"); + + LatexQuery* query = new LatexQuery(); + man->transcend->registerQuery(query, QueryId::LatexQuery); + man->analyse(); + + Demand demand = query->getFnDemand("main"); + ASSERT_EQ(1, demand.size()); + ASSERT_STREQ("forC", demand.front().c_str()); +} + +TEST(Latex, LatexQuery_getDecision_static_1){ + std::string program = + R"CODE( + import raw("scripts/cfa/context.lp"). + a = function:: int {context::decisionSome. c()} + b = function:: int {c()} + c = function:: int {context:: alias(blockC). 0} + )CODE"; + + std::unique_ptr man(details::tier1::XreateManager::prepare(move(program))); + man->transcend->addRawScript( + R"SCRIPT( + latex_scope_demand(BlockC, forC):- bind_scope(BlockC, alias(blockC), strong). + latex_registered_subjects(forC, decisionSome). + )SCRIPT"); + + LatexQuery* query = new LatexQuery(); + man->transcend->registerQuery(query, QueryId::LatexQuery); + man->analyse(); + + LateAnnotation decisionLA = query->getDecision("forC", man->root->findFunction("a")->getEntryScope()); + auto decisionGS = decisionLA.select({}, man->root, man->transcend); + ASSERT_TRUE(decisionGS); + + decisionGS->print(cout); + cout << endl; + auto decisionTuple = man->transcend->parse(*decisionGS); + string decision = get<2>(decisionTuple); + ASSERT_STREQ("decisionSome", decision.c_str()); +} + +TEST(Latex, Compilation_1) { + std::string program = + R"CODE( + + a = function:: int + {0} + + main = function:: int; entry + { + a() + } + )CODE"; + + string script = + R"SCRIPT( + latex_fn_demand(%1%, subject1). + latex_decision(%2%, subject1, 5). + latex_registered_subjects(subject1, 1). + latex_registered_subjects(subject1, 5). + )SCRIPT"; + + typedef LatexBruteFunctionDecorator FnImpl; + typedef LatexBruteScopeDecorator> ScopeImpl; + + std::unique_ptr man(details::tier1::XreateManager::prepare(move(program))); + ScopePacked scopeMainP = man->transcend->pack(man->root->findFunction("main")->getEntryScope()); + boost::format format(script); + man->transcend->addRawScript((format % "a" % scopeMainP).str()); + man->transcend->registerQuery(new LatexQuery(), QueryId::LatexQuery); + man->analyse(); + + std::unique_ptr compiler(new compilation::CompilePassCustomDecorators(man.get())); + compiler->run(); + man->llvm->initJit(); + int(*fnMain)() = (int(*)())man->llvm->getFunctionPointer(compiler->getEntryFunction()); + ASSERT_EQ(0, fnMain()); +} + +// +//TEST(Latex, Full1) { +// std::string program = +// R"CODE( +// import raw("scripts/cfa/context.lp"). +// +// a = function:: int +// { +// context:: forC(a). +// c() +// } +// +// b = function:: int +// { +// context:: forC(b). +// c() +// } +// +// c = function:: int {0} +// +// main = function:: int; entry +// { +// a() + b() +// } +// )CODE"; +// +// string script = +// R"SCRIPT( +// alias(%1%, scopeC). +// latex_scope_demand(ScopeC, forC) :- alias(ScopeC, scopeC). +// latex_registered_subjects(forC, forC(a)). +// latex_registered_subjects(forC, forC(b)). +// )SCRIPT"; +// +// typedef LatexBruteFunctionDecorator FnImpl; +// typedef LatexBruteScopeDecorator> ScopeImpl; +// +// std::unique_ptr man(details::tier1::XreateManager::prepare(move(program))); +// ScopePacked scopeMainP = man->transcend->pack(man->root->findFunction("main")->getEntryScope()); +// auto scopeCP = man->transcend->pack(man->root->findFunction("c")->getEntryScope()); +// boost::format format(script); +// man->transcend->addRawScript((format %scopeCP).str()); +// man->transcend->registerQuery(new LatexQuery(), QueryId::LatexQuery); +// man->analyse(); +// +// std::unique_ptr compiler(new compilation::CompilePassCustomDecorators(man.get())); +// compiler->run(); +// man->llvm->print(); +//} +// +TEST(Latex, Compilation_TransitFn1){ + std::string program = + R"CODE( + import raw("scripts/cfa/context.lp"). + + branchA = function:: int + { + context:: sink_a. + fnTransit() + } + + branchB = function:: int + { + context:: sink_b. + fnTransit() + } + + fnSink = function:: int {0} + fnTransit = function:: int {fnSink()} + + main = function:: int; entry + { + branchA() + branchB() + } + )CODE"; + + string script = +R"SCRIPT( + alias(scopeSink, %1%). + latex_scope_demand(ScopeSink, sink):- alias(scopeSink, ScopeSink). + latex_registered_subjects(sink, sink_a). + latex_registered_subjects(sink, sink_b). +)SCRIPT"; + + typedef LatexBruteFunctionDecorator FnImpl; + typedef LatexBruteScopeDecorator> ScopeImpl; + + std::unique_ptr man(details::tier1::XreateManager::prepare(move(program))); + CodeScope* scopeSink = man->root->findFunction("fnSink")->getEntryScope(); + auto scopeSinkP = man->transcend->pack(scopeSink); + ScopedSymbol argLatexSS{1, -1}; + Symbol argLatexS{argLatexSS, scopeSink}; + man->transcend->pack(argLatexS); + boost::format format(script); + man->transcend->addRawScript((format %scopeSinkP).str()); + man->transcend->registerQuery(new LatexQuery(), QueryId::LatexQuery); + man->analyse(); + + std::unique_ptr compiler(new compilation::CompilePassCustomDecorators(man.get())); + compiler->run(); + man->llvm->print(); + man->llvm->initJit(); + int(*fnMain)() = (int(*)()) man->llvm->getFunctionPointer(compiler->getEntryFunction()); + int valueActual = fnMain(); + ASSERT_EQ(0, valueActual); +} \ No newline at end of file diff --git a/cpp/tests/loops.cpp b/cpp/tests/loops.cpp index efa66a5..1de81f0 100644 --- a/cpp/tests/loops.cpp +++ b/cpp/tests/loops.cpp @@ -1,59 +1,187 @@ -#include "passmanager.h" +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ + * + * loops.cpp + * + * Created on: - + * Author: pgess + */ + +#include "xreatemanager.h" #include "gtest/gtest.h" using namespace std; +TEST(Loop, SimpleLoop1){ + string code = +R"CODE( + main = function:: int; entry { + input = [1..5]:: [int]. + + loop fold(input->el::int, 0->sum)::int + { + sum + el + } + } + +)CODE"; + + xreate::XreateManager* man = xreate::XreateManager::prepare(move(code)); + int (*funcMain)() = (int (*)()) man->run(); + + int answerActual = funcMain(); + ASSERT_EQ(15, answerActual); +} + TEST(Loop, Break1){ string code = R"CODE( main = function:: int; entry { - input = [0..10]:: [int]. + input = [1..10]:: [int]. - loop fold(input->el::int, 0->a)::[int] + loop fold(input->el::int, 0->sum)::int { - if (a>=5)::int { - 5:: int; break + if (sum>5)::int { + sum:: int; break - } else {a+el} + } else {sum+el} } } )CODE"; - xreate::PassManager* man = xreate::PassManager::prepareForCode(move(code)); + xreate::XreateManager* man = xreate::XreateManager::prepare(move(code)); int (*funcMain)() = (int (*)()) man->run(); int answerActual = funcMain(); - ASSERT_EQ(5, answerActual); + ASSERT_EQ(6, answerActual); +} + +TEST(Loop, NestedLoopsSimple1){ + string code = +R"CODE( + main = function:: int; entry { + listX = [1..5]:: [int]. + loop fold(listX->x::int, 0->acc)::int + { + listY = [1..5]:: [int]. + + row = loop fold(listY->y::int, 1->acc):: int { + acc * ( y + x) + }. + + acc + row + } + } + +)CODE"; + + xreate::XreateManager* man = xreate::XreateManager::prepare(move(code)); + int (*funcMain)() = (int (*)()) man->run(); + int answerActual = funcMain(); + + ASSERT_EQ(55320, answerActual); +} + +TEST(Loop, NestedLoopsBreak1){ + string code = +R"CODE( + main = function:: int; entry { + listX = [1..5]:: [int]. + loop fold(listX->x::int, 0->acc)::int + { + listY = [1..5]:: [int]. + row = loop fold(listY->y::int, 1->acc):: int { + res = acc * ( y + x) :: int. + + if (res > 20):: int { + 20:: int; break + + } else { + res + } + }. + + acc + row + } + } + +)CODE"; + + xreate::XreateManager* man = xreate::XreateManager::prepare(move(code)); + int (*funcMain)() = (int (*)()) man->run(); + int answerActual = funcMain(); + + ASSERT_EQ(100, answerActual); } +TEST(Loop, NestedLoopsBreak2){ + string code = +R"CODE( + main = function:: int; entry { + listX = [1..3]:: [int]. + loop fold(listX->x::int, 0->acc)::int + { + listY = [1..5]:: [int]. + row = loop fold(listY->y::int, 1->acc):: int { + res = acc * y :: int. + + if (res > 24):: int { + 24:: int; break + + } else { + res + } + }. + + if (x==3)::int{ + acc:: int; break + + } else { + acc + row + } + } + } + +)CODE"; + + xreate::XreateManager* man = xreate::XreateManager::prepare(move(code)); + int (*funcMain)() = (int (*)()) man->run(); + int answerActual = funcMain(); + + ASSERT_EQ(48, answerActual); +} + +//TEST nested loop breaks. +//TEST 2 breaks^ outer loop break, inner loop break + TEST(Loop, InfiniteLoop1){ string code = R"Code( fac = function(x:: int):: int{ range = [2..x] :: [int]. loop fold(range->i::int, 1->acc)::int { acc * i } } main = function:: int; entry { loop fold inf(2->state) :: int { if (fac(state)==120)::int { state::int; break } else {state + 1} } } )Code" ; - xreate::PassManager* man = xreate::PassManager::prepareForCode(move(code)); + xreate::XreateManager* man = xreate::XreateManager::prepare(move(code)); int (*funcMain)() = (int (*)()) man->run(); int answerActual = funcMain(); ASSERT_EQ(5, answerActual); -} \ No newline at end of file +} diff --git a/cpp/tests/main.cpp b/cpp/tests/main.cpp index 66078a2..2df18c6 100644 --- a/cpp/tests/main.cpp +++ b/cpp/tests/main.cpp @@ -1,136 +1,24 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ + * + * main.cpp + * + * Created on: 00:00 Xreate Epoch + * Author: pgess + */ + #include "utils.h" #include using namespace std; using namespace xreate; int main(int argc, char **argv) { testing::GTEST_FLAG(color) = "yes"; - string testsTemplate = Config::get("tests.template"); string testsFilter = Config::get(string("tests.templates.") + testsTemplate); testing::GTEST_FLAG(filter) = testsFilter; testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); } - -//TODO adopt useful tests - -//void testParser_1() -//{ -// shared_ptr scanner(new Scanner(L"scripts/input.xreate")); -// shared_ptr parser(new Parser(scanner.get())); -// parser->Parse(); -// flush(cout); - -// AST& root = parser->root; -// LLVMLayer l(&root); - -// root.compile(l); -// root.run(l); -//} - -//void testClasp2() -//{ -// shared_ptr scanner(new Scanner(L"scripts/input.xreate")); -// shared_ptr parser(new Parser(scanner.get())); -// parser->Parse(); -// flush(cout); - -// if (parser->errors->count) -// { -// cout << "Found " << parser->errors->count << " errors. Stop" << endl; -// exit(1); -// } - -// AST& root = parser->root; -// ClaspLayer clasp; - -// /* -// FunctionTagsPass(root).run(clasp); -// RulesPass(root).run(clasp); - -// CFGPass(&clasp).run(); - -// clasp.1 -// run(); -// */ -//} - -//void testUnsafeCode1() -//{ -// shared_ptr scanner(new Scanner(L"scripts/cases/bugs-code.xreate")); -// shared_ptr parser(new Parser(scanner.get())); -// parser->Parse(); -// flush(cout); - -// if (parser->errors->count) -// { -// cout << "Found " << parser->errors->count << " errors. Stop" << endl; -// exit(1); -// } - -// AST& root = parser->root; -// ClaspLayer clasp; - -// /* -// FunctionTagsPass(root).run(clasp); -// RulesPass(root).run(clasp); - -// CFGPass(&clasp).run(); -// //clasp.addRule(":- call(X, Y), tag(Y, unsafe), not tag(X, unsafe), function(X), function(Y)."); - -// clasp.run(); -// */ -//} - -//void test_DFG_1() -//{ -// shared_ptr scanner(new Scanner(L"scripts/input.xreate")); -// shared_ptr parser(new Parser(scanner.get())); -// parser->Parse(); -// flush(cout); - -// if (parser->errors->count) -// { -// cout << "Found " << parser->errors->count << " errors. Stop" << endl; -// exit(1); -// } - -// PassManager m; -// m.clasp = new ClaspLayer(); - -// m.llvm = new LLVMLayer(&parser->root); -// m.root = & parser->root; -// m.clasp->ast = m.root; - -// m.registerPass(new DFAPass(&m)); -// m.run(); - -// m.clasp->run(); -// m.root->compile(*m.llvm); -// m.root->run(*m.llvm); -//} - -//void test_Xml_1() -//{ -// shared_ptr scanner(new Scanner(L"scripts/input.xreate")); -// shared_ptr parser(new Parser(scanner.get())); -// parser->Parse(); -// flush(cout); - -// if (parser->errors->count) -// { -// cout << "Found " << parser->errors->count << " errors. Stop" << endl; -// exit(1); -// } - -// PassManager m; -// m.root = & parser->root; -// m.clasp = new ClaspLayer(); -// m.clasp->ast = m.root; -// m.llvm = new LLVMLayer(&parser->root); - -// m.registerPass(new DFAPass(&m)); -// m.run(); -//} diff --git a/cpp/tests/modules.cpp b/cpp/tests/modules.cpp new file mode 100644 index 0000000..a857c5d --- /dev/null +++ b/cpp/tests/modules.cpp @@ -0,0 +1,323 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ + * + * modules.cpp + * + * Author: pgess + * Created on June 18, 2017, 8:25 PM + */ + +class Modules_AST2_Test; +class Modules_Discovery1_Test; +class Modules_Solve1_Test; + +#define FRIENDS_MODULES_TESTS \ + friend class ::Modules_AST2_Test; \ + friend class ::Modules_Discovery1_Test; \ + friend class ::Modules_Solve1_Test; + +#include "modules.h" +#include "aux/xreatemanager-decorators.h" +#include "aux/xreatemanager-modules.h" +#include "xreatemanager.h" +#include "modules/Parser.h" +#include "gtest/gtest.h" +#include +#include +#include + +namespace fs = boost::filesystem; + +using namespace std; +using namespace xreate; +using namespace xreate::modules; + +TEST(Modules, AST1) { + FILE* input = fopen("scripts/dsl/regexp.xreate","r"); + assert(input != nullptr); + + Scanner scanner(input); + Parser parser(&scanner); + parser.Parse(); + ASSERT_EQ(parser.errors->count, 0); +} + +TEST(Modules, AST2){ + string code = R"Code( + module { + name(test1). + status(untested). + + require provides(logging). + include controller("/tmp/test-controller.ls"). + discover("/tmp/root/"). + } + )Code"; + + Scanner scanner(reinterpret_cast(code.c_str()), code.size()); + Parser parser(&scanner); + parser.Parse(); + + ModuleRecord module = parser.module; + + ASSERT_EQ(2, module.__properties.size()); + ASSERT_EQ("name", module.__properties.front().getValueString()); + ASSERT_EQ("status", module.__properties.back().getValueString()); + + ASSERT_EQ(1, module.__queries.size()); + ASSERT_EQ("provides", module.__queries.front().getValueString()); + + ASSERT_EQ(1, module.__controllers.size()); + ASSERT_EQ("/tmp/test-controller.ls", module.__controllers.front()); + + ASSERT_EQ(1, module.__discoveries.size()); + ASSERT_EQ("/tmp/root/", module.__discoveries.front()); +} + +TEST(Modules, Discovery1){ + const std::string dirModulesRoot = "/tmp/testModulesDiscovery1_t54723/"; + + string codeA = +R"Code(module { + name(testA). + status(needToTestMore). +})Code"; + + string codeB = +R"Code(module { + name(testB). + status(needToTestEvenMore). +})Code"; + + string codeMain = string("module{discover \"") + dirModulesRoot + "\".}"; + + fs::create_directories(dirModulesRoot); + fs::ofstream fileA(dirModulesRoot + "a.xreate"); + fileA << codeA; + fileA.close(); + + fs::ofstream fileB(dirModulesRoot + "b.xreate"); + fileB << codeB; + fileB.close(); + + Scanner scanner(reinterpret_cast(codeMain.c_str()), codeMain.size()); + Parser parser(&scanner); + parser.Parse(); + + ModulesRegistry registry; + ModulesSolver solver(®istry); + solver.discoverModules(parser.module); + fs::remove_all(dirModulesRoot); + + std::string output = solver.__program.str(); + cout << output << endl; + ASSERT_NE(string::npos, output.find("bind_module(0, name(testA)).")); + ASSERT_NE(string::npos, output.find("bind_module(1, status(needToTestEvenMore)).")); +} + +TEST(Modules, Requests1){ + +} + +TEST(Modules, Solve1){ + const std::string dirModulesRoot = "/tmp/testModulesDiscovery1_t54724/"; + + string codeA = +R"Code(module { + name(testA). + provide(superService). + status(needToTestMore). +})Code"; + + string codeB = +R"Code(module { + name(testB). + provide(superService). + status(needToTestEvenMore). +})Code"; + + string codeMain = +R"Code(module { + discover("/tmp/testModulesDiscovery1_t54724/") + include controller ("/tmp/testModulesDiscovery1_t54724/controller") + + require (superService) +})Code"; + + string codeController = +R"Code( +status_score(0, needToTestEvenMore). +status_score(1, needToTestMore). + +module_include_candidate(X, Y, Request):- + module_require(X, Request); bind_module(Y, provide(Request)). + +module_include_winner(X, Request, MaxScore) :- + MaxScore = #max{Score: module_include_candidate(X, Y, Request), bind_module(Y, status(Status)), status_score(Score, Status)}; + module_require(X, Request). + +module_include(X, Y) :- + module_include_winner(X, Request, MaxScore); + bind_module(Y, provide(Request)); + bind_module(Y, status(Status)); + status_score(MaxScore, Status). +)Code"; + + fs::create_directories(dirModulesRoot); + fs::ofstream fileA(dirModulesRoot + "a.xreate"); + fileA << codeA; + fileA.close(); + + fs::ofstream fileB(dirModulesRoot + "b.xreate"); + fileB << codeB; + fileB.close(); + + fs::ofstream fileController(dirModulesRoot + "controller"); + fileController << codeController; + fileController.close(); + + Scanner scanner(reinterpret_cast(codeMain.c_str()), codeMain.size()); + Parser parser(&scanner); + parser.Parse(); + + ModulesRegistry registry; + ModulesSolver solver(®istry); + solver.init("", parser.module); + fs::remove_all(dirModulesRoot); + + cout << solver.__program.str() << endl; + std::list modulesRequired = solver.run(parser.module); + + ASSERT_EQ(1, modulesRequired.size()); + string moduleActualRequired = modulesRequired.front(); + + string moduleExpected = dirModulesRoot + "a.xreate"; + ASSERT_EQ(moduleExpected, moduleActualRequired); +} + +TEST(Modules, Compilation1){ + const std::string dirModulesRoot = "/tmp/testModulesDiscovery1_t54726/"; + + string codeMain = +R"Code( +module { + discover("/tmp/testModulesDiscovery1_t54726/") + include controller("/tmp/testModulesDiscovery1_t54726/controller") + + require (superService) +} + +test = function:: int; entry { + getYourNumber() +} +)Code"; + + string codeA = +R"Code(module { + name(testA). + provide(superService). + status(needToTestEvenMore). +} + +getYourNumber= function:: int {0} +)Code"; + + string codeB = +R"Code(module { + name(testB). + provide(superService). + status(needToTestMore). +} + +getYourNumber= function:: int {1} +)Code"; + +string codeController = +R"Code( +status_score(0, needToTestEvenMore). +status_score(1, needToTestMore). + +module_include_candidate(X, Y, Request):- + module_require(X, Request); bind_module(Y, provide(Request)). + +module_include_winner(X, Request, MaxScore) :- + MaxScore = #max{Score: module_include_candidate(X, Y, Request), bind_module(Y, status(Status)), status_score(Score, Status)}; + module_require(X, Request). + +module_include(X, Y) :- + module_include_winner(X, Request, MaxScore); + bind_module(Y, provide(Request)); + bind_module(Y, status(Status)); + status_score(MaxScore, Status). +)Code"; + + fs::create_directories(dirModulesRoot); + fs::ofstream fileA(dirModulesRoot + "a.xreate"); + fileA << codeA; + fileA.close(); + + fs::ofstream fileB(dirModulesRoot + "b.xreate"); + fileB << codeB; + fileB.close(); + + fs::ofstream fileController(dirModulesRoot + "controller"); + fileController << codeController; + fileController.close(); + + auto man = new XreateManagerImpl>(); + man->prepareCode(std::move(codeMain)); + fs::remove_all(dirModulesRoot); + + int (*funcMain)() = (int (*)()) man->run(); + int result = funcMain(); + ASSERT_EQ(1, result); +} + +TEST(Modules, Compilation_AssignModulePath1){ + const std::string dirModulesRoot = "/tmp/testModulesDiscovery1_t54725/"; + string codeMain = +R"Code( +module { + discover("/tmp/testModulesDiscovery1_t54725/") + include controller("/tmp/testModulesDiscovery1_t54725/controller") + + require (superService) +} + +test = function:: int; entry { + getYourNumber() +} +)Code"; + + string codeA = +R"Code(module { + name(testA). + provide(superService). + status(needToTestEvenMore). +} + +getYourNumber= function:: int {0} +)Code"; + + string codeController = +R"Code( +module_include(X, "/tmp/testModulesDiscovery1_t54725/a.xreate") :- module_require(X, superService). +)Code"; + + fs::create_directories(dirModulesRoot); + fs::ofstream fileA(dirModulesRoot + "a.xreate"); + fileA << codeA; + fileA.close(); + + fs::ofstream fileController(dirModulesRoot + "controller"); + fileController << codeController; + fileController.close(); + + auto man = new XreateManagerImpl>(); + man->prepareCode(std::move(codeMain)); + fs::remove_all(dirModulesRoot); + + int (*funcMain)() = (int (*)()) man->run(); + int result = funcMain(); + ASSERT_EQ(0, result); +} diff --git a/cpp/tests/polymorph.cpp b/cpp/tests/polymorph.cpp new file mode 100644 index 0000000..9835ac1 --- /dev/null +++ b/cpp/tests/polymorph.cpp @@ -0,0 +1,147 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ + * + * polymorph.cpp + * + * Author: pgess + * Created on October 11, 2017, 8:37 PM + */ + +#include "xreatemanager.h" +#include "ast.h" +#include "transcendlayer.h" +#include "aux/latereasoning.h" +#include +#include "gtest/gtest.h" +#include "query/polymorph.h" + +using namespace xreate; +using namespace xreate::latereasoning; +using namespace xreate::polymorph; +using namespace std; + +TEST(Polymorphs, ast1) { + xreate::XreateManager* man = xreate::XreateManager::prepare( + R"CODE( + guard:: a { + test = function:: int {0} + } + + guard:: b { + test = function:: int {1} + } + + main = function:: int; entry { test() } + +)CODE"); + + const std::list& specs = man->root->getFunctionSpecializations("test"); + ASSERT_EQ(2, specs.size()); + + auto itSpecs = specs.begin(); + ASSERT_EQ("a", (*itSpecs)->guard.getValueString()); + itSpecs++; + ASSERT_EQ("b", (*itSpecs)->guard.getValueString()); +} + +TEST(Polymorphs, PolymorphQuery_Static_1) { + xreate::details::tier1::XreateManager* man = xreate::details::tier1::XreateManager::prepare( + R"CODE( + import raw("scripts/dfa/polymorphism.lp"). + + guard:: a { + test = function:: int {0} + } + + guard:: b { + test = function:: int {1} + } + + main = function:: int; entry { test()::int; callguard(b); dfa_polym(ret)} + +)CODE"); + + man->analyse(); + PolymorphQuery* query = dynamic_cast (man->transcend->getQuery(QueryId::PolymorphQuery)); + + const Expression& bodyE = man->root->findFunction("main")->getEntryScope()->getBody(); + LateAnnotation decisionLA = query->get(bodyE); + ASSERT_EQ(1, decisionLA.guardedContent.size()); + + auto decisionOptSymb = decisionLA.select({}, man->root, man->transcend); + ASSERT_TRUE(decisionOptSymb); + + decisionOptSymb->print(cout); + cout << endl; + string guard = query->getValue(*decisionOptSymb).getValueString(); + ASSERT_STREQ("b", guard.c_str()); +} + +TEST(Polymorphs, PolymorphQuery_Late_1){ + xreate::details::tier1::XreateManager* man = xreate::details::tier1::XreateManager::prepare( +R"CODE( + Late = type variant{a, b}. + main = function:: int; entry{key= a():: Late; test. key::int} +)CODE"); + + man->transcend->addRawScript( +R"RULE( + late(S, S, a, dfa_callguard(S, a)):- + bind(S, test). + + late(S, S, b, dfa_callguard(S, b)):- + bind(S, test). +)RULE"); + man->analyse(); + PolymorphQuery* query = dynamic_cast (man->transcend->getQuery(QueryId::PolymorphQuery)); + + CodeScope* scopeMain = man->root->findFunction("main")->getEntryScope(); + Symbol keyS = Symbol{scopeMain->getSymbol("key"), scopeMain}; + + Expression keyE = scopeMain->getDefinition(keyS); + latereasoning::LateAnnotation answerLA = query->get(keyE); + Expression valueB(Operator::VARIANT, {}); valueB.setValueDouble(1); + auto answerRaw = answerLA.select({valueB}, man->root, man->transcend); + ASSERT_TRUE(answerRaw); + Expression answerE = query->getValue(*answerRaw); + ASSERT_STREQ("b", answerE.getValueString().c_str()); +} + +TEST(Polymorphs, PSCU_1){ + auto man = details::tier1::XreateManager::prepare(R"Code( + Dom = type variant {guard1, guard2}. + + guard:: guard1 { + compute = function :: int + {0} + } + + guard:: guard2 { + compute = function :: int + {1} + } + + test = function:: int; entry + { + xLate = guard2():: Dom. + y1= switch late (xLate:: Dom; alias(xLate)):: int + { + compute():: int; guardkey(xLate) + }. + y1 + } + )Code"); + + man->transcend->addRawScript(R"RAW( + dom(guard1; guard2). + late(Target, Key, Variant, dfa_callguard(Target, Variant)):- + bind(Target, guardkey(Alias)); + bind(Key, alias(Alias)); + dom(Variant). + )RAW"); + man->analyse(); + int (*program)() = (int (*)())man->run(); + int result = program(); + + ASSERT_EQ(1, result); +} diff --git a/cpp/tests/supplemental/versions-algorithm-data_dependency.cpp b/cpp/tests/supplemental/versions-algorithm-data_dependency.cpp new file mode 100644 index 0000000..121e0ad --- /dev/null +++ b/cpp/tests/supplemental/versions-algorithm-data_dependency.cpp @@ -0,0 +1,297 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ + * + * File: algorithm-data_dependency + * Date: Dec 23, 2016 + * Author: pgess + */ + +#include +#include +#include +#include +#include "gtest/gtest.h" +#include +#include + + +const int V_NOVERSION = -2; +const int V_ENDOFLIFE = -1; + +struct Symbol { + std::string name; + int version; + + Symbol getNextVersion() const{ + return Symbol{name, version+1}; + } +}; + +namespace std +{ + template<> + struct hash + { + typedef Symbol argument_type; + typedef std::size_t result_type; + result_type operator()(argument_type const& s) const + { + result_type const h1 ( std::hash()(s.name) ); + return h1 ^ (s.version << 1); // or use boost::hash_combine + } + }; + + template<> + struct equal_to + { + typedef Symbol argument_type; + + bool operator()(const argument_type& __x, const argument_type& __y) const + { return __x.name == __y.name && __x.version == __y.version; } + }; +} + +//Ограничения: +// - точно знаем следующую версию на этапе декл. (C.NV.1) + +class DDSolver{ +public: + + void l1_applyLowerBound(const Symbol& left, const std::initializer_list& dependencies){ + for (Symbol right: dependencies){ + //lower bound: + __infs.emplace(left, right); + __sups.emplace(right, left); + } + } + + void l1_applyOwnUpperBound(const Symbol& left){ + //own upper bound: + //C.NV.1 + __infs.emplace(left.getNextVersion(), left); + __sups.emplace(left, left.getNextVersion()); + } + + void l1_applyDependentUpperBound(const Symbol& left, const std::initializer_list& dependencies){ + // additionally apply dependent upper bound + for (Symbol right: dependencies){ + auto right2 = right.getNextVersion(); + + __infs.emplace(right2, left); + __sups.emplace(left, right2); + } + } + + void addVariable(const Symbol& left, const std::initializer_list& dependencies){ + l1_applyLowerBound(left, dependencies); + l1_applyOwnUpperBound(left); + + //initialization upper bound + l1_applyDependentUpperBound(left, dependencies); + + } + + //TODO assert: only aliases allowed + void addAlias(const Symbol& left, const std::initializer_list& dependencies){ + l1_applyLowerBound(left, dependencies); + l1_applyOwnUpperBound(left); + + //lifetime upper bound + l1_applyDependentUpperBound(left.getNextVersion(), dependencies); + } + + + bool checkCyclicComponent(const Symbol& s, std::unordered_set& symbolsVisited, std::unordered_set& symbolsSups){ + if (symbolsVisited.count(s)) return false; + + symbolsVisited.insert(s); + symbolsSups.insert(s); + + auto rangeInf = __infs.equal_range(s); + if (__infs.count(s)) + for (auto sInf = rangeInf.first; sInf != rangeInf.second; ++sInf){ + if (symbolsSups.count(sInf->second)) { + __flagCycle = std::make_pair(sInf->second, s); + return true; + } + if(checkCyclicComponent(sInf->second, symbolsVisited, symbolsSups)) return true; + } + + symbolsSups.erase(s); + return false; + } + + bool checkCyclicFull(){ + std::unordered_set symbolsVisited, symbolsSups; + + std::unordered_multimap::iterator s; + for (s = __infs.begin(); s != __infs.end(); ++s){ + if(checkCyclicComponent(s->first, symbolsVisited, symbolsSups)) return true; + } + + return false; + } + + bool validate(){ + return !checkCyclicFull(); + } + + void solve(){ + std::unordered_set binEnabled, binFrontier; + + //seed + for (auto edge: __sups){ + if (! __infs.count(edge.first)){ + binEnabled.insert(edge.first); + binFrontier.insert(edge.first); + } + } + + while (binFrontier.size()){ + const Symbol& node= *binFrontier.begin(); + + //print node: + std:: printf("put (%s, %d)\n", node.name.c_str(), node.version); + + auto rangeSups = __sups.equal_range(node); + for(auto sup=rangeSups.first; sup != rangeSups.second; ++sup){ + bool flagEnabled = true; + + auto rangeInfs = __infs.equal_range(sup->second); + for (auto inf=rangeInfs.first; inf != rangeInfs.second; ++inf){ + if (!binEnabled.count(inf->second)){ + flagEnabled = false; + break; + } + } + + if (flagEnabled){ + binEnabled.insert(sup->second); + binFrontier.insert(sup->second); + } + } + + binFrontier.erase(node); + } + } + + void solve2(Symbol nodeEntry, std::unordered_set& binPreviousNodes, std::unordered_set& binEnabledNodes){ + binPreviousNodes.insert(nodeEntry); + + auto rangeChilds = __infs.equal_range(nodeEntry); + for(auto node=rangeChilds.first; node != rangeChilds.second; ++node){ + if (binEnabledNodes.count(node->second)) continue; + + auto nodeError = binPreviousNodes.find(node->second); + if (nodeError != binPreviousNodes.end()){ + std:: printf("(%s, %d) - (%s, %d)", + nodeError->name.c_str(), nodeError->version, + node->second.name.c_str(), node->second.version); + assert(false); + } + + solve2(node->second, binPreviousNodes, binEnabledNodes); + } + + std:: printf("put (%s, %d)\n", nodeEntry.name.c_str(), nodeEntry.version); + binEnabledNodes.insert(nodeEntry); + binPreviousNodes.erase(nodeEntry); + +// auto rangeParents = __sups.equal_range(nodeEntry); +// for(auto node=rangeParents.first; node != rangeParents.second; ++node){ +// std::unordered_set binEmpty; +// solve2(node->second, binEmpty, binEnabledNodes); +// } + } + + void __debug_printGraph(){ + for (auto edge: __infs){ + std:: printf("(%s, %d) <- (%s, %d) \n", + edge.second.name.c_str(), edge.second.version, + edge.first.name.c_str(), edge.first.version); + } + } + +private: + std::unordered_multimap __sups; + std::unordered_multimap __infs; + +public: + std::pair __flagCycle; +}; + +TEST(Datadependency, test1){ + DDSolver solver; + + solver.addAlias(Symbol{"c", V_NOVERSION}, {Symbol{"a", 0}}); + solver.addVariable(Symbol{"a", 1}, {Symbol{"b", 0}}); + solver.addVariable(Symbol{"b", 1}, {Symbol{"c", V_NOVERSION}}); + + solver.__debug_printGraph(); + + ASSERT_FALSE(solver.validate()); + + std:: printf("(%s, %d) - (%s, %d)", + solver.__flagCycle.first.name.c_str(), solver.__flagCycle.first.version, + solver.__flagCycle.second.name.c_str(), solver.__flagCycle.second.version); +} + +TEST(Datadependency, test2){ + DDSolver solver; + + solver.addVariable(Symbol{"c", V_NOVERSION}, {Symbol{"a", 0}}); + solver.addVariable(Symbol{"a", 1}, {Symbol{"b", 0}}); + solver.addVariable(Symbol{"b", 1}, {Symbol{"c", V_NOVERSION}}); + + ASSERT_TRUE(solver.validate()); + + solver.solve(); +} + +TEST(Datadependency, test3){ + DDSolver solver; + + solver.addVariable(Symbol{"c", V_NOVERSION}, {Symbol{"a", 0}}); + solver.addVariable(Symbol{"a", 1}, {Symbol{"b", 0}}); + solver.addVariable(Symbol{"b", 1}, {Symbol{"c", V_NOVERSION}}); + + std::unordered_set binPreviousNodes, binEnabledNodes; + solver.solve2(Symbol{"b", 1}, binPreviousNodes, binEnabledNodes); + ASSERT_TRUE(true); +} + +TEST(Datadependency, test4){ + DDSolver solver; + + solver.addVariable(Symbol{"c", V_NOVERSION}, {Symbol{"a", 0}}); + solver.addVariable(Symbol{"a", 1}, {Symbol{"b", 0}}); + solver.addVariable(Symbol{"b", 1}, {Symbol{"c", V_NOVERSION}}); + + std::unordered_set binPreviousNodes, binEnabledNodes; + solver.solve2(Symbol{"b", 1}, binPreviousNodes, binEnabledNodes); + ASSERT_TRUE(true); +} + +TEST(Datadependency, test5){ + DDSolver solver; + + solver.addAlias(Symbol{"b", V_NOVERSION}, {Symbol{"a", 0}}); + solver.addVariable(Symbol{"a", 1}, {Symbol{"b", V_NOVERSION}}); + + std:: printf("(%s, %d) - (%s, %d)", + solver.__flagCycle.first.name.c_str(), solver.__flagCycle.first.version, + solver.__flagCycle.second.name.c_str(), solver.__flagCycle.second.version); + + ASSERT_TRUE(solver.validate()); +} + +TEST(Datadependency, test6){ + DDSolver solver; + + solver.addVariable(Symbol{"a", 1}, {Symbol{"a", 0}}); + + std::unordered_set binPreviousNodes, binEnabledNodes; + solver.solve2(Symbol{"a", 1}, binPreviousNodes, binEnabledNodes); + + ASSERT_TRUE(solver.validate()); +} diff --git a/cpp/tests/testClangAPI.h b/cpp/tests/testClangAPI.h deleted file mode 100644 index aab7ee5..0000000 --- a/cpp/tests/testClangAPI.h +++ /dev/null @@ -1,9 +0,0 @@ -// -// Created by pgess on 4/16/15. -// - -#ifndef XREATE_TESTCLANGAPI_H -#define XREATE_TESTCLANGAPI_H - -void testClang1(); -#endif //XREATE_TESTCLANGAPI_H diff --git a/cpp/tests/transcend.cpp b/cpp/tests/transcend.cpp new file mode 100644 index 0000000..5ad0ef3 --- /dev/null +++ b/cpp/tests/transcend.cpp @@ -0,0 +1,43 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ + * + * Author: pgess + * Created on June 7, 2018, 3:35 PM + * + * \file transcend.cpp + * \brief Transcend's tests + */ + +#include "xreatemanager.h" +#include "transcendlayer.h" +#include + +using namespace xreate; +using namespace std; + +TEST(Transcend, Parse1) { + std::string script = +R"Code( +)Code"; + + std::unique_ptr man(details::tier1::XreateManager::prepare(std::move(script))); + + std::string scriptTranscend = +R"Code( + test1((1)). + test2((1, 2)). +)Code"; + + man->transcend->addRawScript(move(scriptTranscend)); + man->analyse(); + + StaticModel solution = man->transcend->query("test1"); + Gringo::Symbol symbTest1 = solution.begin()->second; + auto answer1 = man->transcend->parse>(symbTest1); + ASSERT_EQ(1, get<0>(answer1).size()); + + solution = man->transcend->query("test2"); + Gringo::Symbol symbTest2 = solution.begin()->second; + auto answer2 = get<0>(man->transcend->parse>(symbTest2)); + ASSERT_EQ(2, answer2.size()); +} \ No newline at end of file diff --git a/cpp/tests/types.cpp b/cpp/tests/types.cpp index d90a673..a25c7d4 100644 --- a/cpp/tests/types.cpp +++ b/cpp/tests/types.cpp @@ -1,167 +1,248 @@ -/* +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ + * * types.cpp * * Created on: Jun 4, 2015 - * Author: pgess + * Author: pgess */ #include "gtest/gtest.h" -#include "passmanager.h" +#include "xreatemanager.h" #include "llvmlayer.h" -#include "Parser.h" +#include "main/Parser.h" +#include "transcendlayer.h" +#include "analysis/typeinference.h" +#include "analysis/interpretation.h" using namespace std; using namespace xreate; +using namespace xreate::grammar::main; TEST(Types, DependantTypes1) { - string&& code = "XmlNode = type 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); + string&& code = "XmlNode = type {\n" + " tag:: string,\n" + " attrs:: [string], \n" + " content:: string\n" + "}.\n"; + + std::unique_ptr program(XreateManager::prepare(move(code))); + ExpandedType typeXmlNode = program->root->findType("XmlNode"); + + ASSERT_EQ(TypeOperator::LIST_NAMED, typeXmlNode->__operator); + ASSERT_EQ(3, typeXmlNode->__operands.size()); + ASSERT_EQ(TypePrimitive::String, typeXmlNode->__operands.at(0).__value); + ASSERT_EQ(TypeOperator::LIST, typeXmlNode->__operands.at(1).__operator); + ASSERT_EQ(TypePrimitive::String, typeXmlNode->__operands.at(2).__value); } -TEST(Types, 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, ast_ParameterizedTypes_FeatureTypeIndex_1) { + string&& code = "XmlNode = type {\n" + " tag:: string,\n" + " attrs:: [string],\n" + " content:: string\n" + "}.\n" + "" + "Template = type(Leaf) {Leaf, [Leaf[\"content\"]]}." + "Concrete = type Template(XmlNode)."; + + std::unique_ptr program(XreateManager::prepare(move(code))); + ExpandedType typeConcrete = program->root->findType("Concrete"); + + ASSERT_EQ(TypeOperator::LIST_NAMED, typeConcrete->__operator); + ASSERT_EQ(2, typeConcrete->__operands.size()); + ASSERT_EQ(TypeOperator::LIST_NAMED, typeConcrete->__operands.at(0).__operator); + + ASSERT_EQ(TypeOperator::LIST, typeConcrete->__operands.at(1).__operator); + ASSERT_EQ(TypePrimitive::String, typeConcrete->__operands.at(1).__operands.at(0).__value); } TEST(Types, TreeType1) { - string&& code = "XmlNode = type 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); + string&& code = "XmlNode = type {\n" + " tag:: string,\n" + " attrs:: [string],\n" + " content:: string\n" + "}.\n" + "" + "Tree = type(Leaf) {Leaf, [Tree(Leaf)]}." + "Concrete = type Tree(XmlNode)."; + + std::unique_ptr program(XreateManager::prepare(move(code))); + ExpandedType typeConcrete = program->root->findType("Concrete"); + + ASSERT_EQ(TypeOperator::LIST_NAMED, typeConcrete->__operator); + ASSERT_EQ(2, typeConcrete->__operands.size()); + ASSERT_EQ(TypeOperator::LIST_NAMED, typeConcrete->__operands.at(0).__operator); + + ASSERT_EQ(TypeOperator::LIST, typeConcrete->__operands.at(1).__operator); + + auto typeLink = typeConcrete->__operands.at(1).__operands.at(0); + ASSERT_EQ(TypeOperator::LINK, typeLink.__operator); + ASSERT_EQ(typeConcrete->conjuctionId, typeLink.conjuctionId); } -TEST(Types, TreeType1LLvm){ - string&& code = "XmlNode = type alias {\n" - " tag:: string,\n" - " /* attrs:: [string],*/\n" - " content:: string\n" - "}.\n" - "" - "Tree = type Tree(Leaf) [Leaf, [Tree(Leaf)]]." - "Concrete = type alias Tree(XmlNode)."; +TEST(Types, TreeType1LLvm) { + string&& code = "XmlNode = type {\n" + " tag:: string,\n" + " /* attrs:: [string],*/\n" + " content:: string\n" + "}.\n" + "" + "Tree = type(Leaf) {Leaf, [Tree(Leaf)]}." + "Concrete = type Tree(XmlNode)."; - std::unique_ptr program(PassManager::prepareForCode(move(code))); - ExpandedType typeConcrete = program->root->findType("Concrete"); + std::unique_ptr program(XreateManager::prepare(move(code))); + ExpandedType typeConcrete = program->root->findType("Concrete"); - llvm::Type* raw = program->llvm->toLLVMType(typeConcrete); + llvm::Type* raw = program->llvm->toLLVMType(typeConcrete); } -TEST(Types, ArrayOfExternal1){ - FILE* input = fopen("scripts/testspass/Containers_Implementation_LinkedList1.xreate","r"); - assert(input != nullptr); +TEST(Types, ArrayOfExternal1) { + FILE* input = fopen("scripts/containers/Containers_Implementation_LinkedList1.xreate", "r"); + assert(input != nullptr); - Scanner scanner(input); - Parser parser(&scanner); - parser.Parse(); + Scanner scanner(input); + Parser parser(&scanner); - AST& ast = parser.root; - CodeScope* body = ast.findFunction("test")->getEntryScope(); + parser.Parse(); + AST* ast = parser.root->finalize(); - Symbol symb = body->findSymbol("childrenRaw"); + CodeScope* body = ast->findFunction("test")->getEntryScope(); - const TypeAnnotation& t = CodeScope::findDeclaration(symb).type; - const ExpandedType& t2 = ast.expandType(t); - EXPECT_EQ(t2->__operator, TypeOperator::ARRAY); + const ExpandedType& t2 = ast->getType(body->getDefinition(body->getSymbol("childrenRaw"))); + EXPECT_EQ(t2->__operator, TypeOperator::LIST); } -TEST(Types, ExternType1){ - FILE* input = fopen("scripts/testspass/Containers_Implementation_LinkedList1.xreate","r"); - assert(input != nullptr); - - Scanner scanner(input); - Parser parser(&scanner); - parser.Parse(); +TEST(Types, ExternType1) { + FILE* input = fopen("scripts/containers/Containers_Implementation_LinkedList1.xreate", "r"); + assert(input != nullptr); - AST& ast = parser.root; - CodeScope* body = ast.findFunction("test")->getEntryScope(); + Scanner scanner(input); + Parser parser(&scanner); + parser.Parse(); - Symbol symbTree = body->findSymbol("tree"); + AST* ast = parser.root->finalize(); + CodeScope* body = ast->findFunction("test")->getEntryScope(); - const TypeAnnotation& t = CodeScope::findDeclaration(symbTree).type; - const ExpandedType& t2 = ast.expandType(t); + const ExpandedType& t2 = ast->getType(body->getDefinition(body->getSymbol("tree"))); EXPECT_EQ(t2->__operator, TypeOperator::CUSTOM); } -TEST(Types, ast_VariantType1){ - string&& code = - " colors = type variant (RED, BLUE, GREEN).\n" - " test = function:: colors; entry {GREEN}"; +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))); + std::unique_ptr program(XreateManager::prepare(move(code))); - ExpandedType typ = program->root->findType("colors"); - EXPECT_EQ(TypeOperator::VARIANT, typ->__operator); + ExpandedType typ = program->root->findType("colors"); + EXPECT_EQ(TypeOperator::VARIANT, typ->__operator); - Expression eRed = program->root->findFunction("test")->getEntryScope()->getBody(); - EXPECT_EQ(Expression::VARIANT, eRed.__state); + Expression eRed = program->root->findFunction("test")->getEntryScope()->getBody(); + EXPECT_EQ(Operator::VARIANT, eRed.op); - const ExpandedType& typ2 = program->root->expandType(eRed.type); - EXPECT_EQ(TypeOperator::VARIANT, typ2->__operator); - - program->run(); + const ExpandedType& typ2 = program->root->getType(eRed); + EXPECT_EQ(TypeOperator::VARIANT, typ2->__operator); } -TEST(Types, full_VariantType_Switch1){ - string&& code = - " colors = type variant (RED, BLUE, GREEN). \n" - " test = function:: colors {GREEN} \n" +TEST(Types, full_VariantType_Switch1) { + string&& code = + "colors = type variant{RED, BLUE, GREEN}. \n" + " test = function:: colors {GREEN()} \n" + + "main = function:: int; entry { \n" + " switch(test()):: int \n" + " case (GREEN()) {0} \n" + " case default {1} \n" + "}"; + + XreateManager* man = XreateManager::prepare(move(code)); + int (*main)() = (int (*)()) man->run(); - "main = function:: int; entry { \n" - " switch(test()):: int \n" - " case GREEN {0} \n" - " case default {1} \n" - "}"; + EXPECT_EQ(0, main()); +} - PassManager* man = PassManager::prepareForCode(move(code)); - int (*main)() = (int (*)()) man->run(); +TEST(Types, ast_VariantType2) { + std::string script = + R"Code( + Annotation = type + variant { + Num:: int, + String:: string, + Func:: {name::string, arguments::[Expression]} + }. +)Code"; + + std::unique_ptr program(XreateManager::prepare(move(script))); + ExpandedType typ = program->root->findType("Annotation"); + ASSERT_EQ(3, typ.get().fields.size()); +} - EXPECT_EQ(0, main()); +TEST(Types, SlaveTypes_UnwrapSlaveType1) { + auto man = details::tier1::XreateManager::prepare(R"Code( + AtomNumT = type slave atomNumT. + AtomStrT = type slave atomStrT. + CmpndIntStrT = type slave cmpndIntStrT. + + VariantT = type slave variantT. + + VariantComplicatedT = type slave variantComplicatedT. + )Code"); + + man->transcend->addRawScript(R"RAW( + atomNumT(5). atomNumT(8). + atomStrT("a"). atomStrT("b"). + cmpndIntStrT(1, "a"). + cmpndIntStrT(2, "b"). + + variantT(first). + variantT(second). + variantT(third). + + variantComplicatedT(first(1, "a")). + variantComplicatedT(second("b")). + )RAW"); + + man->analyse(); + ExpandedType AtomNumT = man->root->findType("AtomNumT"); + ASSERT_EQ(AtomNumT->__operator, TypeOperator::SLAVE); + + ExpandedType ContentAtomNumT = interpretation::dereferenceSlaveType(AtomNumT, man->transcend); + ASSERT_EQ(TypePrimitive::Num, ContentAtomNumT->__value); + + ExpandedType AtomStrT = man->root->findType("AtomStrT"); + ExpandedType ContentAtomStrT = interpretation::dereferenceSlaveType(AtomStrT, + man->transcend); + ASSERT_EQ(TypePrimitive::String, ContentAtomStrT->__value); + + ExpandedType CmpndIntStrT = man->root->findType("CmpndIntStrT"); + ExpandedType ContentCmpndIntStrT = interpretation::dereferenceSlaveType(CmpndIntStrT, + man->transcend); + ASSERT_EQ(TypeOperator::LIST_NAMED, ContentCmpndIntStrT->__operator); + ASSERT_EQ(2, ContentCmpndIntStrT->__operands.size()); + + ExpandedType VariantT = man->root->findType("VariantT"); + ExpandedType ContentVariantT = interpretation::dereferenceSlaveType(VariantT, + man->transcend); + ASSERT_EQ(TypeOperator::VARIANT, ContentVariantT->__operator); + ASSERT_EQ(3, ContentVariantT->fields.size()); + + ExpandedType VariantComplicatedT = man->root->findType("VariantComplicatedT"); + ExpandedType ContentVariantComplicatedT = interpretation::dereferenceSlaveType(VariantComplicatedT, + man->transcend); + ASSERT_EQ(TypeOperator::VARIANT, ContentVariantComplicatedT->__operator); + ASSERT_EQ(2, ContentVariantComplicatedT->fields.size()); + ASSERT_EQ(2, ContentVariantComplicatedT->__operands.at(0).__operands.size()); } +TEST(Types, IndexNumber_1) +{ + string&& code = +R"CODE( + Tuple = type {string, int}. + Int = type Tuple[1]. +)CODE"; -//TOTEST string type + std::unique_ptr program(XreateManager::prepare(move(code))); + ExpandedType typeInt = program->root->findType("Int"); +} diff --git a/cpp/tests/virtualization.cpp b/cpp/tests/virtualization.cpp new file mode 100644 index 0000000..fe6bc53 --- /dev/null +++ b/cpp/tests/virtualization.cpp @@ -0,0 +1,60 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ + * + * virtualization.cpp + * + * Author: pgess + * Created on February 24, 2018, 4:30 PM + */ + +#include "xreatemanager.h" +#include "ast.h" +#include "analysis/interpretation.h" +#include "gtest/gtest.h" +using namespace xreate; +using namespace std; + +TEST(Virtualization, UniqueSizoPrefix_1) { + FILE* input = fopen("scripts/virtualization/test1.xreate", "r"); + assert(input != nullptr); + + std::unique_ptr man(details::tier1::XreateManager::prepare(input)); + man->analyse(); + + ExpandedType typeDictSizoS = man->root->findType("DictSizo"); + ExpandedType typeDictSizo = interpretation::dereferenceSlaveType(typeDictSizoS, man->transcend); + ASSERT_EQ(TypeOperator::LIST_NAMED, typeDictSizo->__operator); + int (*main)() = (int (*)())man->run(); + + testing::internal::CaptureStdout(); + main(); + std::string outputActual = testing::internal::GetCapturedStdout(); + cout << outputActual << endl; + ASSERT_STREQ("file opened: /0/test1 file opened: /1/test1 ", outputActual.c_str()); +} + +TEST(Virtualization, GlobalDereferenceStrategy_1) { + FILE* input = fopen("scripts/virtualization/test2.xreate", "r"); + assert(input != nullptr); + std::unique_ptr man(XreateManager::prepare(input)); + int (*main)() = (int (*)())man->run(); + + testing::internal::CaptureStdout(); + main(); + std::string outputActual = testing::internal::GetCapturedStdout(); + cout << outputActual << endl; + ASSERT_STREQ("file opened: test1 file opened: test1 ", outputActual.c_str()); +} + +TEST(Virtualization, LocalDereferenceStrategy_1) { +FILE* input = fopen("scripts/virtualization/test3.xreate", "r"); + assert(input != nullptr); + std::unique_ptr man(XreateManager::prepare(input)); + int (*main)() = (int (*)())man->run(); + + testing::internal::CaptureStdout(); + main(); + std::string outputActual = testing::internal::GetCapturedStdout(); + cout << outputActual << endl; + ASSERT_STREQ("file opened: test1 file opened: 1/test1 ", outputActual.c_str()); +} diff --git a/documentation-api/AST-correspondence.fods b/documentation-api/AST-correspondence.fods new file mode 100644 index 0000000..2c9d3e7 --- /dev/null +++ b/documentation-api/AST-correspondence.fods @@ -0,0 +1,620 @@ + + + + 2018-08-02T18:59:05.238218130LibreOffice/6.0.5.2$Linux_X86_64 LibreOffice_project/00m0$Build-22018-10-01T19:29:44.753564292PT6H30M19S9 + + + 0 + 0 + 38038 + 22621 + + + view1 + + + 2 + 38 + 0 + 0 + 0 + 0 + 2 + 0 + 0 + 0 + 15 + 0 + 100 + 60 + true + false + + + Sheet1 + 1237 + 0 + 100 + 60 + false + true + true + true + 12632256 + true + true + true + true + false + false + false + 1270 + 1270 + 1 + 1 + true + false + + + + + 7 + true + false + false + 0 + true + sgH+/0xleG1hcmstWDY1NmRlAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQ1VQUzpMZXhtYXJrLVg2NTZkZQAAAAAAAAAAAAAAAAAWAAMA0wAAAAAAAAAIAFZUAAAkbQAASm9iRGF0YSAxCnByaW50ZXI9TGV4bWFyay1YNjU2ZGUKb3JpZW50YXRpb249UG9ydHJhaXQKY29waWVzPTEKY29sbGF0ZT1mYWxzZQptYXJnaW5kYWp1c3RtZW50PTAsMCwwLDAKY29sb3JkZXB0aD0yNApwc2xldmVsPTAKcGRmZGV2aWNlPTEKY29sb3JkZXZpY2U9MApQUERDb250ZXhEYXRhCkR1cGxleDpOb25lAElucHV0U2xvdDpUcmF5MQBQYWdlU2l6ZTpMZXR0ZXIAABIAQ09NUEFUX0RVUExFWF9NT0RFDwBEdXBsZXhNb2RlOjpPZmY= + Lexmark-X656de + true + 3 + true + false + true + true + 12632256 + true + true + true + false + true + false + true + 1 + false + 1270 + 1270 + false + 1 + true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ??? + + + + Page 1 + + + + + + + ???(???) + + + 00/00/0000, 00:00:00 + + + + + Page 1/ 99 + + + + + + + + + + + + + + + + AST + + + Current Transcend + + + Proposition 1 + + + Types + + + Tests + + + + + Expr + + + + + + op + + + + + + id + + + + + + state + + + + + + bindings + + + + + + operands + + + + + + type + + + + + + tags + + + bind(var, annotation) + + + + + + blocks + + + + + + value + + + + + + + + + CodeScope + + + scope(scopeId) + + + ast_scope(scopeId) + + + + + + bindings + + ast_scope_binding(scopeId, BindingId, ScopeBindName) + + + ast_scope_binding(scopeId, BindingId, ScopeBindName) + + + LIST + + + CFA.ASTCorrespondence_Scope_Bindings_1 + + + + + identifiers + + + + ast_scope_identifier(scopeId, Var) + + + LIST + + + + + + parent + + + cfa_parent(scopeCurrent, scope(scopeParent)) + + + ast_scope_parent(ScopeId, ScopeParentId) + + + SINGLE + + + + + + declarations + + + + LIST + + + + + + tags + + + bind_scope(scopeId, tag, strong/weak(..)) + + + + LIST + + + + + + contextRules + + + + + + + + + Function + + + + + + entry + + + cfa_parent(scopeEntry, functon(name)) + + + + SINGLE + + + + + + name + + + function(name) + + + + SINGLE + + + + + + guard + + + cfa_function_specializations(funcName, tag) + + + + SINGLE + + + + + + tags + + + bind_func(name, tag) + + + + LIST + + + + + + + + + Special Expressions + + + + + + CALL + + cfa_call(scopeFrom, functionTo)dfa_callfn(SymbRet, FnName)weak/dfa_callargs(SymbRet, argFormal, argActual)dfa_fnret(fnName, symbRet) + + + + + + + + + Operator::MAP + + + + ast_op_map(SymbResult, SymbSource, ScopeBody) + + + + + + Operator::FOLD + + + + ast_op_fold(SymbResult, SymbSource, SymbAcc, ScopeBody) + + + + + + Operator::LIST + + + + ast_op_list(SymbResult, Size) + + + + + + Operator::LIST_RANGE + + + + ast_op_list_range(SymbResult) + + + + + + Operator::INDEX + + + + ast_op_index(SymbResult, SymbSource, SymbIndex) + + + + + + + + + + OTHER + + + + + + + var: s(id, version, scope), a(Num) + + + + + + + v(var1) + + + + + + + weak/dfa_alias(aliasFormal, Actual) + + + + + + + + \ No newline at end of file diff --git a/documentation-api/XreateDoxyfile b/documentation-api/XreateDoxyfile new file mode 100644 index 0000000..b6264fb --- /dev/null +++ b/documentation-api/XreateDoxyfile @@ -0,0 +1,2406 @@ +# Doxyfile 1.8.11 + +# This file describes the settings to be used by the documentation system +# doxygen (www.doxygen.org) for a project. +# +# All text after a double hash (##) is considered a comment and is placed in +# front of the TAG it is preceding. +# +# All text after a single hash (#) is considered a comment and will be ignored. +# The format is: +# TAG = value [value, ...] +# For lists, items can also be appended using: +# TAG += value [value, ...] +# Values that contain spaces should be placed between quotes (\" \"). + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- + +# This tag specifies the encoding used for all characters in the config file +# that follow. The default is UTF-8 which is also the encoding used for all text +# before the first occurrence of this tag. Doxygen uses libiconv (or the iconv +# built into libc) for the transcoding. See http://www.gnu.org/software/libiconv +# for the list of possible encodings. +# The default value is: UTF-8. + +DOXYFILE_ENCODING = UTF-8 + +# The PROJECT_NAME tag is a single word (or a sequence of words surrounded by +# double-quotes, unless you are using Doxywizard) that should identify the +# project for which the documentation is generated. This name is used in the +# title of most generated pages and in a few other places. +# The default value is: My Project. + +PROJECT_NAME = "Xreate" + +# The PROJECT_NUMBER tag can be used to enter a project or revision number. This +# could be handy for archiving the generated documentation or if some version +# control system is used. + +PROJECT_NUMBER = + +# Using the PROJECT_BRIEF tag one can provide an optional one line description +# for a project that appears at the top of each page and should give viewer a +# quick idea about the purpose of the project. Keep the description short. + +PROJECT_BRIEF = "Xreate programming language" + +# With the PROJECT_LOGO tag one can specify a logo or an icon that is included +# in the documentation. The maximum height of the logo should not exceed 55 +# pixels and the maximum width should not exceed 200 pixels. Doxygen will copy +# the logo to the output directory. + +PROJECT_LOGO = + +# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path +# into which the generated documentation will be written. If a relative path is +# entered, it will be relative to the location where doxygen was started. If +# left blank the current directory will be used. + +OUTPUT_DIRECTORY = "/tmp/xreate-documentation-api" + +# If the CREATE_SUBDIRS tag is set to YES then doxygen will create 4096 sub- +# directories (in 2 levels) under the output directory of each output format and +# will distribute the generated files over these directories. Enabling this +# option can be useful when feeding doxygen a huge amount of source files, where +# putting all generated files in the same directory would otherwise causes +# performance problems for the file system. +# The default value is: NO. + +CREATE_SUBDIRS = NO + +# If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII +# characters to appear in the names of generated files. If set to NO, non-ASCII +# characters will be escaped, for example _xE3_x81_x84 will be used for Unicode +# U+3044. +# The default value is: NO. + +ALLOW_UNICODE_NAMES = NO + +# The OUTPUT_LANGUAGE tag is used to specify the language in which all +# documentation generated by doxygen is written. Doxygen will use this +# information to generate all constant output in the proper language. +# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese, +# Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States), +# Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian, +# Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages), +# Korean, Korean-en (Korean with English messages), Latvian, Lithuanian, +# Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian, +# Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish, +# Ukrainian and Vietnamese. +# The default value is: English. + +OUTPUT_LANGUAGE = English + +# If the BRIEF_MEMBER_DESC tag is set to YES, doxygen will include brief member +# descriptions after the members that are listed in the file and class +# documentation (similar to Javadoc). Set to NO to disable this. +# The default value is: YES. + +BRIEF_MEMBER_DESC = YES + +# If the REPEAT_BRIEF tag is set to YES, doxygen will prepend the brief +# description of a member or function before the detailed description +# +# Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the +# brief descriptions will be completely suppressed. +# The default value is: YES. + +REPEAT_BRIEF = YES + +# This tag implements a quasi-intelligent brief description abbreviator that is +# used to form the text in various listings. Each string in this list, if found +# as the leading text of the brief description, will be stripped from the text +# and the result, after processing the whole list, is used as the annotated +# text. Otherwise, the brief description is used as-is. If left blank, the +# following values are used ($name is automatically replaced with the name of +# the entity):The $name class, The $name widget, The $name file, is, provides, +# specifies, contains, represents, a, an and the. + +ABBREVIATE_BRIEF = + +# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then +# doxygen will generate a detailed section even if there is only a brief +# description. +# The default value is: NO. + +ALWAYS_DETAILED_SEC = NO + +# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all +# inherited members of a class in the documentation of that class as if those +# members were ordinary class members. Constructors, destructors and assignment +# operators of the base classes will not be shown. +# The default value is: NO. + +INLINE_INHERITED_MEMB = NO + +# If the FULL_PATH_NAMES tag is set to YES, doxygen will prepend the full path +# before files name in the file list and in the header files. If set to NO the +# shortest path that makes the file name unique will be used +# The default value is: YES. + +FULL_PATH_NAMES = YES + +# The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path. +# Stripping is only done if one of the specified strings matches the left-hand +# part of the path. The tag can be used to show relative paths in the file list. +# If left blank the directory from which doxygen is run is used as the path to +# strip. +# +# Note that you can specify absolute paths here, but also relative paths, which +# will be relative from the directory where doxygen is started. +# This tag requires that the tag FULL_PATH_NAMES is set to YES. + +STRIP_FROM_PATH = ../ + +# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the +# path mentioned in the documentation of a class, which tells the reader which +# header file to include in order to use a class. If left blank only the name of +# the header file containing the class definition is used. Otherwise one should +# specify the list of include paths that are normally passed to the compiler +# using the -I flag. + +STRIP_FROM_INC_PATH = + +# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but +# less readable) file names. This can be useful is your file systems doesn't +# support long names like on DOS, Mac, or CD-ROM. +# The default value is: NO. + +SHORT_NAMES = NO + +# If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the +# first line (until the first dot) of a Javadoc-style comment as the brief +# description. If set to NO, the Javadoc-style will behave just like regular Qt- +# style comments (thus requiring an explicit @brief command for a brief +# description.) +# The default value is: NO. + +JAVADOC_AUTOBRIEF = NO + +# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first +# line (until the first dot) of a Qt-style comment as the brief description. If +# set to NO, the Qt-style will behave just like regular Qt-style comments (thus +# requiring an explicit \brief command for a brief description.) +# The default value is: NO. + +QT_AUTOBRIEF = NO + +# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a +# multi-line C++ special comment block (i.e. a block of //! or /// comments) as +# a brief description. This used to be the default behavior. The new default is +# to treat a multi-line C++ comment block as a detailed description. Set this +# tag to YES if you prefer the old behavior instead. +# +# Note that setting this tag to YES also means that rational rose comments are +# not recognized any more. +# The default value is: NO. + +MULTILINE_CPP_IS_BRIEF = NO + +# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the +# documentation from any documented member that it re-implements. +# The default value is: YES. + +INHERIT_DOCS = YES + +# If the SEPARATE_MEMBER_PAGES tag is set to YES then doxygen will produce a new +# page for each member. If set to NO, the documentation of a member will be part +# of the file/class/namespace that contains it. +# The default value is: NO. + +SEPARATE_MEMBER_PAGES = NO + +# The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen +# uses this value to replace tabs by spaces in code fragments. +# Minimum value: 1, maximum value: 16, default value: 4. + +TAB_SIZE = 4 + +# This tag can be used to specify a number of aliases that act as commands in +# the documentation. An alias has the form: +# name=value +# For example adding +# "sideeffect=@par Side Effects:\n" +# will allow you to put the command \sideeffect (or @sideeffect) in the +# documentation, which will result in a user-defined paragraph with heading +# "Side Effects:". You can put \n's in the value part of an alias to insert +# newlines. + +ALIASES = + +# This tag can be used to specify a number of word-keyword mappings (TCL only). +# A mapping has the form "name=value". For example adding "class=itcl::class" +# will allow you to use the command class in the itcl::class meaning. + +TCL_SUBST = + +# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources +# only. Doxygen will then generate output that is more tailored for C. For +# instance, some of the names that are used will be different. The list of all +# members will be omitted, etc. +# The default value is: NO. + +OPTIMIZE_OUTPUT_FOR_C = NO + +# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or +# Python sources only. Doxygen will then generate output that is more tailored +# for that language. For instance, namespaces will be presented as packages, +# qualified scopes will look different, etc. +# The default value is: NO. + +OPTIMIZE_OUTPUT_JAVA = NO + +# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran +# sources. Doxygen will then generate output that is tailored for Fortran. +# The default value is: NO. + +OPTIMIZE_FOR_FORTRAN = NO + +# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL +# sources. Doxygen will then generate output that is tailored for VHDL. +# The default value is: NO. + +OPTIMIZE_OUTPUT_VHDL = NO + +# Doxygen selects the parser to use depending on the extension of the files it +# parses. With this tag you can assign which parser to use for a given +# extension. Doxygen has a built-in mapping, but you can override or extend it +# using this tag. The format is ext=language, where ext is a file extension, and +# language is one of the parsers supported by doxygen: IDL, Java, Javascript, +# C#, C, C++, D, PHP, Objective-C, Python, Fortran (fixed format Fortran: +# FortranFixed, free formatted Fortran: FortranFree, unknown formatted Fortran: +# Fortran. In the later case the parser tries to guess whether the code is fixed +# or free formatted code, this is the default for Fortran type files), VHDL. For +# instance to make doxygen treat .inc files as Fortran files (default is PHP), +# and .f files as C (default is Fortran), use: inc=Fortran f=C. +# +# Note: For files without extension you can use no_extension as a placeholder. +# +# Note that for custom extensions you also need to set FILE_PATTERNS otherwise +# the files are not read by doxygen. + +EXTENSION_MAPPING = + +# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments +# according to the Markdown format, which allows for more readable +# documentation. See http://daringfireball.net/projects/markdown/ for details. +# The output of markdown processing is further processed by doxygen, so you can +# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in +# case of backward compatibilities issues. +# The default value is: YES. + +MARKDOWN_SUPPORT = YES + +# When enabled doxygen tries to link words that correspond to documented +# classes, or namespaces to their corresponding documentation. Such a link can +# be prevented in individual cases by putting a % sign in front of the word or +# globally by setting AUTOLINK_SUPPORT to NO. +# The default value is: YES. + +AUTOLINK_SUPPORT = YES + +# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want +# to include (a tag file for) the STL sources as input, then you should set this +# tag to YES in order to let doxygen match functions declarations and +# definitions whose arguments contain STL classes (e.g. func(std::string); +# versus func(std::string) {}). This also make the inheritance and collaboration +# diagrams that involve STL classes more complete and accurate. +# The default value is: NO. + +BUILTIN_STL_SUPPORT = YES + +# If you use Microsoft's C++/CLI language, you should set this option to YES to +# enable parsing support. +# The default value is: NO. + +CPP_CLI_SUPPORT = NO + +# Set the SIP_SUPPORT tag to YES if your project consists of sip (see: +# http://www.riverbankcomputing.co.uk/software/sip/intro) sources only. Doxygen +# will parse them like normal C++ but will assume all classes use public instead +# of private inheritance when no explicit protection keyword is present. +# The default value is: NO. + +SIP_SUPPORT = NO + +# For Microsoft's IDL there are propget and propput attributes to indicate +# getter and setter methods for a property. Setting this option to YES will make +# doxygen to replace the get and set methods by a property in the documentation. +# This will only work if the methods are indeed getting or setting a simple +# type. If this is not the case, or you want to show the methods anyway, you +# should set this option to NO. +# The default value is: YES. + +IDL_PROPERTY_SUPPORT = YES + +# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC +# tag is set to YES then doxygen will reuse the documentation of the first +# member in the group (if any) for the other members of the group. By default +# all members of a group must be documented explicitly. +# The default value is: NO. + +DISTRIBUTE_GROUP_DOC = NO + +# If one adds a struct or class to a group and this option is enabled, then also +# any nested class or struct is added to the same group. By default this option +# is disabled and one has to add nested compounds explicitly via \ingroup. +# The default value is: NO. + +GROUP_NESTED_COMPOUNDS = NO + +# Set the SUBGROUPING tag to YES to allow class member groups of the same type +# (for instance a group of public functions) to be put as a subgroup of that +# type (e.g. under the Public Functions section). Set it to NO to prevent +# subgrouping. Alternatively, this can be done per class using the +# \nosubgrouping command. +# The default value is: YES. + +SUBGROUPING = YES + +# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions +# are shown inside the group in which they are included (e.g. using \ingroup) +# instead of on a separate page (for HTML and Man pages) or section (for LaTeX +# and RTF). +# +# Note that this feature does not work in combination with +# SEPARATE_MEMBER_PAGES. +# The default value is: NO. + +INLINE_GROUPED_CLASSES = NO + +# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions +# with only public data fields or simple typedef fields will be shown inline in +# the documentation of the scope in which they are defined (i.e. file, +# namespace, or group documentation), provided this scope is documented. If set +# to NO, structs, classes, and unions are shown on a separate page (for HTML and +# Man pages) or section (for LaTeX and RTF). +# The default value is: NO. + +INLINE_SIMPLE_STRUCTS = NO + +# When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or +# enum is documented as struct, union, or enum with the name of the typedef. So +# typedef struct TypeS {} TypeT, will appear in the documentation as a struct +# with name TypeT. When disabled the typedef will appear as a member of a file, +# namespace, or class. And the struct will be named TypeS. This can typically be +# useful for C code in case the coding convention dictates that all compound +# types are typedef'ed and only the typedef is referenced, never the tag name. +# The default value is: NO. + +TYPEDEF_HIDES_STRUCT = NO + +# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This +# cache is used to resolve symbols given their name and scope. Since this can be +# an expensive process and often the same symbol appears multiple times in the +# code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small +# doxygen will become slower. If the cache is too large, memory is wasted. The +# cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range +# is 0..9, the default is 0, corresponding to a cache size of 2^16=65536 +# symbols. At the end of a run doxygen will report the cache usage and suggest +# the optimal cache size from a speed point of view. +# Minimum value: 0, maximum value: 9, default value: 0. + +LOOKUP_CACHE_SIZE = 0 + +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- + +# If the EXTRACT_ALL tag is set to YES, doxygen will assume all entities in +# documentation are documented, even if no documentation was available. Private +# class members and static file members will be hidden unless the +# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES. +# Note: This will also disable the warnings about undocumented members that are +# normally produced when WARNINGS is set to YES. +# The default value is: NO. + +EXTRACT_ALL = NO + +# If the EXTRACT_PRIVATE tag is set to YES, all private members of a class will +# be included in the documentation. +# The default value is: NO. + +EXTRACT_PRIVATE = NO + +# If the EXTRACT_PACKAGE tag is set to YES, all members with package or internal +# scope will be included in the documentation. +# The default value is: NO. + +EXTRACT_PACKAGE = NO + +# If the EXTRACT_STATIC tag is set to YES, all static members of a file will be +# included in the documentation. +# The default value is: NO. + +EXTRACT_STATIC = YES + +# If the EXTRACT_LOCAL_CLASSES tag is set to YES, classes (and structs) defined +# locally in source files will be included in the documentation. If set to NO, +# only classes defined in header files are included. Does not have any effect +# for Java sources. +# The default value is: YES. + +EXTRACT_LOCAL_CLASSES = YES + +# This flag is only useful for Objective-C code. If set to YES, local methods, +# which are defined in the implementation section but not in the interface are +# included in the documentation. If set to NO, only methods in the interface are +# included. +# The default value is: NO. + +EXTRACT_LOCAL_METHODS = NO + +# If this flag is set to YES, the members of anonymous namespaces will be +# extracted and appear in the documentation as a namespace called +# 'anonymous_namespace{file}', where file will be replaced with the base name of +# the file that contains the anonymous namespace. By default anonymous namespace +# are hidden. +# The default value is: NO. + +EXTRACT_ANON_NSPACES = NO + +# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all +# undocumented members inside documented classes or files. If set to NO these +# members will be included in the various overviews, but no documentation +# section is generated. This option has no effect if EXTRACT_ALL is enabled. +# The default value is: NO. + +HIDE_UNDOC_MEMBERS = YES + +# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all +# undocumented classes that are normally visible in the class hierarchy. If set +# to NO, these classes will be included in the various overviews. This option +# has no effect if EXTRACT_ALL is enabled. +# The default value is: NO. + +HIDE_UNDOC_CLASSES = YES + +# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend +# (class|struct|union) declarations. If set to NO, these declarations will be +# included in the documentation. +# The default value is: NO. + +HIDE_FRIEND_COMPOUNDS = YES + +# If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any +# documentation blocks found inside the body of a function. If set to NO, these +# blocks will be appended to the function's detailed documentation block. +# The default value is: NO. + +HIDE_IN_BODY_DOCS = NO + +# The INTERNAL_DOCS tag determines if documentation that is typed after a +# \internal command is included. If the tag is set to NO then the documentation +# will be excluded. Set it to YES to include the internal documentation. +# The default value is: NO. + +INTERNAL_DOCS = NO + +# If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file +# names in lower-case letters. If set to YES, upper-case letters are also +# allowed. This is useful if you have classes or files whose names only differ +# in case and if your file system supports case sensitive file names. Windows +# and Mac users are advised to set this option to NO. +# The default value is: system dependent. + +CASE_SENSE_NAMES = YES + +# If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with +# their full class and namespace scopes in the documentation. If set to YES, the +# scope will be hidden. +# The default value is: NO. + +HIDE_SCOPE_NAMES = YES + +# If the HIDE_COMPOUND_REFERENCE tag is set to NO (default) then doxygen will +# append additional text to a page's title, such as Class Reference. If set to +# YES the compound reference will be hidden. +# The default value is: NO. + +HIDE_COMPOUND_REFERENCE= NO + +# If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of +# the files that are included by a file in the documentation of that file. +# The default value is: YES. + +SHOW_INCLUDE_FILES = YES + +# If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each +# grouped member an include statement to the documentation, telling the reader +# which file to include in order to use the member. +# The default value is: NO. + +SHOW_GROUPED_MEMB_INC = NO + +# If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include +# files with double quotes in the documentation rather than with sharp brackets. +# The default value is: NO. + +FORCE_LOCAL_INCLUDES = NO + +# If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the +# documentation for inline members. +# The default value is: YES. + +INLINE_INFO = YES + +# If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the +# (detailed) documentation of file and class members alphabetically by member +# name. If set to NO, the members will appear in declaration order. +# The default value is: YES. + +SORT_MEMBER_DOCS = YES + +# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief +# descriptions of file, namespace and class members alphabetically by member +# name. If set to NO, the members will appear in declaration order. Note that +# this will also influence the order of the classes in the class list. +# The default value is: NO. + +SORT_BRIEF_DOCS = NO + +# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the +# (brief and detailed) documentation of class members so that constructors and +# destructors are listed first. If set to NO the constructors will appear in the +# respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS. +# Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief +# member documentation. +# Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting +# detailed member documentation. +# The default value is: NO. + +SORT_MEMBERS_CTORS_1ST = NO + +# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy +# of group names into alphabetical order. If set to NO the group names will +# appear in their defined order. +# The default value is: NO. + +SORT_GROUP_NAMES = NO + +# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by +# fully-qualified names, including namespaces. If set to NO, the class list will +# be sorted only by class name, not including the namespace part. +# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. +# Note: This option applies only to the class list, not to the alphabetical +# list. +# The default value is: NO. + +SORT_BY_SCOPE_NAME = NO + +# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper +# type resolution of all parameters of a function it will reject a match between +# the prototype and the implementation of a member function even if there is +# only one candidate or it is obvious which candidate to choose by doing a +# simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still +# accept a match between prototype and implementation in such cases. +# The default value is: NO. + +STRICT_PROTO_MATCHING = NO + +# The GENERATE_TODOLIST tag can be used to enable (YES) or disable (NO) the todo +# list. This list is created by putting \todo commands in the documentation. +# The default value is: YES. + +GENERATE_TODOLIST = YES + +# The GENERATE_TESTLIST tag can be used to enable (YES) or disable (NO) the test +# list. This list is created by putting \test commands in the documentation. +# The default value is: YES. + +GENERATE_TESTLIST = YES + +# The GENERATE_BUGLIST tag can be used to enable (YES) or disable (NO) the bug +# list. This list is created by putting \bug commands in the documentation. +# The default value is: YES. + +GENERATE_BUGLIST = YES + +# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or disable (NO) +# the deprecated list. This list is created by putting \deprecated commands in +# the documentation. +# The default value is: YES. + +GENERATE_DEPRECATEDLIST= YES + +# The ENABLED_SECTIONS tag can be used to enable conditional documentation +# sections, marked by \if ... \endif and \cond +# ... \endcond blocks. + +ENABLED_SECTIONS = + +# The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the +# initial value of a variable or macro / define can have for it to appear in the +# documentation. If the initializer consists of more lines than specified here +# it will be hidden. Use a value of 0 to hide initializers completely. The +# appearance of the value of individual variables and macros / defines can be +# controlled using \showinitializer or \hideinitializer command in the +# documentation regardless of this setting. +# Minimum value: 0, maximum value: 10000, default value: 30. + +MAX_INITIALIZER_LINES = 30 + +# Set the SHOW_USED_FILES tag to NO to disable the list of files generated at +# the bottom of the documentation of classes and structs. If set to YES, the +# list will mention the files that were used to generate the documentation. +# The default value is: YES. + +SHOW_USED_FILES = YES + +# Set the SHOW_FILES tag to NO to disable the generation of the Files page. This +# will remove the Files entry from the Quick Index and from the Folder Tree View +# (if specified). +# The default value is: YES. + +SHOW_FILES = YES + +# Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces +# page. This will remove the Namespaces entry from the Quick Index and from the +# Folder Tree View (if specified). +# The default value is: YES. + +SHOW_NAMESPACES = YES + +# The FILE_VERSION_FILTER tag can be used to specify a program or script that +# doxygen should invoke to get the current version for each file (typically from +# the version control system). Doxygen will invoke the program by executing (via +# popen()) the command command input-file, where command is the value of the +# FILE_VERSION_FILTER tag, and input-file is the name of an input file provided +# by doxygen. Whatever the program writes to standard output is used as the file +# version. For an example see the documentation. + +FILE_VERSION_FILTER = + +# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed +# by doxygen. The layout file controls the global structure of the generated +# output files in an output format independent way. To create the layout file +# that represents doxygen's defaults, run doxygen with the -l option. You can +# optionally specify a file name after the option, if omitted DoxygenLayout.xml +# will be used as the name of the layout file. +# +# Note that if you run doxygen from a directory containing a file called +# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE +# tag is left empty. + +LAYOUT_FILE = XreateDoxygenLayout.xml + +# The CITE_BIB_FILES tag can be used to specify one or more bib files containing +# the reference definitions. This must be a list of .bib files. The .bib +# extension is automatically appended if omitted. This requires the bibtex tool +# to be installed. See also http://en.wikipedia.org/wiki/BibTeX for more info. +# For LaTeX the style of the bibliography can be controlled using +# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the +# search path. See also \cite for info how to create references. + +CITE_BIB_FILES = + +#--------------------------------------------------------------------------- +# Configuration options related to warning and progress messages +#--------------------------------------------------------------------------- + +# The QUIET tag can be used to turn on/off the messages that are generated to +# standard output by doxygen. If QUIET is set to YES this implies that the +# messages are off. +# The default value is: NO. + +QUIET = NO + +# The WARNINGS tag can be used to turn on/off the warning messages that are +# generated to standard error (stderr) by doxygen. If WARNINGS is set to YES +# this implies that the warnings are on. +# +# Tip: Turn warnings on while writing the documentation. +# The default value is: YES. + +WARNINGS = YES + +# If the WARN_IF_UNDOCUMENTED tag is set to YES then doxygen will generate +# warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag +# will automatically be disabled. +# The default value is: YES. + +WARN_IF_UNDOCUMENTED = YES + +# If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for +# potential errors in the documentation, such as not documenting some parameters +# in a documented function, or documenting parameters that don't exist or using +# markup commands wrongly. +# The default value is: YES. + +WARN_IF_DOC_ERROR = YES + +# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that +# are documented, but have no documentation for their parameters or return +# value. If set to NO, doxygen will only warn about wrong or incomplete +# parameter documentation, but not about the absence of documentation. +# The default value is: NO. + +WARN_NO_PARAMDOC = NO + +# If the WARN_AS_ERROR tag is set to YES then doxygen will immediately stop when +# a warning is encountered. +# The default value is: NO. + +WARN_AS_ERROR = NO + +# The WARN_FORMAT tag determines the format of the warning messages that doxygen +# can produce. The string should contain the $file, $line, and $text tags, which +# will be replaced by the file and line number from which the warning originated +# and the warning text. Optionally the format may contain $version, which will +# be replaced by the version of the file (if it could be obtained via +# FILE_VERSION_FILTER) +# The default value is: $file:$line: $text. + +WARN_FORMAT = "$file:$line: $text" + +# The WARN_LOGFILE tag can be used to specify a file to which warning and error +# messages should be written. If left blank the output is written to standard +# error (stderr). + +WARN_LOGFILE = + +#--------------------------------------------------------------------------- +# Configuration options related to the input files +#--------------------------------------------------------------------------- + +# The INPUT tag is used to specify the files and/or directories that contain +# documented source files. You may enter file names like myfile.cpp or +# directories like /usr/src/myproject. Separate the files or directories with +# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING +# Note: If this tag is empty the current directory is searched. + +INPUT = ../cpp/src ./ + +# This tag can be used to specify the character encoding of the source files +# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses +# libiconv (or the iconv built into libc) for the transcoding. See the libiconv +# documentation (see: http://www.gnu.org/software/libiconv) for the list of +# possible encodings. +# The default value is: UTF-8. + +INPUT_ENCODING = UTF-8 + +# If the value of the INPUT tag contains directories, you can use the +# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and +# *.h) to filter out the source-files in the directories. +# +# Note that for custom extensions or not directly supported extensions you also +# need to set EXTENSION_MAPPING for the extension otherwise the files are not +# read by doxygen. +# +# If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cpp, +# *.c++, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, +# *.hh, *.hxx, *.hpp, *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc, +# *.m, *.markdown, *.md, *.mm, *.dox, *.py, *.pyw, *.f90, *.f, *.for, *.tcl, +# *.vhd, *.vhdl, *.ucf, *.qsf, *.as and *.js. + +FILE_PATTERNS = *.cpp *.h *.dox + +# The RECURSIVE tag can be used to specify whether or not subdirectories should +# be searched for input files as well. +# The default value is: NO. + +RECURSIVE = YES + +# The EXCLUDE tag can be used to specify files and/or directories that should be +# excluded from the INPUT source files. This way you can easily exclude a +# subdirectory from a directory tree whose root is specified with the INPUT tag. +# +# Note that relative paths are relative to the directory from which doxygen is +# run. + +EXCLUDE = + +# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or +# directories that are symbolic links (a Unix file system feature) are excluded +# from the input. +# The default value is: NO. + +EXCLUDE_SYMLINKS = NO + +# If the value of the INPUT tag contains directories, you can use the +# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude +# certain files from those directories. +# +# Note that the wildcards are matched against the file with absolute path, so to +# exclude all test directories for example use the pattern */test/* + +EXCLUDE_PATTERNS = + +# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names +# (namespaces, classes, functions, etc.) that should be excluded from the +# output. The symbol name can be a fully qualified name, a word, or if the +# wildcard * is used, a substring. Examples: ANamespace, AClass, +# AClass::ANamespace, ANamespace::*Test +# +# Note that the wildcards are matched against the file with absolute path, so to +# exclude all test directories use the pattern */test/* + +EXCLUDE_SYMBOLS = + +# The EXAMPLE_PATH tag can be used to specify one or more files or directories +# that contain example code fragments that are included (see the \include +# command). + +EXAMPLE_PATH = + +# If the value of the EXAMPLE_PATH tag contains directories, you can use the +# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and +# *.h) to filter out the source-files in the directories. If left blank all +# files are included. + +EXAMPLE_PATTERNS = + +# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be +# searched for input files to be used with the \include or \dontinclude commands +# irrespective of the value of the RECURSIVE tag. +# The default value is: NO. + +EXAMPLE_RECURSIVE = NO + +# The IMAGE_PATH tag can be used to specify one or more files or directories +# that contain images that are to be included in the documentation (see the +# \image command). + +IMAGE_PATH = + +# The INPUT_FILTER tag can be used to specify a program that doxygen should +# invoke to filter for each input file. Doxygen will invoke the filter program +# by executing (via popen()) the command: +# +# +# +# where is the value of the INPUT_FILTER tag, and is the +# name of an input file. Doxygen will then use the output that the filter +# program writes to standard output. If FILTER_PATTERNS is specified, this tag +# will be ignored. +# +# Note that the filter must not add or remove lines; it is applied before the +# code is scanned, but not when the output code is generated. If lines are added +# or removed, the anchors will not be placed correctly. +# +# Note that for custom extensions or not directly supported extensions you also +# need to set EXTENSION_MAPPING for the extension otherwise the files are not +# properly processed by doxygen. + +INPUT_FILTER = + +# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern +# basis. Doxygen will compare the file name with each pattern and apply the +# filter if there is a match. The filters are a list of the form: pattern=filter +# (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how +# filters are used. If the FILTER_PATTERNS tag is empty or if none of the +# patterns match the file name, INPUT_FILTER is applied. +# +# Note that for custom extensions or not directly supported extensions you also +# need to set EXTENSION_MAPPING for the extension otherwise the files are not +# properly processed by doxygen. + +FILTER_PATTERNS = + +# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using +# INPUT_FILTER) will also be used to filter the input files that are used for +# producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES). +# The default value is: NO. + +FILTER_SOURCE_FILES = NO + +# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file +# pattern. A pattern will override the setting for FILTER_PATTERN (if any) and +# it is also possible to disable source filtering for a specific pattern using +# *.ext= (so without naming a filter). +# This tag requires that the tag FILTER_SOURCE_FILES is set to YES. + +FILTER_SOURCE_PATTERNS = + +# If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that +# is part of the input, its contents will be placed on the main page +# (index.html). This can be useful if you have a project on for instance GitHub +# and want to reuse the introduction page also for the doxygen output. + +USE_MDFILE_AS_MAINPAGE = + +#--------------------------------------------------------------------------- +# Configuration options related to source browsing +#--------------------------------------------------------------------------- + +# If the SOURCE_BROWSER tag is set to YES then a list of source files will be +# generated. Documented entities will be cross-referenced with these sources. +# +# Note: To get rid of all source code in the generated output, make sure that +# also VERBATIM_HEADERS is set to NO. +# The default value is: NO. + +SOURCE_BROWSER = NO + +# Setting the INLINE_SOURCES tag to YES will include the body of functions, +# classes and enums directly into the documentation. +# The default value is: NO. + +INLINE_SOURCES = NO + +# Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any +# special comment blocks from generated source code fragments. Normal C, C++ and +# Fortran comments will always remain visible. +# The default value is: YES. + +STRIP_CODE_COMMENTS = YES + +# If the REFERENCED_BY_RELATION tag is set to YES then for each documented +# function all documented functions referencing it will be listed. +# The default value is: NO. + +REFERENCED_BY_RELATION = NO + +# If the REFERENCES_RELATION tag is set to YES then for each documented function +# all documented entities called/used by that function will be listed. +# The default value is: NO. + +REFERENCES_RELATION = NO + +# If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set +# to YES then the hyperlinks from functions in REFERENCES_RELATION and +# REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will +# link to the documentation. +# The default value is: YES. + +REFERENCES_LINK_SOURCE = YES + +# If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the +# source code will show a tooltip with additional information such as prototype, +# brief description and links to the definition and documentation. Since this +# will make the HTML file larger and loading of large files a bit slower, you +# can opt to disable this feature. +# The default value is: YES. +# This tag requires that the tag SOURCE_BROWSER is set to YES. + +SOURCE_TOOLTIPS = YES + +# If the USE_HTAGS tag is set to YES then the references to source code will +# point to the HTML generated by the htags(1) tool instead of doxygen built-in +# source browser. The htags tool is part of GNU's global source tagging system +# (see http://www.gnu.org/software/global/global.html). You will need version +# 4.8.6 or higher. +# +# To use it do the following: +# - Install the latest version of global +# - Enable SOURCE_BROWSER and USE_HTAGS in the config file +# - Make sure the INPUT points to the root of the source tree +# - Run doxygen as normal +# +# Doxygen will invoke htags (and that will in turn invoke gtags), so these +# tools must be available from the command line (i.e. in the search path). +# +# The result: instead of the source browser generated by doxygen, the links to +# source code will now point to the output of htags. +# The default value is: NO. +# This tag requires that the tag SOURCE_BROWSER is set to YES. + +USE_HTAGS = NO + +# If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a +# verbatim copy of the header file for each class for which an include is +# specified. Set to NO to disable this. +# See also: Section \class. +# The default value is: YES. + +VERBATIM_HEADERS = NO + +#--------------------------------------------------------------------------- +# Configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- + +# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all +# compounds will be generated. Enable this if the project contains a lot of +# classes, structs, unions or interfaces. +# The default value is: YES. + +ALPHABETICAL_INDEX = YES + +# The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in +# which the alphabetical index list will be split. +# Minimum value: 1, maximum value: 20, default value: 5. +# This tag requires that the tag ALPHABETICAL_INDEX is set to YES. + +COLS_IN_ALPHA_INDEX = 5 + +# In case all classes in a project start with a common prefix, all classes will +# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag +# can be used to specify a prefix (or a list of prefixes) that should be ignored +# while generating the index headers. +# This tag requires that the tag ALPHABETICAL_INDEX is set to YES. + +IGNORE_PREFIX = + +#--------------------------------------------------------------------------- +# Configuration options related to the HTML output +#--------------------------------------------------------------------------- + +# If the GENERATE_HTML tag is set to YES, doxygen will generate HTML output +# The default value is: YES. + +GENERATE_HTML = YES + +# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a +# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of +# it. +# The default directory is: html. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_OUTPUT = html + +# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each +# generated HTML page (for example: .htm, .php, .asp). +# The default value is: .html. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_FILE_EXTENSION = .html + +# The HTML_HEADER tag can be used to specify a user-defined HTML header file for +# each generated HTML page. If the tag is left blank doxygen will generate a +# standard header. +# +# To get valid HTML the header file that includes any scripts and style sheets +# that doxygen needs, which is dependent on the configuration options used (e.g. +# the setting GENERATE_TREEVIEW). It is highly recommended to start with a +# default header using +# doxygen -w html new_header.html new_footer.html new_stylesheet.css +# YourConfigFile +# and then modify the file new_header.html. See also section "Doxygen usage" +# for information on how to generate the default header that doxygen normally +# uses. +# Note: The header is subject to change so you typically have to regenerate the +# default header when upgrading to a newer version of doxygen. For a description +# of the possible markers and block names see the documentation. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_HEADER = + +# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each +# generated HTML page. If the tag is left blank doxygen will generate a standard +# footer. See HTML_HEADER for more information on how to generate a default +# footer and what special commands can be used inside the footer. See also +# section "Doxygen usage" for information on how to generate the default footer +# that doxygen normally uses. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_FOOTER = + +# The HTML_STYLESHEET tag can be used to specify a user-defined cascading style +# sheet that is used by each HTML page. It can be used to fine-tune the look of +# the HTML output. If left blank doxygen will generate a default style sheet. +# See also section "Doxygen usage" for information on how to generate the style +# sheet that doxygen normally uses. +# Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as +# it is more robust and this tag (HTML_STYLESHEET) will in the future become +# obsolete. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_STYLESHEET = + +# The HTML_EXTRA_STYLESHEET tag can be used to specify additional user-defined +# cascading style sheets that are included after the standard style sheets +# created by doxygen. Using this option one can overrule certain style aspects. +# This is preferred over using HTML_STYLESHEET since it does not replace the +# standard style sheet and is therefore more robust against future updates. +# Doxygen will copy the style sheet files to the output directory. +# Note: The order of the extra style sheet files is of importance (e.g. the last +# style sheet in the list overrules the setting of the previous ones in the +# list). For an example see the documentation. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_EXTRA_STYLESHEET = + +# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or +# other source files which should be copied to the HTML output directory. Note +# that these files will be copied to the base HTML output directory. Use the +# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these +# files. In the HTML_STYLESHEET file, use the file name only. Also note that the +# files will be copied as-is; there are no commands or markers available. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_EXTRA_FILES = + +# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen +# will adjust the colors in the style sheet and background images according to +# this color. Hue is specified as an angle on a colorwheel, see +# http://en.wikipedia.org/wiki/Hue for more information. For instance the value +# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300 +# purple, and 360 is red again. +# Minimum value: 0, maximum value: 359, default value: 220. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE_HUE = 220 + +# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors +# in the HTML output. For a value of 0 the output will use grayscales only. A +# value of 255 will produce the most vivid colors. +# Minimum value: 0, maximum value: 255, default value: 100. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE_SAT = 100 + +# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the +# luminance component of the colors in the HTML output. Values below 100 +# gradually make the output lighter, whereas values above 100 make the output +# darker. The value divided by 100 is the actual gamma applied, so 80 represents +# a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not +# change the gamma. +# Minimum value: 40, maximum value: 240, default value: 80. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE_GAMMA = 80 + +# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML +# page will contain the date and time when the page was generated. Setting this +# to YES can help to show when doxygen was last run and thus if the +# documentation is up to date. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_TIMESTAMP = NO + +# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML +# documentation will contain sections that can be hidden and shown after the +# page has loaded. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_DYNAMIC_SECTIONS = NO + +# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries +# shown in the various tree structured indices initially; the user can expand +# and collapse entries dynamically later on. Doxygen will expand the tree to +# such a level that at most the specified number of entries are visible (unless +# a fully collapsed tree already exceeds this amount). So setting the number of +# entries 1 will produce a full collapsed tree by default. 0 is a special value +# representing an infinite number of entries and will result in a full expanded +# tree by default. +# Minimum value: 0, maximum value: 9999, default value: 100. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_INDEX_NUM_ENTRIES = 100 + +# If the GENERATE_DOCSET tag is set to YES, additional index files will be +# generated that can be used as input for Apple's Xcode 3 integrated development +# environment (see: http://developer.apple.com/tools/xcode/), introduced with +# OSX 10.5 (Leopard). To create a documentation set, doxygen will generate a +# Makefile in the HTML output directory. Running make will produce the docset in +# that directory and running make install will install the docset in +# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at +# startup. See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html +# for more information. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_DOCSET = NO + +# This tag determines the name of the docset feed. A documentation feed provides +# an umbrella under which multiple documentation sets from a single provider +# (such as a company or product suite) can be grouped. +# The default value is: Doxygen generated docs. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_FEEDNAME = "Doxygen generated docs" + +# This tag specifies a string that should uniquely identify the documentation +# set bundle. This should be a reverse domain-name style string, e.g. +# com.mycompany.MyDocSet. Doxygen will append .docset to the name. +# The default value is: org.doxygen.Project. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_BUNDLE_ID = org.doxygen.Project + +# The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify +# the documentation publisher. This should be a reverse domain-name style +# string, e.g. com.mycompany.MyDocSet.documentation. +# The default value is: org.doxygen.Publisher. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_PUBLISHER_ID = org.doxygen.Publisher + +# The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher. +# The default value is: Publisher. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_PUBLISHER_NAME = Publisher + +# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three +# additional HTML index files: index.hhp, index.hhc, and index.hhk. The +# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop +# (see: http://www.microsoft.com/en-us/download/details.aspx?id=21138) on +# Windows. +# +# The HTML Help Workshop contains a compiler that can convert all HTML output +# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML +# files are now used as the Windows 98 help format, and will replace the old +# Windows help format (.hlp) on all Windows platforms in the future. Compressed +# HTML files also contain an index, a table of contents, and you can search for +# words in the documentation. The HTML workshop also contains a viewer for +# compressed HTML files. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_HTMLHELP = NO + +# The CHM_FILE tag can be used to specify the file name of the resulting .chm +# file. You can add a path in front of the file if the result should not be +# written to the html output directory. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +CHM_FILE = + +# The HHC_LOCATION tag can be used to specify the location (absolute path +# including file name) of the HTML help compiler (hhc.exe). If non-empty, +# doxygen will try to run the HTML help compiler on the generated index.hhp. +# The file has to be specified with full path. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +HHC_LOCATION = + +# The GENERATE_CHI flag controls if a separate .chi index file is generated +# (YES) or that it should be included in the master .chm file (NO). +# The default value is: NO. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +GENERATE_CHI = NO + +# The CHM_INDEX_ENCODING is used to encode HtmlHelp index (hhk), content (hhc) +# and project file content. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +CHM_INDEX_ENCODING = + +# The BINARY_TOC flag controls whether a binary table of contents is generated +# (YES) or a normal table of contents (NO) in the .chm file. Furthermore it +# enables the Previous and Next buttons. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +BINARY_TOC = NO + +# The TOC_EXPAND flag can be set to YES to add extra items for group members to +# the table of contents of the HTML help documentation and to the tree view. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +TOC_EXPAND = NO + +# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and +# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that +# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help +# (.qch) of the generated HTML documentation. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_QHP = NO + +# If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify +# the file name of the resulting .qch file. The path specified is relative to +# the HTML output folder. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QCH_FILE = + +# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help +# Project output. For more information please see Qt Help Project / Namespace +# (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#namespace). +# The default value is: org.doxygen.Project. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_NAMESPACE = org.doxygen.Project + +# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt +# Help Project output. For more information please see Qt Help Project / Virtual +# Folders (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#virtual- +# folders). +# The default value is: doc. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_VIRTUAL_FOLDER = doc + +# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom +# filter to add. For more information please see Qt Help Project / Custom +# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom- +# filters). +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_CUST_FILTER_NAME = + +# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the +# custom filter to add. For more information please see Qt Help Project / Custom +# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom- +# filters). +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_CUST_FILTER_ATTRS = + +# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this +# project's filter section matches. Qt Help Project / Filter Attributes (see: +# http://qt-project.org/doc/qt-4.8/qthelpproject.html#filter-attributes). +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_SECT_FILTER_ATTRS = + +# The QHG_LOCATION tag can be used to specify the location of Qt's +# qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the +# generated .qhp file. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHG_LOCATION = + +# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be +# generated, together with the HTML files, they form an Eclipse help plugin. To +# install this plugin and make it available under the help contents menu in +# Eclipse, the contents of the directory containing the HTML and XML files needs +# to be copied into the plugins directory of eclipse. The name of the directory +# within the plugins directory should be the same as the ECLIPSE_DOC_ID value. +# After copying Eclipse needs to be restarted before the help appears. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_ECLIPSEHELP = NO + +# A unique identifier for the Eclipse help plugin. When installing the plugin +# the directory name containing the HTML and XML files should also have this +# name. Each documentation set should have its own identifier. +# The default value is: org.doxygen.Project. +# This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES. + +ECLIPSE_DOC_ID = org.doxygen.Project + +# If you want full control over the layout of the generated HTML pages it might +# be necessary to disable the index and replace it with your own. The +# DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top +# of each HTML page. A value of NO enables the index and the value YES disables +# it. Since the tabs in the index contain the same information as the navigation +# tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +DISABLE_INDEX = NO + +# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index +# structure should be generated to display hierarchical information. If the tag +# value is set to YES, a side panel will be generated containing a tree-like +# index structure (just like the one that is generated for HTML Help). For this +# to work a browser that supports JavaScript, DHTML, CSS and frames is required +# (i.e. any modern browser). Windows users are probably better off using the +# HTML help feature. Via custom style sheets (see HTML_EXTRA_STYLESHEET) one can +# further fine-tune the look of the index. As an example, the default style +# sheet generated by doxygen has an example that shows how to put an image at +# the root of the tree instead of the PROJECT_NAME. Since the tree basically has +# the same information as the tab index, you could consider setting +# DISABLE_INDEX to YES when enabling this option. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_TREEVIEW = NO + +# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that +# doxygen will group on one line in the generated HTML documentation. +# +# Note that a value of 0 will completely suppress the enum values from appearing +# in the overview section. +# Minimum value: 0, maximum value: 20, default value: 4. +# This tag requires that the tag GENERATE_HTML is set to YES. + +ENUM_VALUES_PER_LINE = 4 + +# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used +# to set the initial width (in pixels) of the frame in which the tree is shown. +# Minimum value: 0, maximum value: 1500, default value: 250. +# This tag requires that the tag GENERATE_HTML is set to YES. + +TREEVIEW_WIDTH = 250 + +# If the EXT_LINKS_IN_WINDOW option is set to YES, doxygen will open links to +# external symbols imported via tag files in a separate window. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +EXT_LINKS_IN_WINDOW = NO + +# Use this tag to change the font size of LaTeX formulas included as images in +# the HTML documentation. When you change the font size after a successful +# doxygen run you need to manually remove any form_*.png images from the HTML +# output directory to force them to be regenerated. +# Minimum value: 8, maximum value: 50, default value: 10. +# This tag requires that the tag GENERATE_HTML is set to YES. + +FORMULA_FONTSIZE = 10 + +# Use the FORMULA_TRANPARENT tag to determine whether or not the images +# generated for formulas are transparent PNGs. Transparent PNGs are not +# supported properly for IE 6.0, but are supported on all modern browsers. +# +# Note that when changing this option you need to delete any form_*.png files in +# the HTML output directory before the changes have effect. +# The default value is: YES. +# This tag requires that the tag GENERATE_HTML is set to YES. + +FORMULA_TRANSPARENT = YES + +# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see +# http://www.mathjax.org) which uses client side Javascript for the rendering +# instead of using pre-rendered bitmaps. Use this if you do not have LaTeX +# installed or if you want to formulas look prettier in the HTML output. When +# enabled you may also need to install MathJax separately and configure the path +# to it using the MATHJAX_RELPATH option. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +USE_MATHJAX = NO + +# When MathJax is enabled you can set the default output format to be used for +# the MathJax output. See the MathJax site (see: +# http://docs.mathjax.org/en/latest/output.html) for more details. +# Possible values are: HTML-CSS (which is slower, but has the best +# compatibility), NativeMML (i.e. MathML) and SVG. +# The default value is: HTML-CSS. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_FORMAT = HTML-CSS + +# When MathJax is enabled you need to specify the location relative to the HTML +# output directory using the MATHJAX_RELPATH option. The destination directory +# should contain the MathJax.js script. For instance, if the mathjax directory +# is located at the same level as the HTML output directory, then +# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax +# Content Delivery Network so you can quickly see the result without installing +# MathJax. However, it is strongly recommended to install a local copy of +# MathJax from http://www.mathjax.org before deployment. +# The default value is: http://cdn.mathjax.org/mathjax/latest. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest + +# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax +# extension names that should be enabled during MathJax rendering. For example +# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_EXTENSIONS = + +# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces +# of code that will be used on startup of the MathJax code. See the MathJax site +# (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an +# example see the documentation. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_CODEFILE = + +# When the SEARCHENGINE tag is enabled doxygen will generate a search box for +# the HTML output. The underlying search engine uses javascript and DHTML and +# should work on any modern browser. Note that when using HTML help +# (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET) +# there is already a search function so this one should typically be disabled. +# For large projects the javascript based search engine can be slow, then +# enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to +# search using the keyboard; to jump to the search box use + S +# (what the is depends on the OS and browser, but it is typically +# , /