diff --git a/.gitignore b/.gitignore index b3fe7b7..f27ef5d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,68 +1,72 @@ # 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 cpp/CMakeLists.txt.user* hs/* project/* nb*.xml .* target/* -/tools/phabricator/xreate-frontend/nbproject/private/ \ No newline at end of file +/tools/phabricator/xreate-frontend/nbproject/private/ +documentation/trash4/ +CMakeFiles/ +gen-cpp/ +gen-php diff --git a/coco/Taste-example.ATG b/coco/Taste-example.ATG deleted file mode 100644 index 1ada837..0000000 --- a/coco/Taste-example.ATG +++ /dev/null @@ -1,147 +0,0 @@ -COMPILER Taste - -Proc curProc; // current program unit (procedure or main program) - -CHARACTERS - letter = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz". - digit = "0123456789". - cr = '\r'. - lf = '\n'. - tab = '\t'. - -TOKENS - ident = letter {letter | digit}. - number = digit {digit}. - -COMMENTS FROM "/*" TO "*/" NESTED -COMMENTS FROM "//" TO lf - -IGNORE cr + lf + tab - - - -PRODUCTIONS - -/*=================== Program and declarations ============================*/ - -Taste (. String name; .) -= "program" - Ident (. curProc = new Proc(name, null, this); .) - "{" - { VarDecl | ProcDecl } - "}" (. for (Obj obj: curProc.locals) { - if (obj instanceof Proc) ((Proc)obj).dump(); - } .). -/*------------------------------------------------------------------------*/ -VarDecl (. String name; Type type; .) -= Typ - Ident (. curProc.add(new Var(name, type)); .) - { ',' Ident (. curProc.add(new Var(name, type)); .) - } ';'. -/*------------------------------------------------------------------------*/ -Typ -= (. type = Type.INT; .) - ( "int" - | "bool" (. type = Type.BOOL; .) - ). -/*------------------------------------------------------------------------*/ -ProcDecl (. String name; .) -= "void" - Ident (. Proc oldProc = curProc; - curProc = new Proc(name, oldProc, this); - oldProc.add(curProc); .) - '(' ')' - Block (. curProc = oldProc; .). - - -/*============================= Statements ===============================*/ - -Block (. Stat s; .) -= '{' (. b = new Block(); .) - { Stat (. b.add(s); .) - | VarDecl - } - '}' - . -/*------------------------------------------------------------------------*/ -Stat (. String name; Expr e; Stat s2; Block b; .) -= (. s = null; .) -( Ident (. Obj obj = curProc.find(name); .) - ( '=' - Expr ';' (. s = new Assignment(obj, e); .) - | '(' ')' ';' (. s = new Call(obj); .) - ) - -| "if" - '(' Expr ')' - Stat (. s = new If(e, s); .) - [ "else" Stat (. s = new IfElse(s, s2); .) - ] - -| "while" - '(' Expr ')' - Stat (. s = new While(e, s); .) - -| "read" - Ident ';' (. s = new Read(curProc.find(name)); .) - -| "write" - Expr ';' (. s = new Write(e); .) - -| Block (. s = b; .) -). - - - -/*============================ Expressions ===============================*/ - -Expr (. Operator op; Expr e2; .) -= SimExpr - [ RelOp - SimExpr (. e = new BinExpr(e, op, e2); .) - ]. -/*------------------------------------------------------------------------*/ -SimExpr (. Operator op; Expr e2; .) -= Term - { AddOp - Term (. e = new BinExpr(e, op, e2); .) - }. -/*------------------------------------------------------------------------*/ -Term (. Operator op; Expr e2; .) -= Factor - { MulOp - Factor (. e = new BinExpr(e, op, e2); .) - }. -/*------------------------------------------------------------------------*/ -Factor (. String name; .) -= (. e = null; .) - ( Ident (. e = new Ident(curProc.find(name)); .) - | number (. e = new IntCon(Integer.parseInt(t.val)); .) - | '-' Factor (. e = new UnaryExpr(Operator.SUB, e); .) - | "true" (. e = new BoolCon(true); .) - | "false" (. e = new BoolCon(false); .) - ). -/*------------------------------------------------------------------------*/ -Ident -= ident (. name = t.val; .). -/*------------------------------------------------------------------------*/ -AddOp -= (. op = Operator.ADD; .) - ( '+' - | '-' (. op = Operator.SUB; .) - ). -/*------------------------------------------------------------------------*/ -MulOp -= (. op = Operator.MUL; .) - ( '*' - | '/' (. op = Operator.DIV; .) - ). -/*------------------------------------------------------------------------*/ -RelOp -= (. op = Operator.EQU; .) - ( "==" - | '<' (. op = Operator.LSS; .) - | '>' (. op = Operator.GTR; .) - ). - -END Taste. diff --git a/coco/Taste-example.TAS b/coco/Taste-example.TAS deleted file mode 100644 index ff122d6..0000000 --- a/coco/Taste-example.TAS +++ /dev/null @@ -1,31 +0,0 @@ - -// This is a test program which can be compiled by the Taste-compiler. -// It reads a sequence of numbers and computes the sum of all integers -// up to these numbers. - -program Test { - int i; - - void Foo() { - int a, b, max; - read a; read b; - if (a > b) max = a; else max = b; - write max; - } - - void SumUp() { - int sum; - sum = 0; - while (i > 0) { sum = sum + i; i = i - 1; } - write sum; - } - - void Main() { - read i; - while (i > 0) { - SumUp(); - read i; - } - } -} - diff --git a/coco/gen-grammar b/coco/gen-grammar index 814c770..66a5acd 100755 --- a/coco/gen-grammar +++ b/coco/gen-grammar @@ -1 +1,4 @@ -cococpp -frames ./generator-frames ./xreate.ATG +COCO_PATH=/opt/coco-cpp/ + +echo "Run coco generator: " +$COCO_PATH/Coco ./xreate.ATG -frames $COCO_PATH diff --git a/coco/xreate.ATG b/coco/xreate.ATG index 242d665..afc8fda 100644 --- a/coco/xreate.ATG +++ b/coco/xreate.ATG @@ -1,518 +1,549 @@ //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 varname; TypeAnnotation typIn; TypeAnnotation typOut; bool flagIsPrefunct = false; .) +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 Type (. f->addArg(std::move(varname), move(typIn)); .) -{',' Ident tagcolon Type (. f->addArg(std::move(varname), move(typIn));.) +['(' 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->__body.bindType(move(typOut));.) +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" | "int" | "num" | "float" | "bool") (. typ = Atom(t->val); .) - . + ("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; TypeAnnotation typ;.) -Ident assign ExprTyped - (. f->addDeclaration(move(vname), move(typ), move(e)); .) +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(move(tag)); .) -{';' MetaSimpExpr (. scope->tags.push_back(move(tag)); .) +MetaSimpExpr (. scope->tags.push_back(tag); .) +{';' MetaSimpExpr (. scope->tags.push_back(tag); .) }. //TODO forbid multiple body declaration (ExprTyped) -BDecl = (. Expression body; TypeAnnotation typ; pushContextScope(scope); .) +BDecl = (. Expression body; pushContextScope(scope); .) '{' { (RuleContextDecl | ContextDecl '.' | IF(checkAssignment()) VDecl '.' - | ExprTyped (. scope->setBody(body); popContextScope();.) + | ExprTyped (. scope->setBody(body); popContextScope();.) )} '}'. -IfDecl = (. Expression cond; ManagedScpPtr blockTrue = root.add(new xreate::CodeScope(context.scope)); ManagedScpPtr blockFalse = root.add(new xreate::CodeScope(context.scope)); TypeAnnotation typIf; .) -"if" '(' Expr ')' tagcolon Type BDecl<&*blockTrue> "else" BDecl<&*blockFalse> -(. e = Expression(Operator::IF, {cond}); e.addBlock(blockTrue); e.addBlock(blockFalse); e.bindType(move(typIf)); .) +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; TypeAnnotation typEl, typAcc; +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 tagcolon Type ')' tagcolon Type BDecl<&*block> - (. e = Expression(Operator::MAP, {eIn}); + ("map" '(' Expr implic Ident (. e = Expression(Operator::MAP, {eIn}); .) + tagcolon ExprAnnotations ')' tagcolon ExprAnnotations BDecl<&*block> + (. e.addBindings({Atom(varEl)}); - block->addArg(Atom(varEl), move(typEl)); - e.addBlock(block); .) - |"fold" '(' Expr implic Ident tagcolon Type ['|' Expr ] ',' Expr implic Ident')' tagcolon Type BDecl<&*block> - (. e = Expression(Operator::FOLD, {eIn, eAcc}); - e.addBindings({Atom(varEl), Atom(varAcc)}); - block->addArg(Atom(varEl), move(typEl)); - block->addArg(Atom(varAcc), move(typOut)); - e.addBlock(block); - .) - + 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 Type (. eSwitch.operands.push_back(eCondition); eSwitch.type = typ; .) + ( "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 = (. TypeAnnotation argtyp; Expression condition; .) +CaseParam = (. Expression condition; .) ( IF(checkAssignment()) VDecl - | ExprTyped (. guard.addArg(move(condition)); .) + | ExprTyped (. guard.addArg(move(condition)); .) ). SequenceDecl = "sequence" ListLiteral (. sequence.setOp(Operator::SEQUENCE); .). /*============================ INTERFACES ===============================*/ Imprt<> = "import" "raw" lparen string (. root.__rawImports.push_back(Atom(t->val).get()); .) rparen . InterfaceData<> = "interface" '(' ( "dfa" ')' InterfaceDFA | "extern-c" ')' InterfaceExternC | "cfa" ')' InterfaceCFA | "adhoc" ')' InterfaceAdhoc ). InterfaceAdhoc<> = '{' [ PrefunctionSchemeDecl ] '}'. PrefunctionSchemeDecl<> = (. TypeAnnotation typReturn; std::wstring prefName; Expression exprCases; .) pre function Ident tagcolon Type '{' SwitchDecl '}' (. Expression prefData(Operator::CALL, {Atom(prefName), exprCases}); prefData.type = typReturn; root.addInterfaceData(Adhoc, move(prefData)); .). InterfaceExternC<> = (.xreate::ExternData data; .) '{' {IncludeExternDecl | LibExternDecl } '}' (. root.addExternData(move(data)); .) . LibExternDecl = (. std::wstring pkgname, libname; .) Ident assign "library" tagcolon "pkgconfig" '(' string (. pkgname = t->val; .) ')' '.' (. data.addLibrary(Atom(libname), Atom(pkgname)); .) . IncludeExternDecl = (. Expression inc; .) "include" StructLiteral '.' (. data.addIncludeDecl(move(inc)); .) . InterfaceDFA<> = '{' { InstructDecl } '}' . InstructDecl = (.Operator op; Expression tag; Expression scheme; std::vector& tags = scheme.operands; tags.push_back(Expression()); /* return value */ .) "operator" InstructAlias tagcolon '(' (.scheme.setOp(op); .) [ MetaSimpExpr (. tags.push_back(tag); .) { ',' MetaSimpExpr (. tags.push_back(tag); .) } ] ')' [ implic MetaSimpExpr (. tags[0] = tag; .) ] (. root.addDFAData(move(scheme)); .) '.'. InstructAlias = ( "map" (. op = Operator::MAP; .) | "list_range" (. op = Operator::LIST_RANGE; .) | "list" (. op = Operator::LIST; .) | "fold" (. op = Operator::FOLD; .) | "index" (. op = Operator::INDEX; .) ). InterfaceCFA<> = '{' { InstructCFADecl } '}' . InstructCFADecl<> = (.Operator op; Expression tag; Expression scheme; std::vector& tags = scheme.operands; .) "operator" InstructAlias tagcolon (. scheme.setOp(op); .) [ MetaSimpExpr (. tags.push_back(tag); .) { ',' MetaSimpExpr (. tags.push_back(tag); .) } ] '.' (. root.addInterfaceData(CFA, move(scheme)); .). /*============================ METAPROGRAMMING ===============================*/ // TagsDecl = (. Expression tag; TagModifier mod = TagModifier::NONE; .) // ':' { MetaSimpExpr (. /*f.addTag(std::move(tag), mod); */ .) // }. FnTag = (. Expression tag; TagModifier mod = TagModifier::NONE; .) MetaSimpExpr ['-' TagMod] (. f->addTag(std::move(tag), mod); .). TagMod = ( "assert" (. mod = TagModifier::ASSERT; .) | "require" (. mod = TagModifier::REQUIRE; .) ). RuleDecl<> = "rule" tagcolon (. RuleArguments args; RuleGuards guards; DomainAnnotation typ; std::wstring arg; .) '(' Ident tagcolon Domain (. args.add(arg, typ); .) {',' Ident tagcolon Domain (. args.add(arg, typ); .) } ')' ["case" RGuard {',' RGuard}] '{' RBody '}' . /* - TODO use RGuard for guards-*/ RuleContextDecl = (.Expression eHead, eGuards, eBody; .) "rule" "context" tagcolon MetaSimpExpr "case" MetaSimpExpr '{' MetaSimpExpr '}' (.scope->contextRules.push_back(Expression(Operator::CONTEXT_RULE, {eHead, eGuards, eBody})); .). Domain = ( "function" (. dom = DomainAnnotation::FUNCTION; .) | "variable" (. dom = DomainAnnotation::VARIABLE; .) ). RGuard= (. Expression e; .) MetaExpr (. guards.add(std::move(e)); .). MetaExpr= (.Operator op; Expression e2; .) MetaExpr2 [MetaOp MetaExpr2 (. e = Expression(op, {e, e2}); .) ]. MetaExpr2= ( '(' MetaExpr ')' | MetaSimpExpr ). MetaSimpExpr= (. std::wstring i1, infix; Expression e2; .) ( '-' MetaSimpExpr (. e = Expression(Operator::NEG, {e2}); .) | IF(checkParametersList()) Ident (. e = Expression(Operator::CALL, {Expression(Atom(i1))}); .) '(' [ CalleeParams ] ')' | IF(checkInfix()) Ident Ident MetaSimpExpr (. e = Expression(Operator::CALL, {Expression(Atom(infix))}); e.addArg(Expression(Atom(i1))); e.addArg(std::move(e2)); .) | Ident (. e = Expression(Atom(i1)); .) ). RBody = (. Expression e; std::wstring msg; .) "warning" MetaExpr ["message" string (. msg = t->val; .) ] (. root.add(new RuleWarning(RuleArguments(args), RuleGuards(guards), std::move(e), Atom(msg))); .) . MetaOp< Operator& op> = implic (. op = Operator::IMPL; .) . /*============================ Expressions ===============================*/ - -ExprTyped = (. Expression tag; .) - Expr [tagcolon Type (. e.bindType(move(typ)); .) - {';' MetaSimpExpr (. e.tags.emplace(tag.getValueString(), move(tag)); .) - - }] -. +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< e> - [ RelOp< op> -SimExpr< e2> (. e = Expression(op, {e, 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; TypeAnnotation typ; .) +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 */.) + | StructLiteral (. /* struct */.) | SequenceDecl - | LoopDecl - | IfDecl + | LoopDecl + | IfDecl | SwitchDecl | AdhocDecl | number (. e = Expression(Atom(t->val)); .) | string (. e = Expression(Atom(t->val)); .) | '-' Factor< e> (. e = Expression(Operator::NEG, {e}); .) - | '(' Expr ')' + | '(' 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(move(val)); keys.push_back(Atom(key)); .) + {',' Ident '=' Expr (.e.addArg(Expression(val)); keys.push_back(Atom(key)); .) } '}' (. e.addBindings(keys.begin(), keys.end()); .) . ListLiteral = (. Expression eFrom, eTo; .) '[' -[ Expr (. e.addArg(std::move(eFrom)); .) -(".." Expr (. e.addArg(std::move(eTo)); e.setOp(Operator::LIST_RANGE); .) - |{',' Expr (. e.addArg(std::move(eFrom)); .) +[ 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; TypeAnnotation typ; .) - ExprTyped (. e.addArg(std::move(e2)); .) - {',' ExprTyped (. e.addArg(std::move(e2)); .) +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; .) += (. op = Operator::EQU; .) ( equal - | '<' (. op = Operator::LSS; .) - | '>' (. op = Operator::GTR; .) + | (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 08e9bd6..8cbfb4f 100644 --- a/config/default.json +++ b/config/default.json @@ -1,59 +1,73 @@ { "containers": { "id": { "implementations": "impl_fulfill_cluster", "clusters": "var_cluster", "prototypes": "proto_cluster", "linkedlist": "linkedlist" }, "impl": { "solid": "solid", "onthefly": "on_the_fly" } }, "logging": { "id": "logging" }, "function-entry": "entry", "clasp": { "bindings" : { "variable": "bind", "function": "bind_func", "scope": "bind_scope", "function_demand" : "bind_function_demand", "scope_decision": "bind_scope_decision" }, + "context" : { + "decisions":{ + "dependent": "resolution_dependency" + }, + }, + "nonevalue": "nonevalue", "ret": { "symbol": "retv", "tag": "ret" } }, "tests": { - "template": "context", + "template": "default", "templates": { - "basic": "EntryFunction*", "default": "*-", - "types": "Types*-", + + "basic": "Basic.*", + "ast": "AST.*", + "cfa": "CFA.*", + "dfa": "DFA.*", + "compilation": "Compilation.*", "containers": "Containers*-", - "ast": "AST*", - "non-containers": "*-Containers*", + "diagnostic": "Diagnostic.*", + "serializer": "ExpressionSerializer.*", + "externc": "InterfaceExternC.*", + "context": "ExpressionSerializer.*:Context.*", + "types": "Types.*-", "log": "Logging*", - "clang": "ClangAPI*", - "cfg": "CFG.*", - "skip": "SkipDetection*", + "clang": "ClangAPI.*", + "skip": "SkipDetection*:Adhoc_Loop_SkipDetection.*", "raw-xml": "libxml2*", "xml": "Xml.*", - "adhocs": "ExpressionSerializer.*:Adhoc.*:Context.*", - "context": "ExpressionSerializer.*:Context.*", - "installation": "Compilation.*:Sprint1.*" + "installation": "Compilation.*:Sprint1.*", + "exploitation": "Exploitation.*", + "loops": "Loop.*", + "dsl": "Interpretation.*", + "adhocs": "Adhoc.*", } } } diff --git a/cpp/src/CMakeLists.txt b/cpp/src/CMakeLists.txt index b64dbed..71152a3 100644 --- a/cpp/src/CMakeLists.txt +++ b/cpp/src/CMakeLists.txt @@ -1,228 +1,225 @@ cmake_minimum_required(VERSION 2.8.11) project(xreate) cmake_policy(SET CMP0022 NEW) # BUILD OPTIONS #====================== set(XREATE_DEFINITIONS -D_GNU_SOURCE -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS -DWITH_THREADS=1 ) add_definitions(${XREATE_DEFINITIONS}) add_compile_options(-Winvalid-pch -std=c++14 -fPIC) # LLVM #====================== FIND_PACKAGE (LLVM REQUIRED CONFIG PATHS /opt/llvm-3.8.0-0.x86_64/usr/share/llvm/cmake NO_DEFAULT_PATH) set (CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake-tools") #include(PCH_GCC4_v2) set(LLVM_VERSION ${LLVM_VERSION_MAJOR}.${LLVM_VERSION_MINOR}) message ("LLVM LIB PATH:" ${LLVM_LIBRARY_DIRS}) set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_LIST_DIR}) message ("MPATH:" ${CMAKE_MODULE_PATH}) message(STATUS "Found LLVM ${LLVM_PACKAGE_VERSION}") message(STATUS "Using LLVMConfig.cmake in: ${LLVM_DIR}") message(STATUS "INCLUDE DIR: ${LLVM_INCLUDE_DIRS}") INCLUDE_DIRECTORIES(${LLVM_INCLUDE_DIRS}) message("LLVM defs: " ${LLVM_DEFINITIONS}) add_definitions(${LLVM_DEFINITIONS}) llvm_map_components_to_libnames(LLVM_LIBS core nativecodegen native executionengine mcjit support) message("LLVM libs: " ${LLVM_LIBS}) # CLANG #====================== set(CLANG_LIBS ${LLVM_LIBRARY_DIRS}/libclangCodeGen.so ${LLVM_LIBRARY_DIRS}/libclangASTMatchers.so ${LLVM_LIBRARY_DIRS}/libclangQuery.so ${LLVM_LIBRARY_DIRS}/libclangTooling.so ${LLVM_LIBRARY_DIRS}/libclangFrontend.so ${LLVM_LIBRARY_DIRS}/libclangSerialization.so ${LLVM_LIBRARY_DIRS}/libclangDriver.so ${LLVM_LIBRARY_DIRS}/libclangParse.so ${LLVM_LIBRARY_DIRS}/libclangSema.so ${LLVM_LIBRARY_DIRS}/libclangAnalysis.so ${LLVM_LIBRARY_DIRS}/libclangAST.so ${LLVM_LIBRARY_DIRS}/libclangEdit.so ${LLVM_LIBRARY_DIRS}/libclangLex.so ${LLVM_LIBRARY_DIRS}/libclangBasic.so ) #find_package(Clang REQUIRED clangTooling libClang) message(STATUS "CLANG LIBS: " ${CLANG_LIBS}) # POTASSCO #====================== set(POTASSCO_PATH "/opt/potassco/clingo" CACHE PATH "Path to potassco sources") set(POTASSCO_INCLUDE_PATH ${POTASSCO_PATH}/libgringo ${POTASSCO_PATH}/libclasp ${POTASSCO_PATH}/libclingo ${POTASSCO_PATH}/libprogram_opts ${POTASSCO_PATH}/liblp ) INCLUDE_DIRECTORIES(${POTASSCO_INCLUDE_PATH}) set (LIBCLASP_PATH ${POTASSCO_PATH}/build/debug) set(LIBCLASP_LIBS clingo clasp gringo program_opts reify lp ) message(STATUS "CLASP LIBS: " ${LIBCLASP_LIBS}) link_directories(${LIBCLASP_PATH}) # OTHER DEPENDENCIES #=========================== set(JEAYESON_INCLUDE_PATH ${CMAKE_HOME_DIRECTORY}/../vendors/jeayeson/include/ ) INCLUDE_DIRECTORIES(${JEAYESON_INCLUDE_PATH}) # COCO #=========================== set(COCO_PATH ${CMAKE_HOME_DIRECTORY}/../coco/) set(COCO_SOURCE_FILES ${COCO_PATH}/Parser.cpp ${COCO_PATH}/Scanner.cpp) INCLUDE_DIRECTORIES(${COCO_PATH}) add_custom_command(OUTPUT ${COCO_SOURCE_FILES} COMMAND ${COCO_PATH}/gen-grammar WORKING_DIRECTORY ${COCO_PATH} MAIN_DEPENDENCY ${COCO_PATH}/xreate.ATG ) message(STATUS "COCO GRAMMAR BUILD STATUS:" ${COCO_OUTPUT}) # XREATE #====================== set(SOURCE_FILES pass/compilepass.cpp + pass/interpretationpass.cpp + compilation/targetinterpretation.cpp ast.cpp ExternLayer.cpp attachments.cpp - pass/interpretationpass.cpp - compilation/targetinterpretation.cpp analysis/cfagraph.cpp analysis/dfagraph.cpp analysis/aux.cpp compilation/containers.cpp compilation/advanced.cpp compilation/transformations.cpp analysis/DominatorsTreeAnalysisProvider.cpp clasplayer.cpp compilation/latecontextcompiler2.cpp query/context.cpp #compilation/latecontextcompiler.cpp serialization/expressionserializer.cpp serialization/expressionserializer2.cpp llvmlayer.cpp utils.cpp passmanager.cpp pass/abstractpass.cpp pass/dfapass.cpp pass/cfapass.cpp pass/loggerpass.cpp pass/adhocpass.cpp #pass/rulespass.cpp # query/containers.cpp query/ptrvalid.cpp contextrule.cpp - - #${POTASSCO_PATH}/app/shared/src/clingocontrol.cc - #${POTASSCO_PATH}/app/pyclingo/src/clingo_lib.cc ) set(XREATE_INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/ ) INCLUDE_DIRECTORIES(${XREATE_INCLUDE_DIRS}) set(XREATE_PRIVATE_INCLUDE_DIRS ${XREATE_INCLUDE_DIRS} ${COCO_PATH} ${JEAYESON_INCLUDE_PATH} ${LLVM_INCLUDE_DIRS} ${POTASSCO_INCLUDE_PATH} ) add_library(${PROJECT_NAME} SHARED ${SOURCE_FILES} ${COCO_SOURCE_FILES}) target_link_libraries(${PROJECT_NAME} ${LIBCLASP_LIBS}) target_include_directories(${PROJECT_NAME} INTERFACE ${XREATE_INCLUDE_DIRS} ${COCO_PATH} ${JEAYESON_INCLUDE_PATH} ${LLVM_INCLUDE_DIRS} ${POTASSCO_INCLUDE_PATH} ) get_directory_property(DEFINITIONS_ALL DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} COMPILE_DEFINITIONS) message("definitions all: " ${DEFINITIONS_ALL}) target_compile_definitions(${PROJECT_NAME} INTERFACE ${DEFINITIONS_ALL}) get_directory_property(COMPILATION_OPTIONS_ALL DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} COMPILE_OPTIONS) message("compilations all: " ${COMPILATION_OPTIONS_ALL}) target_compile_options(${PROJECT_NAME} INTERFACE ${COMPILATION_OPTIONS_ALL}) SET_PROPERTY(TARGET ${PROJECT_NAME} PROPERTY INTERFACE_LINK_LIBRARIES ${LLVM_LIBS} ${CLANG_LIBS} tbb ) #set (LINK_INTERFACE_LIBRARIES "") # FUNCTION(PREPEND var prefix) # SET(listVar "") # FOREACH(f ${ARGN}) # LIST(APPEND listVar "${prefix}/${f}") # ENDFOREACH(f) # SET(${var} "${listVar}" PARENT_SCOPE) # ENDFUNCTION(PREPEND) #set(COTIRE_UNITY_SOURCE_MAXIMUM_NUMBER_OF_INCLUDES "-j4") #cotire(xreate) # MACRO (ADD_PCH_RULE _header_filename _src_list) # SET(_gch_filename "${_header_filename}.gch") # LIST(APPEND ${_src_list} ${_gch_filename}) # SET (_args ${CMAKE_CXX_FLAGS}) # LIST(APPEND _args -c ${_header_filename} -o ${_gch_filename}) # GET_DIRECTORY_PROPERTY(DIRINC INCLUDE_DIRECTORIES) # foreach (_inc ${DIRINC}) # LIST(APPEND _args "-I" ${_inc}) # endforeach(_inc ${DIRINC}) # SEPARATE_ARGUMENTS(_args) # add_custom_command(OUTPUT ${_gch_filename} # COMMAND rm -f ${_gch_filename} # COMMAND ${CMAKE_CXX_COMPILER} ${CMAKE_CXX_COMPILER_ARG1} ${_args} # DEPENDS ${_header_filename}) # ENDMACRO(ADD_PCH_RULE _header_filename _src_list) # ADD_PCH_RULE (${CMAKE_HOME_DIRECTORY}/src/ast.h SOURCE_FILES) # ADD_PCH_RULE (${CMAKE_HOME_DIRECTORY}/src/llvmlayer.h SOURCE_FILES) # ADD_PCH_RULE (${CMAKE_HOME_DIRECTORY}/src/clasplayer.h SOURCE_FILES) # ADD_PCH_RULE (${CMAKE_HOME_DIRECTORY}/src/pass/abstractpass.h SOURCE_FILES) diff --git a/cpp/src/ExternLayer.cpp b/cpp/src/ExternLayer.cpp index 48f3f85..8874a23 100644 --- a/cpp/src/ExternLayer.cpp +++ b/cpp/src/ExternLayer.cpp @@ -1,299 +1,310 @@ // // Created by pgess on 4/21/15. // #include "ExternLayer.h" #include #include #include "clang/Tooling/Tooling.h" #include "clang/Frontend/ASTUnit.h" #include "clang/Frontend/CodeGenOptions.h" #include "clang/ASTMatchers/ASTMatchers.h" #include "clang/ASTMatchers/ASTMatchFinder.h" #include "clang/Basic/TargetInfo.h" #include "clang/Lex/PreprocessorOptions.h" #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; class FinderCallbackTypeDecl : public MatchFinder::MatchCallback { public : QualType typeResult; virtual void run(const MatchFinder::MatchResult &Result) { if (const TypedefDecl* decl = Result.Nodes.getNodeAs("typename")) { typeResult = decl->getUnderlyingType(); } } }; class FinderCallbackFunction : public MatchFinder::MatchCallback { public : QualType typeResult; virtual void run(const MatchFinder::MatchResult &Result) { if (const FunctionDecl* decl = Result.Nodes.getNodeAs("function")) { typeResult = decl->getType(); } } }; void ExternData::addLibrary(Atom&& name, Atom&& package) { __dictLibraries.emplace(name.get(), package.get()); } void ExternData::addIncludeDecl(Expression&& e) { assert(e.op == Operator::LIST_NAMED); //TODO ?? implement Expression parsing(Array of Expr as vector); for(size_t i=0, size=e.operands.size(); i headers; std::transform(listHeaders.operands.begin(), listHeaders.operands.end(), std::inserter(headers, headers.end()), [](const Expression& o){ assert(o.__state == Expression::STRING); return o.getValueString(); }); entries.emplace_back(ExternEntry{package, std::move(headers)}); } } void ExternLayer::addExternalData(const std::vector& data){ entries.insert(entries.end(), data.begin(), data.end()); } ExternLayer::ExternLayer(LLVMLayer *llvm) : __llvm(llvm) {} std::vector ExternLayer::fetchPackageFlags(const ExternEntry& entry){ std::vector args; FILE* flags = popen((string("pkg-config --cflags ") + entry.package).c_str(), "r"); size_t linesize=0; char* linebuf=0; ssize_t linelen=0; while ((linelen=getdelim(&linebuf, &linesize, ' ', flags))>0) { if (linebuf[0]=='\n') continue; if (linelen==1 && linebuf[0]==' ') continue; - if (linebuf[linelen-1 ] == ' ') - linebuf[linelen-1] = 0; + //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); + args.push_back(linebuf); free(linebuf); linebuf = 0; } + pclose(flags); return (args); } std::vector ExternLayer::fetchPackageLibs(const ExternEntry& entry){ std::vector libs; FILE* flags = popen((string("pkg-config --libs ") + entry.package).c_str(), "r"); size_t linesize=0; char* linebuf=0; ssize_t linelen=0; while ((linelen=getdelim(&linebuf, &linesize, ' ', flags))>0) { - if (linebuf[0]=='\n') continue; - if (linelen==1 && linebuf[0]==' ') continue; - if (linebuf[linelen-1 ] == ' ') - linebuf[linelen-1] = 0; - if (linelen>=2 && linebuf[0] == '-' && linebuf[1] == 'l'){ - libs.push_back(linebuf + 2); - } else { - libs.push_back(linebuf); - } + 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; - llvm::outs() << '<' << linebuf << "> "; - free(linebuf); - linebuf = 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 "<__externdata); - // TODO 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" }; std::vector libs; boost::format formatInclude("#include \"%1%\""); for(const ExternEntry& entry: entries) { llvm::outs()<<"[ExternC] Processing package: "<< entry.package << "\n"; llvm::outs()<<"[ExternC] args: "; vector&& args2 = fetchPackageFlags(entry); args.insert(args.end(), args2.begin(), args2.end()); for(const string arg: args2) { llvm::outs()<< "<" << arg << "> "; } llvm::outs()<<"\n[ExternC] libs: "; args2 = fetchPackageLibs(entry); for(const string arg: args2) { llvm::outs()<< "<" << arg << "> "; } libs.insert(libs.end(), args2.begin(), args2.end()); llvm::outs()<<"\n[ExternC] headers: "; std::transform(entry.headers.begin(), entry.headers.end(), std::inserter(code, code.begin()), [&formatInclude](const string header ) { string line = boost::str(formatInclude % header); llvm::outs()<< "<" << line << "> "; return line; }); llvm::outs() << '\n'; } loadLibraries(move(libs)); ast = buildASTFromCodeWithArgs(boost::algorithm::join(code, "\n"), args); __cgo.reset(new CodeGenOptions); __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(), - + ast->getASTContext(), + *__hso, *__ppo, - *__cgo, + *__cgo, *__llvm->module, ast->getASTContext().getDiagnostics())); }; bool ExternLayer::isPointer(const clang::QualType &t) { const clang::Type * tInfo = t.getTypePtr(); assert(tInfo); return tInfo->isAnyPointerType(); } llvm::Type* ExternLayer::toLLVMType(const clang::QualType& t){ return __cgm->getTypes().ConvertType(t); } std::vector ExternLayer::getStructFields(const clang::QualType& ty) { clang::QualType t = ty; if (isPointer(ty)){ const clang::PointerType* tPtr = ty->getAs(); t = tPtr->getPointeeType(); } assert(t.getTypePtr()->isRecordType()); const RecordType *record = t->getAsStructureType(); assert(record); std::vector result; //FieldDecl* field: record->getDecl()->fields() for (auto i=record->getDecl()->field_begin(); i!= record->getDecl()->field_end(); ++i){ result.push_back(i->getName()); } return result; } clang::QualType ExternLayer::lookupType(const std::string& id){ MatchFinder finder; FinderCallbackTypeDecl callbackTypeDecl; auto matcherTypeDecl = typedefDecl(hasName(id)).bind("typename"); finder.addMatcher(matcherTypeDecl, &callbackTypeDecl); finder.matchAST(ast->getASTContext()); assert(! callbackTypeDecl.typeResult.isNull()); return callbackTypeDecl.typeResult; } llvm::Function* ExternLayer::lookupFunction(const std::string& name){ if (__functions.count(name)){ return __functions.at(name); } MatchFinder finder; FinderCallbackFunction callback; auto matcher = functionDecl(hasName(name)).bind("function"); finder.addMatcher(matcher, &callback); finder.matchAST(ast->getASTContext()); if (callback.typeResult.isNull()){ cout <<"[External Layer] " << "Unknown function: "<getTypes().ConvertType(tyFuncQual); llvm::FunctionType* tyRawFunc = llvm::dyn_cast(tyRaw); llvm::Function* function = llvm::Function::Create(tyRawFunc, llvm::GlobalValue::ExternalLinkage, name, __llvm->module); __functions.emplace(name, function); return function; } diff --git a/cpp/src/analysis/dfagraph.cpp b/cpp/src/analysis/dfagraph.cpp index 360035b..7ccf9e0 100644 --- a/cpp/src/analysis/dfagraph.cpp +++ b/cpp/src/analysis/dfagraph.cpp @@ -1,237 +1,250 @@ #include "analysis/dfagraph.h" #include "analysis/aux.h" #include using namespace xreate; using namespace xreate::analysis; using namespace std; -namespace xreate {namespace analysis { -void -DFAGraph::print(std::ostringstream& output) const { - std::set symbols; +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 << endl << "%\t\tStatic analysis: DFA" << endl; + output << formatDfaConnection + % formatSymbol(i1->first) + % formatSymbol(i1->second) + % edgeName + << " %" << this->__clasp->getHintForPackedSymbol(i1->first) << " - " << this->__clasp->getHintForPackedSymbol(i1->second) + << endl; - std::vector>::const_iterator i1; - std::vector::const_iterator i2; + symbols.insert(i1->first); + symbols.insert(i1->second); + } - 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; - } + 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; + } - output << formatDfaConnection - %formatSymbol(i1->first) - %formatSymbol(i1->second) - %edgeName - << " %" <__clasp->getHintForPackedSymbol(i1->first) << " - " << this->__clasp->getHintForPackedSymbol(i1->second) - <& 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(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<first) - %formatSymbol(i->second) - << " %" - << this->__clasp->getHintForPackedSymbol(i->first) << " - " - << this->__clasp->getHintForPackedSymbol(i->second) - <& 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; + } } - symbols.insert(tag.first); - } + class VisitorAddTag : public boost::static_visitor<> { + public: - for (const SymbolPacked& s: symbols) - { - output << "v(" << formatSymbol(s) << ")." - << " %" << this->__clasp->getHintForPackedSymbol(s) - <__tags.emplace(symbol, move(__tag)); + } -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()(SymbolTransient& symbol){ - symbol.tags.push_back(move(__tag)); - } + void operator()(const SymbolInvalid& symbol) { + assert(false && "Undefined behaviour"); + } - void operator()(const SymbolInvalid& symbol){ - assert(false && "Undefined behaviour"); - } + VisitorAddTag(DFAGraph * const dfagraph, Expression&& tag) : + __graph(dfagraph), __tag(tag) { + } + + private: + DFAGraph * const __graph; + Expression __tag; + }; + + class VisitorAddLink : public boost::static_visitor<> { + public: + + void operator()(const SymbolPacked& nodeFrom) { + if (!__graph->isConnected(__nodeTo, nodeFrom)) { + __graph->__edges.emplace_back(__nodeTo, nodeFrom); + __graph->__data.push_back(__link); + + DFAGraph::EdgeId eid = __graph->__edges.size() - 1; + __graph->__outEdges.emplace(nodeFrom, eid); + } + } + + void operator()(const SymbolTransient& symbolFrom) { + 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"); + } + } + + void operator()(const SymbolInvalid&) { + if (__link == DFGConnection::STRONG) return; + if (__link == DFGConnection::WEAK) return; - VisitorAddTag(DFAGraph* const dfagraph, Expression&& tag): - __graph(dfagraph), __tag(tag) {} + assert(false && "Undefined behavior"); + } - private: - DFAGraph* const __graph; - Expression __tag; -}; + VisitorAddLink(DFAGraph * const dfagraph, const SymbolPacked& nodeTo, DFGConnection link) : + __graph(dfagraph), __nodeTo(nodeTo), __link(link) { + } -class VisitorAddLink: public boost::static_visitor<> { -public: - void operator()(const SymbolPacked& nodeFrom){ - if (!__graph->isConnected(__nodeTo, nodeFrom)) + private: + DFAGraph * const __graph; + SymbolPacked __nodeTo; + DFGConnection __link; + }; + + class VisitorGetDependencyConnection : public boost::static_visitor> { - __graph->__edges.emplace_back(__nodeTo, nodeFrom); - __graph->__data.push_back(__link); + public: + + list + operator()(const SymbolPacked & nodeFrom) { + return + { + nodeFrom + }; + } - DFAGraph::EdgeId eid = __graph->__edges.size()-1; - __graph->__outEdges.emplace(nodeFrom, eid); - } - } + list + operator()(const SymbolTransient & nodeFrom) { + return nodeFrom.dependencies; + } - void operator()(const SymbolTransient& symbolFrom){ - switch (__link){ - case DFGConnection::WEAK: { - //virtual symbol to hold transient annotations - SymbolPacked symbPivot = __graph->createAnonymousSymbol(symbolFrom.scope); + list + operator()(const SymbolInvalid&) { + assert(false && "Undefined behavior"); + } - __graph->addConnection(symbPivot, symbolFrom, DFGConnection::STRONG); - __graph->addConnection(__nodeTo, symbPivot, DFGConnection::WEAK); - break; + VisitorGetDependencyConnection(DFAGraph * const g) : graph(g) { } + DFAGraph * const graph; + }; + + class VisitorSetDependencyConnection : public boost::static_visitor<> { + public: + + void operator()(SymbolPacked& nodeTo) { + VisitorGetDependencyConnection visitorGetDepenencies(graph); + auto deps = boost::apply_visitor(visitorGetDepenencies, nodeFrom); - case DFGConnection::STRONG: { - for (const Expression& tag: symbolFrom.tags){ - __graph->__tags.emplace(__nodeTo, tag); + for (const SymbolPacked& dep : deps) { + graph->__dependencies.emplace(nodeTo, dep); } - break; } - default: - assert(false && "Undefined behavior"); - } - } + void operator()(SymbolTransient& nodeTo) { + VisitorGetDependencyConnection visitorGetDepenencies(graph); + auto deps = boost::apply_visitor(visitorGetDepenencies, nodeFrom); - void operator()(const SymbolInvalid&){ - if (__link == DFGConnection::STRONG) return; - if (__link == DFGConnection::WEAK) return; + for (const SymbolPacked& dep : deps) { + nodeTo.dependencies.push_back(dep); + } + } - assert(false && "Undefined behavior"); - } + void operator()(SymbolInvalid&) { + assert(false && "Undefined behavior"); + } - VisitorAddLink(DFAGraph* const dfagraph, const SymbolPacked& nodeTo, DFGConnection link): - __graph(dfagraph), __nodeTo(nodeTo), __link(link) {} + VisitorSetDependencyConnection(DFAGraph * const g, SymbolNode s) : graph(g), nodeFrom(s) { + } + DFAGraph * const graph; + SymbolNode nodeFrom; + }; -private: - DFAGraph* const __graph; - SymbolPacked __nodeTo; - DFGConnection __link; -}; + bool + DFAGraph::isConnected(const SymbolPacked& identifierTo, const SymbolPacked& identifierFrom) { + auto range = __outEdges.equal_range(identifierFrom); -class VisitorGetDependencyConnection: public boost::static_visitor> { -public: - list - operator()(const SymbolPacked& nodeFrom){ - return {nodeFrom}; - } - - list - operator()(const SymbolTransient& nodeFrom){ - return nodeFrom.dependencies; - } - - list - operator()(const SymbolInvalid&){ - assert(false && "Undefined behavior"); - } - - VisitorGetDependencyConnection(DFAGraph* const g): graph(g){} - DFAGraph* const graph; -}; - -class VisitorSetDependencyConnection: public boost::static_visitor<> { -public: - void operator()(SymbolPacked& nodeTo){ - VisitorGetDependencyConnection visitorGetDepenencies(graph); - auto deps = boost::apply_visitor(visitorGetDepenencies, nodeFrom); - - for (const SymbolPacked& dep: deps){ - graph->__dependencies.emplace(nodeTo, dep); + for (std::multimap::iterator edge = range.first; edge != range.second; ++edge) { + if (__edges[edge->second].second == identifierTo) + return true; + } + + return false; } - } - - void operator()(SymbolTransient& nodeTo){ - VisitorGetDependencyConnection visitorGetDepenencies(graph); - auto deps = boost::apply_visitor(visitorGetDepenencies, nodeFrom); - - for (const SymbolPacked& dep: deps){ - nodeTo.dependencies.push_back(dep); + + void + DFAGraph::addConnection(const SymbolPacked& nodeTo, const SymbolNode& nodeFrom, DFGConnection link) { + VisitorAddLink visitor(this, nodeTo, link); + boost::apply_visitor(visitor, nodeFrom); } - } - - void operator()(SymbolInvalid&){ - assert(false && "Undefined behavior"); - } - - VisitorSetDependencyConnection(DFAGraph* const g, SymbolNode s): graph(g), nodeFrom(s){} - DFAGraph* const graph; - SymbolNode nodeFrom; -}; - -bool -DFAGraph::isConnected(const SymbolPacked& identifierTo, const SymbolPacked& identifierFrom) -{ - auto range = __outEdges.equal_range(identifierFrom); - - for(std::multimap::iterator edge = range.first; edge != range.second; ++edge) - { - if (__edges[edge->second].second == identifierTo) - return true; - } - return false; -} - -void -DFAGraph::addConnection(const SymbolPacked& nodeTo, const SymbolNode& nodeFrom, DFGConnection link) { - VisitorAddLink visitor(this, nodeTo, link); - boost::apply_visitor(visitor, nodeFrom); -} - -void -DFAGraph::addDependencyConnection(SymbolNode& identifierTo, SymbolNode& identifierFrom){ - VisitorSetDependencyConnection visitor(this, identifierFrom); - boost::apply_visitor(visitor, identifierTo); -} - -void -DFAGraph::addAnnotation(SymbolNode& node, Expression&& tag) { - VisitorAddTag visitor(this, move(tag)); - boost::apply_visitor(visitor, node); -} - -SymbolPacked -DFAGraph::createAnonymousSymbol(const ScopePacked& scope){ - return SymbolPacked{__countAnonymousSymbols++, scope, true}; -} - -}} \ No newline at end of file + void + DFAGraph::addDependencyConnection(SymbolNode& identifierTo, SymbolNode& identifierFrom) { + VisitorSetDependencyConnection visitor(this, identifierFrom); + boost::apply_visitor(visitor, identifierTo); + } + + void + DFAGraph::addAnnotation(SymbolNode& node, Expression&& tag) { + VisitorAddTag visitor(this, move(tag)); + boost::apply_visitor(visitor, node); + } + + SymbolPacked + DFAGraph::createAnonymousSymbol(const ScopePacked& scope) { + return SymbolPacked{__countAnonymousSymbols++, scope, true}; + } + + } +} \ No newline at end of file diff --git a/cpp/src/ast.cpp b/cpp/src/ast.cpp index 1552a18..27b3468 100644 --- a/cpp/src/ast.cpp +++ b/cpp/src/ast.cpp @@ -1,774 +1,816 @@ #include "ast.h" #include "ExternLayer.h" #include #include #include using namespace std; namespace xreate{ class ExpressionHints{ public: static bool 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 Operator::CALL: case Operator::INDEX: return true; default: return false; } } } return false; } static bool 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; } return false; } }; class TypesResolver { private: const AST* ast; std::map scope; std::map signatures; ExpandedType expandType(const TypeAnnotation &t, const std::vector &args = std::vector()){ return TypesResolver(ast, scope, signatures)(t, args); } std::vector expandOperands(const std::vector& operands) { std::vector pack; pack.reserve(operands.size()); std::transform(operands.begin(), operands.end(), std::inserter(pack, pack.end()), [this](const TypeAnnotation& t){ return expandType(t); }); return pack; } public: TypesResolver(const AST* root, const std::map& scopeOuter = std::map(), std::map signaturesOuter = std::map()) : ast(root), scope(scopeOuter), signatures(signaturesOuter) { } ExpandedType operator()(const TypeAnnotation &t, const std::vector &args = std::vector()) { //assert(args.size() == t.bindings.size()); // invalid number of arguments for (size_t i=0; i elTy = expandType(t.__operands.at(0)); return ExpandedType(TypeAnnotation(tag_array, elTy, t.__size)); } case TypeOperator::STRUCT: { assert(t.__operands.size()); std::vector&& pack = expandOperands(t.__operands); auto tnew = TypeAnnotation(TypeOperator::STRUCT, move(pack)); tnew.fields = t.fields; return ExpandedType(move(tnew)); }; case TypeOperator::CALL: { std::string alias = t.__valueCustom; //find in local scope: TypeAnnotation ty; if (scope.count(alias)) { ty = scope.at(alias); } else if (ast->__indexTypeAliases.count(alias)){ ty = ast->__indexTypeAliases.at(alias); } else { assert(false && "Undefined or external type"); } std::vector&& operands = expandOperands(t.__operands); TypeAnnotation signature(TypeOperator::CALL, move(operands)); signature.__valueCustom = alias; if (signatures.count(signature)) { auto link = TypeAnnotation(TypeOperator::LINK, {}); link.conjuctionId = signatures.at(signature); return ExpandedType(move(link)); } int cid = signatures.size(); signatures[signature] = cid; TypeAnnotation tyResult = expandType(ty, operands); tyResult.conjuctionId = cid; return ExpandedType(move(tyResult)); }; case TypeOperator::CUSTOM: { std::string alias = t.__valueCustom; /* if (signatures.count(alias)) { return ExpandedType(TypeAnnotation(TypeOperator::LINK, {t})); } signatures[alias].emplace(t); */ //find in local scope: if (scope.count(alias)) { return expandType(scope.at(alias)); } // find in general scope: if(ast->__indexTypeAliases.count(alias)) { return expandType(ast->__indexTypeAliases.at(t.__valueCustom)); } //if type is unknown keep it as is. return ExpandedType(TypeAnnotation(t)); }; case TypeOperator::ACCESS: { std::string alias = t.__valueCustom; ExpandedType tyAlias= ExpandedType(TypeAnnotation()); //find in local scope: if (scope.count(alias)) { tyAlias = expandType(scope.at(alias)); //find in global scope: } else if((ast->__indexTypeAliases.count(alias))) { tyAlias = expandType(ast->__indexTypeAliases.at(alias)); } else { assert(false && "Undefined or external type"); } assert(tyAlias->__operator == TypeOperator::STRUCT); for (const string& field: t.fields){ auto fieldIt = std::find(tyAlias->fields.begin(), tyAlias->fields.end(), field); assert(fieldIt != tyAlias->fields.end() && "unknown field"); int fieldId = fieldIt - tyAlias->fields.begin(); tyAlias = expandType(tyAlias->__operands.at(fieldId)); } return tyAlias; } case TypeOperator::TUPLE: { assert(t.__operands.size()); std::vector pack; pack.reserve(t.__operands.size()); std::transform(t.__operands.begin(), t.__operands.end(), std::inserter(pack, pack.end()), [this](const TypeAnnotation& t){ return expandType(t); }); return ExpandedType(TypeAnnotation(TypeOperator::TUPLE, move(pack))); } case TypeOperator::VARIANT: { return ExpandedType(TypeAnnotation(t)); } case TypeOperator::NONE: { return ExpandedType(TypeAnnotation(t)); } default: assert(false); } assert(false); return ExpandedType(TypeAnnotation()); } }; TypeAnnotation::TypeAnnotation() { } TypeAnnotation::TypeAnnotation(const Atom &typ) : __value(typ.get()) { ; } TypeAnnotation::TypeAnnotation (TypePrimitive typ) : __value(typ) {} TypeAnnotation::TypeAnnotation(TypeOperator op, std::initializer_list operands) : __operator(op), __operands(operands) { } TypeAnnotation::TypeAnnotation (TypeOperator op, std::vector&& operands) : __operator(op), __operands(operands) {} TypeAnnotation::TypeAnnotation (llvm_array_tag, TypeAnnotation typ, int size) :TypeAnnotation(TypeOperator::ARRAY, {typ}) { __size=size; } bool TypeAnnotation::operator< (const TypeAnnotation& t) const{ if (__operator != t.__operator) return __operator < t.__operator; if (__operator == TypeOperator::NONE) return __value < t.__value; if (__operator == TypeOperator::CALL || __operator == TypeOperator::CUSTOM || __operator == TypeOperator::ACCESS){ if (__valueCustom != t.__valueCustom) return __valueCustom < t.__valueCustom; } return __operands < t.__operands; } /* TypeAnnotation (struct_tag, std::initializer_list) {} */ void TypeAnnotation::addBindings(std::vector>&& params) { bindings.reserve(bindings.size() + params.size()); std::transform(params.begin(), params.end(), std::inserter(bindings, bindings.end()), [](const Atom& ident){return ident.get(); }); } void TypeAnnotation::addFields(std::vector>&& listFields) { fields.reserve(fields.size() + listFields.size()); std::transform(listFields.begin(), listFields.end(), std::inserter(fields, fields.end()), [](const Atom& ident){return ident.get(); }); } Expression::Expression(const Atom& number) : __state(NUMBER), op(Operator::NONE), __valueD(number.get()) { } Expression::Expression(const Atom& a) : __state(STRING), op(Operator::NONE), __valueS(a.get()) { } Expression::Expression(const Atom &ident) : __state(IDENT), op(Operator::NONE), __valueS(ident.get()) { } Expression::Expression(const Operator &oprt, std::initializer_list params) : __state(COMPOUND), op(oprt) { if (op == Operator::CALL) { assert(params.size() > 0); Expression arg = *params.begin(); assert(arg.__state == Expression::IDENT); __valueS = std::move(arg.__valueS); operands.insert(operands.end(), params.begin()+1, params.end()); return; } operands.insert(operands.end(), params.begin(), params.end()); } void Expression::setOp(Operator oprt) { op = oprt; switch (op) { case Operator::NONE: __state = INVALID; break; default: __state = COMPOUND; break; } } void Expression::addArg(Expression &&arg) { operands.push_back(arg); } void Expression::addBindings(std::initializer_list> params) { addBindings(params.begin(), params.end()); } void Expression::bindType(TypeAnnotation t) { type = move(t); } void Expression::addBlock(ManagedScpPtr scope) { blocks.push_back(scope.operator ->()); } const std::vector& Expression::getOperands() const { return operands; } double Expression::getValueDouble() const { return __valueD; } const std::string& Expression::getValueString() const { return __valueS; } void Expression::setValue(const Atom&& v){ __valueS = v.get(); } void Expression::setValueDouble(double value){ __valueD = value; } bool Expression::isValid() const{ return (__state != INVALID); } bool Expression::isDefined() const{ return (__state != BINDING); } 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; } AST::AST() { } void AST::addInterfaceData(const ASTInterface& interface, Expression&& data ) { __interfacesData.emplace(interface, move(data)); } void AST::addDFAData(Expression &&data) { __dfadata.push_back(data); } void AST::addExternData(ExternData &&data) { __externdata.insert(__externdata.end(), data.entries.begin(), data.entries.end()); } void AST::add(Function* f) { __functions.push_back(f); __indexFunctions.emplace(f->getName(), __functions.size()-1); } void AST::add(MetaRuleAbstract *r) { __rules.push_back(r); } void AST::add(TypeAnnotation t, Atom alias){ if (t.__operator == TypeOperator::VARIANT){ for (int i=0, size=t.fields.size(); i< size; ++i){ __dictVariants.emplace(t.fields[i], make_pair(t, i)); } } __indexTypeAliases.emplace(alias.get(), move(t)); } ManagedScpPtr AST::add(CodeScope* scope) { this->__scopes.push_back(scope); return ManagedScpPtr(this->__scopes.size()-1, &this->__scopes); } std::string AST::getModuleName() { const std::string name = "moduleTest"; return name; } ManagedPtr AST::findFunction(const std::string& name) { int count = __indexFunctions.count(name); if (!count) { return ManagedFnPtr::Invalid(); } assert(count ==1); auto range = __indexFunctions.equal_range(name); return ManagedPtr(range.first->second, &this->__functions); } std::list AST::getAllFunctions() const{ const size_t size = __functions.size(); std::list result; for (size_t i=0; i__functions)); } return result; } //TASK select default specializations std::list AST::getFunctionVariants(const std::string& name) const{ auto functions = __indexFunctions.equal_range(name); std::list result; std::transform(functions.first, functions.second, inserter(result, result.end()), [this](auto f){return ManagedFnPtr(f.second, &this->__functions);}); return result; } template<> ManagedPtr AST::begin() {return ManagedPtr(0, &this->__functions);} template<> ManagedPtr AST::begin() {return ManagedPtr(0, &this->__scopes);} template<> ManagedPtr AST::begin() {return ManagedPtr(0, &this->__rules);} Expanded AST::expandType(const TypeAnnotation &t) const { return TypesResolver(this)(t); } Expanded AST::findType(const std::string& name){ // find in general scope: if(__indexTypeAliases.count(name)) return expandType(__indexTypeAliases.at(name)); //if type is unknown keep it as is. TypeAnnotation t(TypeOperator::CUSTOM, {}); t.__valueCustom = name; return ExpandedType(move(t)); } void AST::recognizeVariantIdentifier(Expression& identifier){ // 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 assert(identifier.__state == Expression::IDENT); std::string name = identifier.getValueString(); if (__dictVariants.count(name)){ auto record = __dictVariants.at(name); const TypeAnnotation& typ = record.first; identifier.__state = Expression::VARIANT; identifier.setValueDouble(record.second); identifier.type = typ; } } Function::Function(const Atom& name) : __entry(new CodeScope(0)) { __name = name.get(); } void Function::addTag(Expression&& tag, const TagModifier mod) { string name = tag.getValueString(); __tags.emplace(move(name), move(tag)); } const std::map& Function::getTags() const { return __tags; } CodeScope* Function::getEntryScope() const { return __entry; } void Function::addBinding(Atom && name, Expression&& argument) { __entry->addBinding(move(name), move(argument)); } void Function::setReturnType(const TypeAnnotation &rtyp) { + __entry->__declarations[0].type = rtyp; } const std::string& Function::getName() const { return __name; } Symbol CodeScope::registerIdentifier(Atom &&name) { __identifiers.emplace(name.get(), ++__vCounter); return {__vCounter, this}; } void CodeScope::addBinding(Atom && name, Expression&& argument) { __bindings.push_back(name.get()); Symbol binding = registerIdentifier(move(name)); argument.__state = Expression::BINDING; __declarations[binding.identifier] = move(argument); } void CodeScope::addDeclaration(Atom && name, Expression&& body) { Symbol s = registerIdentifier(move(name)); __declarations[s.identifier] = move(body); } CodeScope::CodeScope(CodeScope* parent) :__parent(parent) {} CodeScope::~CodeScope() {} - - - - void CodeScope::setBody(const Expression &body) { - __body = body; + __declarations[0] = body; +} + +Expression& +CodeScope::getBody(){ + return __declarations[0]; } 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::findDeclaration(const Symbol& symbol) { CodeScope* self = symbol.scope; return self->__declarations[symbol.identifier]; } void RuleArguments::add(const Atom &arg, DomainAnnotation typ) { emplace_back(arg.get(), typ); } void RuleGuards::add(Expression&& e) { push_back(e); } MetaRuleAbstract:: MetaRuleAbstract(RuleArguments&& args, RuleGuards&& guards) : __args(std::move(args)), __guards(std::move(guards)) {} MetaRuleAbstract::~MetaRuleAbstract(){} RuleWarning:: RuleWarning(RuleArguments&& args, RuleGuards&& guards, Expression&& condition, Atom&& message) : MetaRuleAbstract(std::move(args), std::move(guards)), __message(message.get()), __condition(condition) {} RuleWarning::~RuleWarning(){} void RuleWarning::compile(ClaspLayer& layer) { //TODO restore addRuleWarning //layer.addRuleWarning(*this); } bool operator< (const Symbol& s1, const Symbol& s2) { return (s1.scope < s2.scope) || (s1.scope==s2.scope && s1.identifier #include #include #include #include #include #include #include "utils.h" #include namespace llvm { class Value; } namespace xreate { struct String_t { }; struct Identifier_t { }; struct Number_t { }; struct Type_t { }; template class Atom { }; //DEBT hold for all atoms/identifiers Parser::Token data, like line:col position template<> class Atom { public: Atom(const std::wstring& value) { char buffer[32]; wcstombs(buffer, value.c_str(), 32); __value = buffer; } Atom(std::string && name) : __value(name) { } const std::string& get() const { return __value; } private: std::string __value; }; template<> class Atom { public: Atom(wchar_t* value) { __value = wcstol(value, 0, 10); } Atom(int value) : __value(value) { } double get()const { return __value; } private: double __value; }; template<> class Atom { public: Atom(const std::wstring& value) { assert(value.size()); __value = std::string(++value.begin(), --value.end()); } const std::string& get() const { return __value; } private: std::string __value; }; enum class TypePrimitive { Bool, 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 { }; struct struct_tag { }; const llvm_array_tag tag_array = llvm_array_tag(); const struct_tag tag_struct = struct_tag(); class TypeAnnotation { public: TypeAnnotation(); TypeAnnotation(const Atom& typ); TypeAnnotation(TypePrimitive typ); TypeAnnotation(llvm_array_tag, TypeAnnotation typ, int size); TypeAnnotation(TypeOperator op, std::initializer_list operands); TypeAnnotation(TypeOperator op, std::vector&& operands); void addBindings(std::vector>&& params); void addFields(std::vector>&& listFields); bool operator<(const TypeAnnotation& t) const; // TypeAnnotation (struct_tag, std::initializer_list); TypeOperator __operator = TypeOperator::NONE; std::vector __operands; TypePrimitive __value; std::string __valueCustom; int conjuctionId = -1; //conjunction point id (relevant for recursive types) uint64_t __size = 0; std::vector fields; std::vector bindings; private: }; enum class Operator { ADD, SUB, MUL, DIV, EQU, 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 }; class Function; class AST; class CodeScope; class MetaRuleAbstract; template struct ManagedPtr { static ManagedPtr Invalid() { return ManagedPtr(); } ManagedPtr() : __storage(0) { } ManagedPtr(unsigned int id, const std::vector* storage) : __id(id), __storage(storage) { } Target& operator*() const { assert(isValid() && "Invalid Ptr"); return *__storage->at(__id); } void operator=(const ManagedPtr& other) { __id = other.__id; __storage = other.__storage; } bool operator==(const ManagedPtr& other) { return isValid() && (__id == other.__id); } Target* operator->() const noexcept { assert(isValid() && "Invalid Ptr"); return __storage->at(__id); } inline bool isValid() const { return (__storage) && (0 <= __id) && (__id < __storage->size()); } inline operator bool() const { return isValid(); } ManagedPtr& operator++() { ++__id; return *this; } inline unsigned int id() const { return __id; } private: unsigned int __id = 0; const std::vector * __storage = 0; }; typedef ManagedPtr ManagedFnPtr; typedef ManagedPtr ManagedScpPtr; typedef ManagedPtr ManagedRulePtr; const ManagedScpPtr NO_SCOPE = ManagedScpPtr(UINT_MAX, 0); //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&); template void Expression::addBindings(InputIt paramsBegin, InputIt paramsEnd) { size_t index = bindings.size(); std::transform(paramsBegin, paramsEnd, std::inserter(bindings, bindings.end()), [&index, this] (const Atom atom) { std::string key = atom.get(); this->__indexBindings[key] = index++; return key; }); } typedef std::list ExpressionList; enum class TagModifier { NONE, ASSERT, REQUIRE }; enum class DomainAnnotation { FUNCTION, VARIABLE }; class RuleArguments : public std::vector> { public: void add(const Atom& name, DomainAnnotation typ); }; class RuleGuards : public std::vector { public: void add(Expression&& e); }; class ClaspLayer; class LLVMLayer; class MetaRuleAbstract { public: MetaRuleAbstract(RuleArguments&& args, RuleGuards&& guards); virtual ~MetaRuleAbstract(); virtual void compile(ClaspLayer& layer) = 0; protected: RuleArguments __args; RuleGuards __guards; }; class RuleWarning : public MetaRuleAbstract { friend class ClaspLayer; public: RuleWarning(RuleArguments&& args, RuleGuards&& guards, Expression&& condition, Atom&& message); virtual void compile(ClaspLayer& layer); ~RuleWarning(); private: std::string __message; Expression __condition; }; typedef unsigned int VID; /* class Expression: ExpressionAbstract { friend class CFGPass; public: llvm::Value* compile(LLVMLayer& l, Function* f, std::string* hintRetVar=0) const; }; */ typedef std::pair Tag; struct Symbol { VID identifier; CodeScope * scope; }; bool operator<(const Symbol& s1, const Symbol& s2); bool operator==(const Symbol& s1, const Symbol& s2); class CodeScope { friend class Function; friend class PassManager; public: CodeScope(CodeScope* parent = 0); void setBody(const Expression& body); + 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; - Expression __body; //TODO move __body to __declarations[0] - 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); }; class Function { friend class Expression; friend class CodeScope; friend class AST; 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: std::map __tags; }; class ExternData; struct ExternEntry { std::string package; std::vector headers; }; typedef Expanded ExpandedType; enum ASTInterface { CFA, DFA, Extern, Adhoc }; struct FunctionSpecialization { std::string guard; size_t id; }; struct FunctionSpecializationQuery { std::unordered_set context; }; template<> struct AttachmentsStorage { static Attachments* get(const Symbol& s) { return &s.scope->findDeclaration(s).tagsInternal; } }; template<> struct AttachmentsStorage { static Attachments* get(const Expression& e) { return &e.tagsInternal; } }; class AST { public: AST(); //TASK extern and DFA interfaces move into addInterfaceData /** * DFA Interface */ void addDFAData(Expression&& data); /** * Extern Interface */ void addExternData(ExternData&& data); void addInterfaceData(const ASTInterface& interface, Expression&& data); void add(Function* f); void add(MetaRuleAbstract* r); ManagedScpPtr add(CodeScope* scope); std::string getModuleName(); ManagedPtr findFunction(const std::string& name); typedef std::multimap FUNCTIONS_REGISTRY; std::list getAllFunctions() const; std::list getFunctionVariants(const std::string& name) const; template ManagedPtr begin(); std::vector __externdata; std::list __dfadata; //TODO move to more appropriate place std::list __rawImports; //TODO move to more appropriate place std::multimap __interfacesData; //TODO CFA data here. private: std::vector __rules; std::vector __functions; std::vector __scopes; FUNCTIONS_REGISTRY __indexFunctions; // ***** TYPES SECTION ***** public: std::map __indexTypeAliases; ExpandedType expandType(const TypeAnnotation &t) const; ExpandedType findType(const std::string& name); void add(TypeAnnotation t, Atom alias); void recognizeVariantIdentifier(Expression& identifier); private: std::map> __dictVariants; ExpandedType expandType(const TypeAnnotation &t, std::map scope, const std::vector &args = std::vector()) const; // ***** TYPES SECTION END ***** }; template<> ManagedPtr AST::begin(); template<> ManagedPtr AST::begin(); template<> ManagedPtr AST::begin(); } #endif // AST_H diff --git a/cpp/src/attachments.h b/cpp/src/attachments.h index a62cd20..03b8711 100644 --- a/cpp/src/attachments.h +++ b/cpp/src/attachments.h @@ -1,124 +1,124 @@ // // Created by pgess on 3/15/15. // #ifndef _XREATE_ATTACHMENTS_H_ #define _XREATE_ATTACHMENTS_H_ #include #include #include namespace xreate { //Attachments dictionary template struct AttachmentsDict { // typedef void Data; - // static const unsigned int key (current unreserved - 5); + // static const unsigned int key (current unreserved - 6); }; template struct AttachmentsStorage { //static Attachments* get(const T&); }; namespace detail { 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); } template typename std::enable_if::value, void*>::type __wrap(const Typ& value){ Typ* holder = new Typ(value); return holder; } template typename std::enable_if::value, Typ&>::type __unwrap(void* value){ return *reinterpret_cast(value); } template typename std::enable_if::value, void>::type __delete(void* value){ delete reinterpret_cast(value); } template typename std::enable_if::value, void>::type __delete(void* value){ delete reinterpret_cast(value); } } //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); } 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); return detail::__unwrap>(self->get(key)); } template static bool exists(const Holder& holder) { const unsigned int key = AttachmentsDict::key; Attachments* self = AttachmentsStorage::get(holder); return self->exists(key); } private: std::map __data; 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/clasplayer.cpp b/cpp/src/clasplayer.cpp index c1a6b7c..76509c6 100644 --- a/cpp/src/clasplayer.cpp +++ b/cpp/src/clasplayer.cpp @@ -1,274 +1,279 @@ #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 + + 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(); - this->dataDFA->print(__partGeneral); - this->dataCFA->print(__partGeneral); - + 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->handlerSolution(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 + + size_t ClaspLayer::getScopesCount() const{ return __registryScopes.size(); } SymbolPacked ClaspLayer::pack(const Symbol& symbol, std::string hintSymbolName) { SymbolPacked result; result.scope = pack(symbol.scope); result.identifier = symbol.identifier; __indexSymbolNameHints.emplace(result, hintSymbolName); return result; } - + Symbol ClaspLayer::unpack(const SymbolPacked& symbol) { return Symbol{symbol.identifier, __registryScopes[symbol.scope]}; }; std::string ClaspLayer::getHintForPackedSymbol(const SymbolPacked& symbol){ 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); } } diff --git a/cpp/src/clasplayer.h b/cpp/src/clasplayer.h index 76d83f3..ad8da19 100644 --- a/cpp/src/clasplayer.h +++ b/cpp/src/clasplayer.h @@ -1,227 +1,227 @@ #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 = false; }; 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 handlerSolution(Gringo::Model const &model); + 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 diff --git a/cpp/src/compilation/advanced.cpp b/cpp/src/compilation/advanced.cpp index db651c0..ba70f84 100644 --- a/cpp/src/compilation/advanced.cpp +++ b/cpp/src/compilation/advanced.cpp @@ -1,449 +1,449 @@ /* * 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 "query/ptrvalid.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::compileMapSolid(const Expression &expr, const std::string hintRetVar) { EXPAND_CONTEXT //initialization std::string varIn = expr.getOperands()[0].getValueString(); Symbol symbolIn = scope->scope->findSymbol(varIn); ImplementationRec implIn = containers::Query::queryImplementation(symbolIn).extract(); // impl of input list size_t size = implIn.size; CodeScope* scopeLoop = expr.blocks.front(); std::string varEl = scopeLoop->__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(const Symbol &dataSymbol, std::vector indexes, std::string hintRetVar) { EXPAND_CONTEXT UNUSED(function); //TODO find out symbol identifier in order to name it in raw llvm; llvm::Value* data = scope->compileSymbol(dataSymbol); const Expression& decl = CodeScope::findDeclaration(dataSymbol); //TODO review array index compilation strategy if (decl.op == Operator::LIST) { assert(indexes.size() == 1); return llvm->builder.CreateExtractElement(data, indexes[0], NAME("el")); } indexes.insert(indexes.begin(), llvm::ConstantInt::get(tyNum, 0)); Value *pEl = llvm->builder.CreateGEP(data, llvm::ArrayRef(indexes)); return llvm->builder.CreateLoad(pEl, NAME("el")); } Value* 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 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: not null ptr // SECTIONTAG validptr exception Symbol s; if (! QueryPtrValid::assertValidPtr(s)){ PointerType* tyAggr = dyn_cast(aggregate->getType()); llvm::Value* null = llvm::ConstantPointerNull::get(tyAggr); Value* condNull = llvm->builder.CreateICmpNE(aggregate, null); llvm::BasicBlock *blockException = llvm::BasicBlock::Create(llvm::getGlobalContext(), "exception", function->raw); llvm->builder.CreateCondBr(condNull, blockSafe, blockException); llvm->initExceptionBlock(blockException); } llvm->builder.SetInsertPoint(blockSafe); std::vector indexes; //dereference pointer if (types.isPointer(t)){ indexes.push_back(zero); } indexes.push_back(ConstantInt::get(tyInt, i)); Value* addr = llvm->builder.CreateGEP(aggregate, indexes); return llvm->builder.CreateLoad(addr); } } assert(false && "not found required struct field"); 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(scope); UNUSED(function); assert(exprSwitch.operands.size() >= 2); - assert(exprSwitch.operands[1].op == Operator::CASE_DEFAULT); + 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; iraw); llvm::Value* condCase = function->getScopeUnit(exprSwitch.operands[i].blocks.front())->compile(); builder.SetInsertPoint(blockCase); llvm::Value* resultCase = function->getScopeUnit(exprSwitch.operands[i].blocks.back())->compile(); builder.CreateBr(blockEpilog); ret->addIncoming(resultCase, builder.GetInsertBlock()); builder.SetInsertPoint(blockProlog); instructionSwitch->addCase(dyn_cast(condCase), blockCase); } //compile default block: builder.SetInsertPoint(blockDefault); CodeScope* scopeDefault = exprSwitch.operands[1].blocks.front(); llvm::Value* resultDefault = function->getScopeUnit(scopeDefault)->compile(); builder.CreateBr(blockEpilog); ret->addIncoming(resultDefault, builder.GetInsertBlock()); builder.SetInsertPoint(blockEpilog); return ret; } llvm::Value* Advanced::compileConstantArray(const Expression &expr, const std::string& hintRetVar) { EXPAND_CONTEXT UNUSED(scope); UNUSED(function); const size_t& __size = expr.getOperands().size(); const Expression& __data = expr; ArrayType* typList = (ArrayType*) (llvm->toLLVMType(ExpandedType(TypeAnnotation(tag_array, TypePrimitive::I32, __size)))); Type*typI32 = llvm->toLLVMType(ExpandedType(TypeAnnotation(TypePrimitive::I32))); std::vector list; list.reserve(__size); const std::vector operands = __data.getOperands(); std::transform(operands.begin(), operands.end(), std::inserter(list, list.begin()), [typI32](const Expression& e){return ConstantInt::get(typI32, e.getValueDouble());}); Value* listSource = ConstantArray::get(typList, ArrayRef(list)); /* Value* listDest = l.builder.CreateAlloca(typList, ConstantInt::get(typI32, __size), *hintRetVar); l.buil1der.CreateMemCpy(listDest, listSource, __size, 16); */ return listSource; } llvm::Value* 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/latecontextcompiler.cpp b/cpp/src/compilation/latecontextcompiler.cpp deleted file mode 100644 index 418b655..0000000 --- a/cpp/src/compilation/latecontextcompiler.cpp +++ /dev/null @@ -1,136 +0,0 @@ -/* - * LateContext.cpp - * - * Created on: Jan 8, 2016 - * Author: pgess - */ - -#include "query/context.h" -#include -#include "pass/compilepass.h" -#include "llvmlayer.h" - -namespace xreate { - -LateContextCompiler::LateContextCompiler(const std::string& function, CompilePass* compilePass) - : pass(compilePass) -{} - -LateContextCompiler::~LateContextCompiler() -{} - -llvm::Value* -LateContextCompiler::compileCheckContext(const Expression& e){ -// llvm::Value* environment; -// LLVMLayer* llvm; -// -// PackedExpression rep = __context.pack(e); -// assert(storage.count(rep)); -// -// size_t id = storage.at(rep); -// //TODO determine short name of expression -// return llvm->builder.CreateExtractElement(environment, id, NAME("checkContext"+e.getValueString())); - - return nullptr; -} - -llvm::Value* -LateContextCompiler::findFunction(const std::string name, ScopePacked scopeOuter, llvm::Function* functionOuter){ -/* - * , functionDomain(&compilePass->queryContext->getFunctionDomain(function)) - //RUNTIME PART - llvm::BasicBlock *blockCurrent = llvm->builder.GetInsertBlock(); - llvm::BasicBlock *blockEnd = llvm::BasicBlock::Create(llvm::getGlobalContext(), "ContextDeterminationEnd", functionOuter); - - llvm->builder.SetInsertPoint(blockEnd); - llvm::Type* tyFuncCallee = funcDefault->getType(); - llvm::PHINode *ret = llvm->builder.CreatePHI(tyFuncCallee, functionDomain->size(), "callee"); - - - //check runtime context - for (const ManagedFnPtr& f: specializations){ - const Expression& guard = f->guardContext; - if (!guard.isValid()) continue; - - if (functionDomain->count(guard)){ - ///example: if (domain[c]) return specializtion.at(c) else - llvm->builder.SetInsertPoint(blockCurrent); - //TASK implement `cond` - llvm::Value* cond; - llvm::BasicBlock *blockNext = llvm::BasicBlock::Create(llvm::getGlobalContext(), "ContextDeterminationNext", functionOuter); - llvm->builder.CreateCondBr(cond, blockEnd, blockNext); - ret->addIncoming(pass->getFunctionUnit(f)->compile(), blockCurrent); - blockCurrent = blockNext; - } - } - - //check default variant in runtime - llvm->builder.SetInsertPoint(blockCurrent); - llvm->builder.CreateBr(blockEnd); - ret->addIncoming(funcDefault, blockCurrent); - - llvm->builder.SetInsertPoint(blockEnd); - return ret; - - */ return nullptr; -} - -llvm::Value* -LateContextCompiler::compileArgument(const std::string& callee, ScopePacked scopeOuter){ - /* - LLVMLayer* llvm = pass->man->llvm; - - std::unordered_set indexContextStatic; - const ContextDomain& listContextStatic = pass->queryContext->getContext(scopeOuter); - const ContextDomain& calleeDomain = pass->queryContext->getFunctionDomain(callee); - - llvm::Type* tyBool = llvm::Type::getInt1Ty(llvm::getGlobalContext()); - llvm::Type* tyInt32 = llvm::Type::getInt32Ty(llvm::getGlobalContext()); - - llvm::Value* result = llvm->builder.CreateAlloca(tyBool, llvm::ConstantInt::get(tyInt32, calleeDomain.size())); - llvm::Value* valueTrue = llvm::ConstantInt::get(tyBool, 1); - llvm::Value* valueFalse = llvm::ConstantInt::get(tyBool, 0); - - for (const Expression& e: listContextStatic){ - auto i = calleeDomain.getId(e); //TODO it is like iteration 0..size-1, right? - if (i){ - result = llvm->builder.CreateInsertElement(result, llvm::ConstantInt::get(tyInt32, *i), valueTrue); - indexContextStatic.insert(*i); - } - } - - for (size_t i=0, size=calleeDomain.size(); igetExpressionId(e); - if (posPrev){ - llvm::Value* element = llvm->builder.CreateExtractElement(raw, llvm::ConstantInt::get(tyInt32, *posPrev)); - result = llvm->builder.CreateInsertElement(result, llvm::ConstantInt::get(tyInt32, i), element); - continue; - } - - result = llvm->builder.CreateInsertElement(result, llvm::ConstantInt::get(tyInt32, i), valueFalse); - } - - return result; - */ - - return nullptr; -} - -size_t -LateContextCompiler::getFunctionDomainSize() const { - return pass->queryContext->getFunctionDomain(functionName).size(); -} - -//void -//LateContext::set(const Expression& e){ -// PackedExpression representation = __context.pack(e); -// -// assert(__context.count(representation) == 0); -// __context.emplace(move(representation), __context.size()); -//} - -} /* namespace xreate */ diff --git a/cpp/src/compilation/latecontextcompiler.h b/cpp/src/compilation/latecontextcompiler.h deleted file mode 100644 index e3f6a2e..0000000 --- a/cpp/src/compilation/latecontextcompiler.h +++ /dev/null @@ -1,45 +0,0 @@ -/* - * LateContext.h - * - * Created on: Jan 8, 2016 - * Author: pgess - */ - -#ifndef SRC_COMPILATION_LATECONTEXTCOMPILER_H_ -#define SRC_COMPILATION_LATECONTEXTCOMPILER_H_ - -#include "ast.h" - -namespace llvm { - class Value; - class Function; -} - -namespace xreate { -typedef unsigned int ScopePacked; - -class CompilePass; - -//SECTIONTAG late-context compilation logic wrt late context - -class LateContextCompiler{ - -public: - LateContextCompiler(const std::string& function, CompilePass* compilePass); - ~LateContextCompiler(); - - llvm::Value* compileCheckContext(const Expression& e); - llvm::Value* compileArgument(const std::string& callee, ScopePacked scopeOuter); - llvm::Value* findFunction(const std::string name, ScopePacked scopeOuter, llvm::Function* functionOuter); - size_t getFunctionDomainSize() const; - - llvm::Value* raw = nullptr; - -private: - std::string functionName; - CompilePass* pass; -}; - -} /* namespace xreate */ - -#endif /* SRC_COMPILATION_LATECONTEXTCOMPILER_H_ */ diff --git a/cpp/src/compilation/latecontextcompiler2.cpp b/cpp/src/compilation/latecontextcompiler2.cpp new file mode 100644 index 0000000..7008044 --- /dev/null +++ b/cpp/src/compilation/latecontextcompiler2.cpp @@ -0,0 +1,193 @@ +/* + * 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 new file mode 100644 index 0000000..abb12e1 --- /dev/null +++ b/cpp/src/compilation/latecontextcompiler2.h @@ -0,0 +1,51 @@ +/* + * 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/targetinterpretation.cpp b/cpp/src/compilation/targetinterpretation.cpp index fceda31..90c48fb 100644 --- a/cpp/src/compilation/targetinterpretation.cpp +++ b/cpp/src/compilation/targetinterpretation.cpp @@ -1,354 +1,447 @@ /* * File: targetinterpretation.cpp * Author: pgess * * Created on June 29, 2016, 6:45 PM */ #include "compilation/targetinterpretation.h" #include "pass/interpretationpass.h" +#include "llvmlayer.h" +#include +#include using namespace std; namespace xreate{ namespace compilation { const Expression EXPRESSION_FALSE = Expression(Atom(0)); const Expression EXPRESSION_TRUE = Expression(Atom(1)); //Expression //InterpretationScope::compile(const Expression& expression){} CodeScope* InterpretationScope::processOperatorIf(const Expression& expression){ const Expression& exprCondition = process(expression.getOperands()[0]); if (exprCondition == EXPRESSION_TRUE){ return expression.blocks.front(); } return expression.blocks.back(); } CodeScope* InterpretationScope::processOperatorSwitch(const Expression& expression) { const Expression& exprCondition = process(expression.operands[0]); bool flagHasDefault = expression.operands[1].op == Operator::CASE_DEFAULT; //TODO check that one and only one case variant is appropriate for (size_t size = expression.operands.size(), i= flagHasDefault? 2: 1; igetScope(exprCase.blocks.front())->processScope() == exprCondition){ return exprCase.blocks.back(); } } if (flagHasDefault){ const Expression& exprCaseDefault = expression.operands[1]; return exprCaseDefault.blocks.front(); } assert(false && "Switch has no appropriate variant"); return nullptr; } llvm::Value* InterpretationScope::compileHybrid(const InterpretationOperator& op, const Expression& expression, const Context& context){ switch(op){ case IF_INTERPRET_CONDITION: { CodeScope* scopeResult = processOperatorIf(expression); llvm::Value* result = context.function->getScopeUnit(scopeResult)->compile(); return result; } case SWITCH_INTERPRET_CONDITION:{ CodeScope* scopeResult = processOperatorSwitch(expression); llvm::Value* result = context.function->getScopeUnit(scopeResult)->compile(); return result; } case FOLD_INTERPRET_INPUT: { //initialization const Expression& exprInput = process(expression.getOperands()[0]); assert(exprInput.op == Operator::LIST); CodeScope* scopeBody = expression.blocks.front(); const string& nameEl = expression.bindings[0]; 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(); for (size_t i=0; ireset(); - intrBody->bindArg(exprElement, nameEl); + intrBody->overrideBinding(exprElement, nameEl); unitBody->overrideDeclaration(symbolEl, move(exprElement)); unitBody->bindArg(rawAccum, string(idAccum)); rawAccum = unitBody->compile(); } return rawAccum; } + 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; + + for(size_t no=0, size = expression.operands.size(); no < size; ++no){ + const Expression& op = expression.operands[no]; + + if (calleeData.signature.at(no) == INTR_ONLY){ + sig.bindings.push_back(process(op)); + continue; + } + + argsActual.push_back(scopeUnitSelf->process(op)); + } + + TargetInterpretation* man = dynamic_cast(this->function->man); + PIFunction* pifunction = man->getFunction(move(sig)); + + llvm::Function* raw = pifunction->compile(); + boost::scoped_ptr statement(new CallStatementRaw(raw, man->pass->man->llvm)); + return (*statement)(move(argsActual)); + } + default: break; } assert(false&& "Unknown hybrid operator"); return nullptr; } llvm::Value* InterpretationScope::compile(const Expression& expression, const Context& context){ const InterpretationData& data = Attachments::get(expression); if (data.op != InterpretationOperator::NONE){ return compileHybrid(data.op, expression, context); } Expression result = process(expression); return context.scope->processLowlevel(result); } Expression InterpretationScope::process(const Expression& expression){ switch (expression.__state){ case Expression::VARIANT: case Expression::INVALID: assert(false); case Expression::NUMBER: case Expression::STRING: return expression; case Expression::IDENT:{ const std::string &ident = expression.getValueString(); Symbol s = scope->findSymbol(ident); return Parent::processSymbol(s); } case Expression::COMPOUND: break; default: assert(false); } switch (expression.op) { case Operator::EQU: { const Expression& left = process(expression.operands[0]); const Expression& right = process(expression.operands[1]); if (left == right) return EXPRESSION_TRUE; return EXPRESSION_FALSE; } case Operator::NE: { const Expression& left = process(expression.operands[0]); const Expression& right = process(expression.operands[1]); if (left == right) return EXPRESSION_FALSE; return EXPRESSION_TRUE; } case Operator::LOGIC_AND: { assert(expression.operands.size() == 1); return process (expression.operands[0]); } // case Operator::LOGIC_OR: case Operator::CALL: { const std::string &fnName = expression.getValueString(); ManagedFnPtr fnAst = this->function->man->ast->findFunction(fnName); InterpretatonFunction* fnUnit = this->function->man->getFunction(fnAst); vector args; args.reserve(expression.getOperands().size()); for(size_t i=0, size = expression.getOperands().size(); iprocess(args); } case Operator::IF:{ CodeScope* scopeResult = processOperatorIf(expression); return function->getScope(scopeResult)->processScope(); } case Operator::SWITCH: { CodeScope* scopeResult = processOperatorSwitch(expression); return function->getScope(scopeResult)->processScope(); } case Operator::INDEX: { const Expression& exprKey = process(expression.operands[0]); const Expression& exprData = processSymbol(scope->findSymbol(expression.getValueString())); if (exprKey.__state == Expression::STRING){ const string& key = exprKey.getValueString(); assert(exprData.__indexBindings.count(key)); return exprData.operands[exprData.__indexBindings.at(key)]; } if (exprKey.__state == Expression::NUMBER){ int key = exprKey.getValueDouble(); return exprData.operands[key]; } assert(false); } case Operator::FOLD: { const Expression& exprInput = process(expression.getOperands()[0]); const Expression& exprInit = process(expression.getOperands()[1]); const std::string& argEl = expression.bindings[0]; const std::string& argAccum = expression.bindings[1]; InterpretationScope* body = function->getScope(expression.blocks.front()); Expression accum = exprInit; for(size_t size=exprInput.getOperands().size(), i=0; ibindArg(exprInput.getOperands()[i], argEl); - body->bindArg(accum, argAccum); + body->overrideBinding(exprInput.getOperands()[i], argEl); + body->overrideBinding(accum, argAccum); accum = body->processScope(); } return accum; } // case Operator::MAP: { // break; // } default: break; } return expression; } -InterpretatonFunction::InterpretatonFunction(const ManagedFnPtr& function, Target* target) - : Function(function, target) -{} +InterpretatonFunction* +TargetInterpretation::getFunction(FunctionUnit* unit){ + if (__dictFunctionsByUnit.count(unit)) { + return __dictFunctionsByUnit.at(unit); + } -Expression -InterpretatonFunction::process(const std::vector& args){ - InterpretationScope* body = getScope(__function->__entry); + InterpretatonFunction* f = new InterpretatonFunction(unit->function, this); + __dictFunctionsByUnit.emplace(unit, f); + assert(__functions.emplace(unit->function.id(), f).second); - for(size_t i=0, size = args.size(); ibindArg(args.at(i), string(body->scope->__bindings.at(i))); + return f; +} + +PIFunction* +TargetInterpretation::getFunction(PIFSignature&& sig){ + + auto f = __pifunctions.find(sig); + if (f != __pifunctions.end()){ + return *f; } - return body->processScope(); -} + PIFunction* result = new PIFunction(move(sig), __pifunctions.size(), this); + __pifunctions.insert(result); + assert(__dictFunctionsByUnit.emplace(result->functionUnit, result).second); -InterpretatonFunction* -TargetInterpretation::getFunction(const PIFSignature& sig){ - return __functions.find(sig); + return result; } InterpretationScope* TargetInterpretation::transformContext(const Context& c){ - return this->getFunction(c.function->function)->getScope(c.scope->scope); + 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){ return transformContext(ctx)->compile(expression, ctx); } bool TargetInterpretation::isAcceptable(const Expression& expression){ - const InterpretationData& data = Attachments::get(expression, {BOTH, NONE}); + const InterpretationData& data = Attachments::get(expression, {ANY, NONE}); return (data.resolution == INTR_ONLY || data.op != InterpretationOperator::NONE); } -}} - - //Partial function interpretation -llvm::Value* -InterpretationScope::compilePartialFnCall(const Expression& expression, const Context& context){ - const std::string &fnName = expression.getValueString(); - ManagedFnPtr fnAst = this->function->man->ast->findFunction(fnName); - context.pass->getFunctionUnit(fnAst) - - intrBody->bindArg(exprElement, nameEl); - unitBody->overrideDeclaration(symbolEl, move(exprElement)); -} +InterpretatonFunction::InterpretatonFunction(const ManagedFnPtr& function, Target* target) + : Function(function, target) +{} -class PartialInterpretationScopeDecorator(){ - void compile(){ +Expression +InterpretatonFunction::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))); } - void findFunction(){ + return body->processScope(); +} - } -}; +// Partial function interpretation + +typedef BasicFunctionDecorator PIFunctionUnitParent; +class PIFunctionUnit: public PIFunctionUnitParent{ +public: -template -class PartialInterpretationFunctionDecorator: public Parent{ + PIFunctionUnit(ManagedFnPtr f, std::set&& arguments, size_t id, CompilePass* p) + : PIFunctionUnitParent(f, p), argumentsActual(move(arguments)), __id(id) + {} protected: - void recognizeArguments(){ - argsReal.reserve(entry->__bindings.size()); + std::vector prepareArguments(){ + LLVMLayer* llvm = PIFunctionUnitParent::pass->man->llvm; + AST* ast = PIFunctionUnitParent::pass->man->root; + CodeScope* entry = PIFunctionUnitParent::function->__entry; + std::vector signature; - 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)); + for(size_t no: argumentsActual){ + Symbol arg = entry->findSymbol(entry->__bindings[no]); - InterpretationResolution res = recognizeTags(arg.tags); - if (res != INTR_ONLY){ - argsReal.push_back(arg); - } + signature.push_back(llvm->toLLVMType(ast->expandType(entry->__declarations[arg.identifier].type))); } + + return signature; } - std::vector prepareArguments(){ - std::vector signature; + llvm::Function::arg_iterator prepareBindings(){ + CodeScope* entry = PIFunctionUnitParent::function->__entry; + CodeScopeUnit* entryCompilation = PIFunctionUnitParent::getScopeUnit(entry); + llvm::Function::arg_iterator fargsI = PIFunctionUnitParent::raw->arg_begin(); - for(size_t no=0, size=argsReal.size(); no < size; ++no){ - signature.push_back(llvm->toLLVMType(ast->expandType(argsReal[no].type))); + for(size_t no: argumentsActual){ + Symbol arg = entry->findSymbol(entry->__bindings[no]); + + entryCompilation->__rawVars[arg.identifier] = &*fargsI; + fargsI->setName(entry->__bindings[no]); + ++fargsI; } + + return fargsI; } - void prepareBindings(){ - // bindings from argsReal + virtual std::string prepareName(){ + return PIFunctionUnitParent::prepareName() + "_" + std::to_string(__id); } private: - std::vector argsReal; + std::set argumentsActual; + size_t __id; }; -template -class PartialInterpretationCallStatement: public Parent { - PartialInterpretationCallStatement(){ +PIFunction::PIFunction(PIFSignature&& sig, size_t id, TargetInterpretation* target) + : InterpretatonFunction(sig.declaration, target), signatureInstance(move(sig)) +{ + const FunctionInterpretationData& functionData = FunctionInterpretationHelper::getSignature(signatureInstance.declaration); + + std::set argumentsActual; + for (size_t no=0, size=functionData.signature.size(); no < size; ++no){ + if (functionData.signature.at(no) != INTR_ONLY){ + argumentsActual.insert(no); + } + } + + functionUnit = new PIFunctionUnit(signatureInstance.declaration, move(argumentsActual), id, target->pass); + CodeScope* entry = signatureInstance.declaration->__entry; + CodeScopeUnit* entryUnit = functionUnit->getEntry(); + InterpretationScope* entryIntrp = InterpretatonFunction::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])); + ++sigNo; + } } -} \ No newline at end of file +} + +llvm::Function* +PIFunction::compile(){ + llvm::Function* raw = functionUnit->compile(); + + return raw; +} + +bool operator<(const PIFSignature& lhs, const PIFSignature& rhs){ + if (lhs.declaration.id() != rhs.declaration.id()) { + return lhs.declaration.id() < rhs.declaration.id(); + } + + return lhs.bindings < rhs.bindings; +} + +bool operator<(const PIFSignature& lhs, PIFunction* const rhs){ + return lhs < rhs->signatureInstance; +} + +bool operator<(PIFunction* const lhs, const PIFSignature& rhs){ + return lhs->signatureInstance < rhs; +} + +}} + diff --git a/cpp/src/compilation/targetinterpretation.h b/cpp/src/compilation/targetinterpretation.h index 94c44d8..2d7444e 100644 --- a/cpp/src/compilation/targetinterpretation.h +++ b/cpp/src/compilation/targetinterpretation.h @@ -1,100 +1,117 @@ /* * 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: targetstatic.h * Author: pgess * * Created on July 2, 2016, 1:25 PM */ #ifndef TARGETSTATIC_H #define TARGETSTATIC_H #include "ast.h" #include "compilation/targets.h" #include "transformations.h" #include "pass/interpretationpass.h" namespace xreate{ namespace compilation { class TargetInterpretation; class InterpretationScope; class InterpretatonFunction; template <> struct TargetInfo { typedef Expression Result; typedef InterpretationScope Scope; typedef InterpretatonFunction Function; }; template<> struct TransformerInfo { static const int id = 1; }; class InterpretationScope: public Scope{ typedef Scope Parent; public: InterpretationScope(CodeScope* scope, Function* f): Parent(scope, f) {} Expression process(const Expression& expression) override; llvm::Value* compile(const Expression& expression, const Context& context); private: llvm::Value* compileHybrid(const InterpretationOperator& op, const Expression& expression, const Context& context); - llvm::Value* compilePartialFnCall(const Expression& expression, const Context& context); + //llvm::Value* compilePartialFnCall(const Expression& expression, const Context& context); CodeScope* processOperatorIf(const Expression& expression); CodeScope* processOperatorSwitch(const Expression& expression); - }; class InterpretatonFunction: public Function{ - public: - PIFSignature signature; - - InterpretatonFunction(const ManagedFnPtr& function, Target* target); - Expression process(const std::vector& args); +public: + InterpretatonFunction(const ManagedFnPtr& function, Target* target); + Expression process(const std::vector& args); }; -/* +/* * Partially interpreted function signature */ struct PIFSignature{ ManagedFnPtr declaration; std::vector bindings; }; -class TargetInterpretation: public Transformer, public Target{ +class PIFunctionUnit; + +class PIFunction: public InterpretatonFunction{ +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{ public: - TargetInterpretation(AST* root): Target(root){} + 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: - InterpretatonFunction* getFunction(const ManagedFnPtr& function); + InterpretatonFunction* getFunction(FunctionUnit* unit); + PIFunction* getFunction(PIFSignature&& sig); + private: - std::set __functions; + std::set> __pifunctions; + std::map __dictFunctionsByUnit; //self: public: + CompilePass* pass; llvm::Value* compile(const Expression& expression, const Context& ctx); private: InterpretationScope* transformContext(const Context& c); }; + + }} #endif /* TARGETSTATIC_H */ diff --git a/cpp/src/compilation/targets.h b/cpp/src/compilation/targets.h index fb10bec..b1821e3 100644 --- a/cpp/src/compilation/targets.h +++ b/cpp/src/compilation/targets.h @@ -1,146 +1,156 @@ /* * File: targetabstract.h * Author: pgess * * Created on July 2, 2016, 1:25 PM */ #ifndef TARGETABSTRACT_H #define TARGETABSTRACT_H #include "ast.h" #include #include namespace xreate{ namespace compilation { template struct TargetInfo{ //typedef Result //typedef Function //typedef Scope }; template class Function; template class Target; template class Scope{ public: CodeScope* scope; typename TargetInfo::Result processSymbol(const Symbol& s){ CodeScope* scope = s.scope; typename TargetInfo::Scope* self = function->getScope(scope); if (self->__bindings.count(s.identifier)) { return self->__bindings[s.identifier]; } const Expression& declaration = CodeScope::findDeclaration(s); 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->__body); + raw = process(scope->getBody()); return *raw; } +// 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(codeScope), function(f) {} virtual ~Scope(){} void - bindArg(typename TargetInfo::Result arg, const std::string& name){ + overrideBinding(typename TargetInfo::Result arg, const std::string& name){ assert(scope->__identifiers.count(name)); VID id = scope->__identifiers.at(name); __bindings[id] = arg; //reset the result if any: raw.reset(); } protected: - Function* function; + Function* function=0; std::map::Result> __bindings; typename boost::optional::Result> raw; //ResultType findFunction(const std::string& callee); }; template class Function{ typedef typename TargetInfo::Result Result; public: Function(const ManagedFnPtr& function, Target* target) : man(target), __function(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)); } return __scopes.at(scope).get(); } virtual Result process(const std::vector& args)=0; - Target* man; - -protected: + Target* man=0; ManagedFnPtr __function; - +protected: std::map::Scope>> __scopes; }; 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, std::unique_ptr(unit)); return unit; } return __functions.at(id).get(); } AST* ast; + virtual ~Target(){} - private: + protected: std::map> __functions; }; }} #endif /* TARGETABSTRACT_H */ diff --git a/cpp/src/pass/abstractpass.cpp b/cpp/src/pass/abstractpass.cpp index ec136fd..fc4e19f 100644 --- a/cpp/src/pass/abstractpass.cpp +++ b/cpp/src/pass/abstractpass.cpp @@ -1,35 +1,35 @@ #include "abstractpass.h" #include "attachments.h" #include "passmanager.h" using namespace std; namespace xreate { template<> void defaultValue(){} void AbstractPassBase::finish(){} AbstractPassBase::AbstractPassBase(PassManager *manager) : man(manager) { } template<> void AbstractPass::processSymbol(const std::string& ident, PassContext context) { const Symbol& symbol = context.scope->findSymbol(ident); if (__visitedSymbols.isCached(symbol)) return; __visitedSymbols.setCachedValue(symbol); const Expression& declaration = CodeScope::findDeclaration(symbol); if (declaration.isDefined()){ PassContext context2 = context.updateScope(symbol.scope); process(declaration, context2, ident); } } -} +} \ No newline at end of file diff --git a/cpp/src/pass/abstractpass.h b/cpp/src/pass/abstractpass.h index 5595004..328a916 100644 --- a/cpp/src/pass/abstractpass.h +++ b/cpp/src/pass/abstractpass.h @@ -1,194 +1,201 @@ #ifndef ABSTRACTPASS_H #define ABSTRACTPASS_H #include "ast.h" #include "passmanager.h" #include namespace xreate { struct PassContext { CodeScope* scope = 0; ManagedFnPtr function; ManagedRulePtr rule; std::string varDecl; PassContext() {} PassContext&& updateScope(CodeScope* scopeNew) { PassContext context2{*this}; context2.scope = scopeNew; return std::move(context2); } ~PassContext(){} }; class AbstractPassBase { public: AbstractPassBase(PassManager* manager); virtual void run()=0; virtual void finish(); PassManager* man; }; template Output defaultValue(); template<> void defaultValue(); template class SymbolCache: private std::map{ public: bool isCached(const Symbol& symbol){ return this->count(symbol); } Output setCachedValue(const Symbol& symbol, Output&& value){ - this->emplace(symbol, value); + (*this)[symbol] = value; return value; } Output getCachedValue(const Symbol& symbol){ assert(this->count(symbol)); return this->at(symbol); } }; template<> class SymbolCache: private std::set{ public: bool isCached(const Symbol& symbol){ bool result = this->count(symbol) > 0; return result; } void setCachedValue(const Symbol& symbol){ this->insert(symbol); } void getCachedValue(const Symbol& symbol){ } }; template class AbstractPass: public AbstractPassBase { 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){} - //NOTE implement processFnCall - virtual void processFnCall(ManagedFnPtr function, PassContext context) - {} + virtual Output processFnCall(ManagedFnPtr function, PassContext context){ + return defaultValue(); + } virtual void processFnCallUncertain(ManagedFnPtr function, PassContext context) - {} + {} virtual void process(ManagedRulePtr rule) - {} + {} - virtual Output process(ManagedFnPtr function){ - const Symbol& symbolFunction{0, function->getEntryScope()}; - - if (__visitedSymbols.isCached(symbolFunction)) - return __visitedSymbols.getCachedValue(symbolFunction); - + virtual Output process(ManagedFnPtr function) + { PassContext context; context.function = function; - + return process(function->getEntryScope(), context); - } + } virtual Output process(CodeScope* scope, PassContext context, const std::string& hintBlockDecl=""){ context.scope = scope; - return process(scope->__body, context); + return process(scope->getBody(), 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; } return defaultValue(); } void run() { ManagedRulePtr rule = man->root->begin(); while (rule.isValid()) { process(rule); ++rule; } ManagedFnPtr f = man->root->begin(); while (f.isValid()) { process(f); ++f; } } }; template<> void AbstractPass::processSymbol(const std::string& ident, PassContext context); } #endif + +//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 diff --git a/cpp/src/pass/adhocpass.cpp b/cpp/src/pass/adhocpass.cpp index ef9d1eb..65cde19 100644 --- a/cpp/src/pass/adhocpass.cpp +++ b/cpp/src/pass/adhocpass.cpp @@ -1,81 +1,81 @@ /* * adhoc.cpp * * Created on: Nov 28, 2015 * Author: pgess */ #include "pass/adhocpass.h" #include "query/context.h" namespace xreate { AdhocScheme* AdhocPass::determineForScope(CodeScope* entry){ 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->__body.operands[0].getValueString(); + 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/compilepass.cpp b/cpp/src/pass/compilepass.cpp index 6c52cee..19129be 100644 --- a/cpp/src/pass/compilepass.cpp +++ b/cpp/src/pass/compilepass.cpp @@ -1,812 +1,827 @@ #include "compilepass.h" #include "clasplayer.h" -#include "llvmlayer.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 "compilation/targetinterpretation.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; } -CodeScopeUnit::CodeScopeUnit(CodeScope* codeScope, FunctionUnit* f, CompilePass* compilePass) - : scope(codeScope), pass(compilePass), function(f) -{} +std::string +BasicFunctionDecorator::prepareName(){ + AST* ast = FunctionUnit::pass->man->root; + + string name = ast->getFunctionVariants(FunctionUnit::function->__name).size() > 1? + FunctionUnit::function->__name + std::to_string(FunctionUnit::function.id()) : + FunctionUnit::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; + 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)); + + VID argid = entry->__identifiers.at(arg); + 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; + + return llvm->toLLVMType(ast->expandType(entry->__declarations[0].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(); + + for (std::string &arg : entry->__bindings) { + VID argid = entry->__identifiers[arg]; + + entryCompilation->__rawVars[argid] = &*fargsI; + 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) + {} + +protected: + std::vector prepareArguments(){ + std::vector&& arguments = Parent::prepareArguments(); + + size_t sizeLateContextDemand = contextCompiler.getFunctionDemandSize(); + if (sizeLateContextDemand) { + llvm::Type* ty32 = llvm::Type::getInt32Ty(llvm::getGlobalContext()); + llvm::Type* tyDemand = llvm::ArrayType::get(ty32, sizeLateContextDemand); + + arguments.push_back(tyDemand); + } + + return arguments; + } + llvm::Function::arg_iterator prepareBindings(){ + llvm::Function::arg_iterator fargsI = Parent::prepareBindings(); + + size_t sizeLateContextDemand = contextCompiler.getFunctionDemandSize(); + if (sizeLateContextDemand){ + fargsI->setName("latecontext"); + contextCompiler.rawContextArgument = &*fargsI; + ++fargsI; + } + + return fargsI; + } -class CallStatement { public: - virtual llvm::Value* operator() (std::vector&& args, const std::string& hintDecl, llvm::IRBuilder<>&) = 0; + LateContextCompiler2 contextCompiler; + }; -class CallStatementRaw: public CallStatement{ +//SECTIONTAG adhoc FunctionDecorator +template +class AdhocFunctionDecorator: public Parent{ public: - CallStatementRaw(llvm::Function* callee): __callee(callee) {} + AdhocFunctionDecorator(ManagedFnPtr f, CompilePass* p) + : Parent(f, p) {} - llvm::Value* operator() (std::vector&& args, const std::string& hintDecl, llvm::IRBuilder<>& builder) { - auto argsFormal = __callee->args(); +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)); - 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(), builder); - } + if (! Parent::function->isPrefunction){ + return Parent::prepareResult(); + } - return builder.CreateCall(__callee, args, hintDecl); - } + adhocImplementation = adhocpass->determineForScope(entry); + return llvm->toLLVMType(ast->expandType(adhocImplementation->getResultType())); + } + +public: + AdhocScheme* adhocImplementation=nullptr; -private: - llvm::Function* __callee; }; -//TASK implement inlining +typedef LateContextFunctionDecorator< + AdhocFunctionDecorator< + BasicFunctionDecorator>> DefaultFunctionUnit; + + +CodeScopeUnit::CodeScopeUnit(CodeScope* codeScope, FunctionUnit* f, CompilePass* compilePass) + : scope(codeScope), pass(compilePass), function(f) +{} + + +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 llvm->builder.CreateCall(__calleeTy, __callee, args, hintDecl); +} + +//DEBT implement inlining class CallStatementInline: public CallStatement{ public: - CallStatementInline(FunctionUnit* caller, FunctionUnit* callee) - : __caller(caller), __callee(callee) {} + CallStatementInline(FunctionUnit* caller, FunctionUnit* callee, LLVMLayer* l) + : __caller(caller), __callee(callee), llvm(l) {} - llvm::Value* operator() (std::vector&& args, const std::string& hintDecl, llvm::IRBuilder<>& builder) { + 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; } }; -template -class CallStatementLateContext: public CallStatement{ - { - if (specializations.size()< 2){ - return Parent... - } - - - - - - - - } - -}; } void CodeScopeUnit::overrideDeclaration(const Symbol binding, Expression&& declaration){ function->getScopeUnit(binding.scope)->__declarationsOverriden.emplace(binding.identifier, move(declaration)); } -class ScopeDecorator{ - -}; - //SECTIONTAG late-context find callee function //TOTEST static late context decisions //TOTEST dynamic late context decisions CallStatement* CodeScopeUnit::findFunction(const std::string& calleeName){ 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); //if no specializations registered - check external function if (specializations.size()==0){ llvm::Function* external = llvm->layerExtern->lookupFunction(calleeName); - return new CallStatementRaw(external); + return new CallStatementRaw(external, llvm); } //no decisions required if (specializations.size()==1){ if (!specializations.front()->guardContext.isValid()) { - return new CallStatementRaw( pass->getFunctionUnit(specializations.front())->compile()); + return new CallStatementRaw( pass->getFunctionUnit(specializations.front())->compile(), llvm); } } //TODO move dictSpecialization over to a separate function in order to perform cache, etc. //prepare specializations dictionary std::map dictSpecializations; boost::optional variantDefault; boost::optional variant; for(const ManagedFnPtr& f: specializations){ const Expression& guard = f->guardContext; //default case: if (!guard.isValid()){ variantDefault = f; continue; } assert(dictSpecializations.emplace(guard, f).second && "Found several identical specializations"); } //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))}); const Decisions& decisions = queryContext->getFinalDecisions(scopeCaller); if (decisions.count(topicSpecialization)){ variant = dictSpecializations.at(decisions.at(topicSpecialization)); } //TODO check only demand for this particular topic. - size_t sizeDemand = this->function->contextCompiler.getFunctionDemandSize(); + size_t sizeDemand = function->contextCompiler.getFunctionDemandSize(); //decision made if static context found or no late context exists(and there is default variant) bool flagHasStaticDecision = variant || (variantDefault && !sizeDemand); //if no late context exists if (flagHasStaticDecision) { FunctionUnit* calleeUnit = pass->getFunctionUnit(variant? *variant: *variantDefault); //inlining possible based on static decision only - if (calleeUnit->isInline()) { - return new CallStatementInline(function, calleeUnit); - } +// if (calleeUnit->isInline()) { +// return new CallStatementInline(function, calleeUnit); +// } - return new CallStatementRaw(calleeUnit->compile()); + return new CallStatementRaw(calleeUnit->compile(), llvm); } //require default variant if no static decision made assert(variantDefault); llvm::Function* functionVariantDefault = this->pass->getFunctionUnit(*variantDefault)->compile(); - return new CallStatementRaw(this->function->contextCompiler.findFunction(calleeName, functionVariantDefault, scopeCaller)); + 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); } void CodeScopeUnit::bindArg(llvm::Value* value, std::string&& alias) { //reset cached compiled value if any raw = nullptr; //ensure existing of an alias assert(scope->__identifiers.count(alias)); //memorize new value for an alias VID id = scope->__identifiers.at(alias); __rawVars[id] = value; } llvm::Value* CodeScopeUnit::process(const Expression& expr, const std::string& hintVarDecl){ Context ctx{this, this->function, this->pass}; -// if (pass->targetInterpretation->isAcceptable(expr)){ -// return pass->targetInterpretation->compile(expr, ctx); -// } + if (pass->targetInterpretation->isAcceptable(expr)){ + return pass->targetInterpretation->compile(expr, ctx); + } llvm::Value* result = processLowlevel(expr, hintVarDecl); if (pass->transformations->isAcceptable(expr)){ return pass->transformations->transform(expr, result, ctx); } return result; } 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: assert(expr.__state == Expression::COMPOUND); assert(expr.operands.size() == 2); left = process(expr.operands[0]); right = process(expr.operands[1]); //SECTIONTAG types/convert binary operation right = doAutomaticTypeConversion(right, left->getType(), l.builder); break; default:; } switch (expr.op) { case Operator::ADD: return l.builder.CreateAdd(left, right, DEFAULT("tmp_add")); break; case Operator::SUB: return l.builder.CreateSub(left, right, DEFAULT("tmp_sub")); break; case Operator::MUL: return l.builder.CreateMul(left, right, DEFAULT("tmp_mul")); break; case Operator::DIV: return l.builder.CreateSDiv(left, right, DEFAULT("tmp_div")); break; case Operator::EQU: if (left->getType()->isIntegerTy()) return l.builder.CreateICmpEQ(left, right, DEFAULT("tmp_equ")); if (left->getType()->isFloatingPointTy()) return l.builder.CreateFCmpOEQ(left, right, DEFAULT("tmp_equ")); break; case Operator::NE: return l.builder.CreateICmpNE(left, right, DEFAULT("tmp_ne")); break; case Operator::LSS: return l.builder.CreateICmpSLT(left, right, DEFAULT("tmp_lss")); break; case Operator::LSE: return l.builder.CreateICmpSLE(left, right, DEFAULT("tmp_lse")); break; case Operator::GTR: return l.builder.CreateICmpSGT(left, right, DEFAULT("tmp_gtr")); break; case Operator::GTE: return l.builder.CreateICmpSGE(left, right, DEFAULT("tmp_gte")); break; case Operator::NEG: left = process(expr.operands[0]); return l.builder.CreateNeg(left, DEFAULT("tmp_neg")); break; case Operator::CALL: { assert(expr.__state == Expression::COMPOUND); std::string nameCallee = expr.getValueString(); - unique_ptr callee(findFunction(nameCallee)); + shared_ptr callee(findFunction(nameCallee)); //prepare arguments std::vector args; args.reserve(expr.operands.size()); std::transform(expr.operands.begin(), expr.operands.end(), std::inserter(args, args.end()), [this](const Expression &operand) { return process(operand); } ); ScopePacked outerScopeId = pass->man->clasp->pack(this->scope); + //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); } - return (*callee)(move(args), DEFAULT("res_"+nameCallee), l.builder); + return (*callee)(move(args), DEFAULT("res_"+nameCallee)); } case Operator::IF: { return instructions.compileIf(expr, DEFAULT("tmp_if")); } case Operator::SWITCH: { return instructions.compileSwitch(expr, DEFAULT("tmp_switch")); } case Operator::LOOP_CONTEXT: { return instructions.compileLoopContext(expr, DEFAULT("tmp_loop")); } case Operator::LOGIC_AND: { assert(expr.operands.size() == 1); return process (expr.operands[0]); } case Operator::LIST: { return instructions.compileConstantArray(expr, DEFAULT("tmp_list")); }; case Operator::LIST_RANGE: { assert(false); //no compilation phase for a range list // return InstructionList(this).compileConstantArray(expr, l, hintRetVar); }; case Operator::LIST_NAMED: { typedef Expanded ExpandedType; ExpandedType tyRaw = l.ast->expandType(expr.type); const std::vector fields = (tyRaw.get().__operator == TypeOperator::CUSTOM)? l.layerExtern->getStructFields(l.layerExtern->lookupType(tyRaw.get().__valueCustom)) : tyRaw.get().fields; std::map indexFields; for(size_t i=0, size = fields.size(); i(l.toLLVMType(tyRaw)); llvm::Value* record = llvm::UndefValue::get(tyRecord); for (size_t i=0; igetElementType(fieldId); // result = llvm::UndefValue::get(tyNullField); // // } else { result = process(operand); // } assert (result); record = l.builder.CreateInsertValue(record, result, llvm::ArrayRef({fieldId})); } return record; }; case Operator::MAP: { assert(expr.blocks.size()); return instructions.compileMapSolid(expr, DEFAULT("map")); }; case Operator::FOLD: { return instructions.compileFold(expr, DEFAULT("fold")); }; case Operator::FOLD_INF: { return instructions.compileFoldInf(expr, DEFAULT("fold")); }; case Operator::INDEX: { //TODO allow multiindex assert(expr.operands.size()==1); const std::string &ident = expr.getValueString(); Symbol s = scope->findSymbol(ident); const TypeAnnotation& t = CodeScope::findDeclaration(s).type; const ExpandedType& t2 = pass->man->root->expandType(t); switch (t2.get().__operator) { case TypeOperator::STRUCT: case TypeOperator::CUSTOM: { Expression idx = expr.operands.at(0); assert(idx.__state == Expression::STRING); std::string idxField = idx.getValueString(); llvm::Value* aggr = compileSymbol(s, ident); return instructions.compileStructIndex(aggr, t2, idxField); }; case TypeOperator::ARRAY: { std::vector indexes; std::transform(++expr.operands.begin(), expr.operands.end(), std::inserter(indexes, indexes.end()), [this] (const Expression& op){return process(op);} ); return instructions.compileArrayIndex(s, indexes, 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: { - assert(function->adhocImplementation && "Adhoc implementation not found"); - string comm = expr.operands[0].getValueString(); + DefaultFunctionUnit* function = dynamic_cast(this->function); + assert(function->adhocImplementation && "Adhoc implementation not found"); + string comm = expr.operands[0].getValueString(); + + CodeScope* scope = function->adhocImplementation->getImplementationForCommand(comm); + CodeScopeUnit* unitScope = function->getScopeUnit(scope); - CodeScope* scope = function->adhocImplementation->getImplementationForCommand(comm); - CodeScopeUnit* unitScope = function->getScopeUnit(scope); - return unitScope->compile(); + //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 Operator::SEQUENCE: { assert (expr.getOperands().size()); llvm::Value* result; for(const Expression &op: expr.getOperands()){ result = process(op, ""); } return result; } case Operator::NONE: assert(expr.__state != Expression::COMPOUND); switch (expr.__state) { case Expression::IDENT: { const std::string &ident = expr.getValueString(); Symbol s = scope->findSymbol(ident); return compileSymbol(s, ident); } case Expression::NUMBER: { int literal = expr.getValueDouble(); return llvm::ConstantInt::get(llvm::Type::getInt32Ty(llvm::getGlobalContext()), literal); } case Expression::STRING: { return instructions.compileConstantStringAsPChar(expr.getValueString(), DEFAULT("tmp_str")); }; case Expression::VARIANT: { const ExpandedType& typVariant = pass->man->root->expandType(expr.type); llvm::Type* typRaw = l.toLLVMType(typVariant); int value = expr.getValueDouble(); return llvm::ConstantInt::get(typRaw, value); } default: { break; } }; break; default: break; } assert(false); return 0; } llvm::Value* CodeScopeUnit::compile(const std::string& hintBlockDecl){ if (raw != nullptr) return raw; if (!hintBlockDecl.empty()) { llvm::BasicBlock *block = llvm::BasicBlock::Create(llvm::getGlobalContext(), hintBlockDecl, function->raw); pass->man->llvm->builder.SetInsertPoint(block); } - raw = process(scope->__body); + 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); } -//SECTIONTAG late-context FunctionDecorator -template -class LateContextFunctionDecorator: public Parent{ - - LateContextFunctionDecorator(ManagedFnPtr f, CompilePass* p) - : Parent(f, p), contextCompiler(this, p) - {} - - std::vector prepareArguments(){ - std::vector&& arguments = Parent::prepareArguments(); - - size_t sizeLateContextDemand = contextCompiler.getFunctionDemandSize(); - if (sizeLateContextDemand) { - llvm::Type* ty32 = llvm::Type::getInt32Ty(llvm::getGlobalContext()); - llvm::Type* tyDemand = llvm::ArrayType::get(ty32, sizeLateContextDemand); - - arguments.push_back(tyDemand); - } - return arguments; - } - - void prepareBindings(){ - if (sizeLateContextDemand){ - fargsI->setName("latecontext"); - contextCompiler.rawContextArgument = &*fargsI; - } - } - -protected: - LateContextCompiler2 contextCompiler; -}; - -//SECTIONTAG adhoc FunctionDecorator -template -class AdhocFunctionDecorator: public Parent{ -protected: - llvm::Type* prepareResult(){ - if (! function->isPrefunction){ - return Parent::prepareResult(); - } - - AdhocPass* adhocpass = reinterpret_cast(pass->man->getPassById(PassId::AdhocPass)); - adhocImplementation = adhocpass->determineForScope(entry); - - return llvm->toLLVMType(ast->expandType(adhocImplementation->getResultType())); - } - -private: - AdhocScheme* adhocImplementation=nullptr; //SECTIONTAG adhoc prefunc scheme declaration -}; - -template -class BasicFunctionDecorator: public Decorator{ -protected: - std::string prepareName(){ - string name = ast->getFunctionVariants(function->__name).size() > 1? - function->__name + std::to_string(function.id()) : - function->__name; - - return name; - } - - virtual std::vector prepareArguments(){ - std::vector signature; - std::transform(entry->__bindings.begin(), entry->__bindings.end(), std::inserter(signature, signature.end()), - [this, 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)); - }); - return signature; - } - - virtual llvm::Type* prepareResult(){ - return llvm->toLLVMType(ast->expandType(entry->__declarations[0].type)); - } - - virtual void prepareBindings(){ - CodeScope* entry = function->__entry; - - CodeScopeUnit* entryCompilation = getScopeUnit(entry); - llvm::Function::arg_iterator fargsI = raw->arg_begin(); - for (std::string &arg : entry->__bindings) { - VID argid = entry->__identifiers[arg]; - - entryCompilation->__rawVars[argid] = &*fargsI; - fargsI->setName(arg); - ++fargsI; - } - } -}; -typedef LateContextFunctionDecorator< - AdhocFunctionDecorator< - BasicFunctionDecorator>> DefaultFunctionUnit; llvm::Function* FunctionUnit::compile(){ if (raw != nullptr) return raw; - LLVMLayer* llvm = pass->man->llvm; llvm::IRBuilder<>& builder = llvm->builder; - AST* ast = pass->man->root; - - - string&& functionName = prepareName(); std::vector&& types = prepareArguments(); llvm::Type* expectedResultType = prepareResult(); llvm::FunctionType *ft = llvm::FunctionType::get(expectedResultType, types, false); raw = llvm::cast(llvm->module->getOrInsertFunction(functionName, ft)); prepareBindings(); const std::string&blockName = "entry"; llvm::BasicBlock* blockCurrent = builder.GetInsertBlock(); - llvm::Value* result = entryCompilation->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)); 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)); } return scopes.at(scope).get(); } CodeScopeUnit* FunctionUnit::getEntry(){ return getScopeUnit(function->getEntryScope()); } CodeScopeUnit* FunctionUnit::getScopeUnit(ManagedScpPtr scope){ return getScopeUnit(&*scope); } FunctionUnit* CompilePass::getFunctionUnit(const ManagedFnPtr& function){ unsigned int id = function.id(); if (!functions.count(id)){ FunctionUnit* unit = new DefaultFunctionUnit(function, this); functions.emplace(id, unit); return unit; } - return functions.at(id).get(); + return functions.at(id); } void CompilePass::run(){ transformations = new Transformations(this); transformations->registerTransformer(new TransformerSaturation(transformations)); - //targetInterpretation = new TargetInterpretation(this->man->root); + targetInterpretation = new TargetInterpretation(this->man->root, this); queryContext = reinterpret_cast (man->clasp->getQuery(QueryId::ContextQuery)); //Find out main function; ClaspLayer::ModelFragment model = man->clasp->query(Config::get("function-entry")); assert(model && "Error: No entry function found"); assert(model->first != model->second && "Error: Ambiguous entry function"); string nameMain = std::get<0>(ClaspLayer::parse(model->first->second)); FunctionUnit* unitMain = getFunctionUnit(man->root->findFunction(nameMain)); entry = unitMain->compile(); } llvm::Function* CompilePass::getEntryFunction(){ assert(entry); return entry; } void CompilePass::prepareQueries(ClaspLayer* clasp){ clasp->registerQuery(new containers::Query(), QueryId::ContainersQuery); clasp->registerQuery(new ContextQuery(), QueryId::ContextQuery); } //CODESCOPE COMPILATION PHASE //FIND SYMBOL(compilation phase): //if (!forceCompile) //{ // return result; //} // //search in already compiled vars //if (__rawVars.count(vId)) //{ // return result; //} //if (!__declarations.count(vId)) { // //error: symbol is uncompiled scope arg // assert(false); //} //const Expression& e = __declarations.at(vId); //__rawVars[vId] = process(e, l, name); //FIND FUNCTION //llvm::Function* //CompilePass::findFunction(const std::string& name){ // ManagedFnPtr calleeFunc = man->root->findFunction(name); // assert(calleeFunc.isValid()); // return nullptr; //} + diff --git a/cpp/src/pass/compilepass.h b/cpp/src/pass/compilepass.h index 54fb72d..416de88 100644 --- a/cpp/src/pass/compilepass.h +++ b/cpp/src/pass/compilepass.h @@ -1,120 +1,155 @@ #ifndef COMPILEPASS_H #define COMPILEPASS_H -#include #include "abstractpass.h" #include "llvm/IR/Function.h" namespace xreate { class AdhocScheme; class ClaspLayer; class ContextQuery; - class CallStatement; + class LLVMLayer; } +//namespace llvm { +// class Function; +// class Value; +// class Type; +//} + namespace xreate { class CompilePass; namespace compilation { class CodeScopeUnit; class FunctionUnit; class TargetInterpretation; struct Context{ CodeScopeUnit* scope; FunctionUnit* function; CompilePass* pass; }; +class CallStatement { +public: + virtual llvm::Value* operator() (std::vector&& args, const std::string& hintDecl="") = 0; +}; + +class CallStatementRaw: public CallStatement{ +public: + CallStatementRaw(llvm::Function* callee, LLVMLayer* l) + : __callee(callee), __calleeTy(callee->getFunctionType()), llvm(l) {} + CallStatementRaw(llvm::Value* callee, llvm::FunctionType* ty, LLVMLayer* l) + : __callee(callee), __calleeTy(ty), llvm(l) {} + llvm::Value* operator() (std::vector&& args, const std::string& hintDecl=""); + +private: + llvm::Value* __callee; + llvm::FunctionType* __calleeTy; + + LLVMLayer* llvm; +}; + class CodeScopeUnit { 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=""); CodeScope* scope; private: CompilePass* pass; llvm::Value* raw = nullptr; FunctionUnit* function; std::unordered_map __declarationsOverriden; CallStatement* findFunction(const std::string& callee); }; class IFunctionDecorator { protected: virtual std::string prepareName() = 0; virtual std::vector prepareArguments() = 0; virtual llvm::Type* prepareResult() = 0; - virtual void prepareBindings() = 0; + virtual llvm::Function::arg_iterator prepareBindings() = 0; virtual ~IFunctionDecorator(){} }; class FunctionUnit: public IFunctionDecorator{ public: FunctionUnit(ManagedFnPtr f, CompilePass* p) : function(f), pass(p) {} llvm::Function* compile(); CodeScopeUnit* getEntry(); CodeScopeUnit* getScopeUnit(CodeScope* scope); CodeScopeUnit* getScopeUnit(ManagedScpPtr scope); ManagedFnPtr function; llvm::Function* raw = nullptr; protected: - std::string prepareName(); - std::vector prepareArguments(); - llvm::Type* prepareResult(); + CompilePass* pass=nullptr; private: - CompilePass* pass; std::map> scopes; }; +class BasicFunctionDecorator: public FunctionUnit{ +public: + BasicFunctionDecorator(ManagedFnPtr f, CompilePass* p) + : FunctionUnit(f, p) {} + +protected: + std::string prepareName(); + virtual std::vector prepareArguments(); + virtual llvm::Type* prepareResult(); + virtual llvm::Function::arg_iterator prepareBindings(); +}; + class Transformations; } // end of namespace `xreate::compilation` class CompilePass : public AbstractPass { friend class LateContextCompiler; friend class LateContextCompiler2; friend class compilation::CodeScopeUnit; friend class compilation::FunctionUnit; public: compilation::Transformations* transformations; CompilePass(PassManager* manager): AbstractPass(manager) {} compilation::FunctionUnit* getFunctionUnit(const ManagedFnPtr& function); void run() override; llvm::Function* getEntryFunction(); static void prepareQueries(ClaspLayer* clasp); private: - std::map functions; + //TODO free `functions` in destructor + std::map functions; llvm::Function* entry = 0; ContextQuery* queryContext; compilation::TargetInterpretation* targetInterpretation; }; } #endif // COMPILEPASS_H diff --git a/cpp/src/pass/dfapass.cpp b/cpp/src/pass/dfapass.cpp index 2939d08..7a019e1 100644 --- a/cpp/src/pass/dfapass.cpp +++ b/cpp/src/pass/dfapass.cpp @@ -1,256 +1,240 @@ #include "pass/dfapass.h" #include "analysis/dfagraph.h" #include "passmanager.h" #include "clasplayer.h" #include using namespace std; using namespace xreate::analysis; namespace xreate{ - + DFAPass::DFAPass(PassManager* manager) : AbstractPass(manager) , __context{new xreate::analysis::DFAGraph(manager->clasp)} , clasp(manager->clasp) {} 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); return retFormal; } SymbolNode DFAPass::process(const Expression& expression, PassContext context, const std::string& decl) { ExpressionCache cache; - + if (!decl.empty()){ cache.result = clasp->pack(context.scope->findSymbol(decl), context.function->getName() + ":" + decl); - + } else if (!expression.tags.empty()) { cache.result = __context.graph->createAnonymousSymbol(clasp->pack(context.scope)); - + } else { cache.result = SymbolTransient{{}, clasp->pack(context.scope)}; } - + cache.operands.reserve(expression.getOperands().size()); for (const Expression &op: expression.getOperands()) { cache.operands.push_back(process(op, context)); } - + cache.blocks.reserve(expression.blocks.size()); for (CodeScope* scope: expression.blocks) { cache.blocks.push_back(process(scope, context)); } - - if (expression.__state != Expression::COMPOUND) { - processElementaryOp(expression, context, cache, decl); - - } else { + + if (expression.__state == Expression::COMPOUND) { processCompoundOp(expression, context, cache, decl); + + } else { + processElementaryOp(expression, context, cache, decl); } - + applyDependencies(expression, context, cache, decl); applyStaticAnnotations(expression, context, cache, decl); applySignatureAnnotations(expression, context, cache, decl); applyInPlaceAnnotations(expression, context, cache, decl); - + //TODO Null ad hoc DFG implementation // if (expression.isNone()){ // return SymbolTransient{{Atom(Config::get("clasp.nonevalue"))}}; // } - + //non initialized(SymbolInvalid) value - + return cache.result; } 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(); - + 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; } - + break; } - + default: break; } } 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; } - + //TODO represent RET connection break; } - + //apply PROTOTYPE relation case Operator::MAP: { SymbolNode nodeFrom= cache.operands.front(); SymbolPacked* nodeFromPacked = boost::get(&nodeFrom); assert(nodeFromPacked); - + SymbolPacked* nodeTo = boost::get(&cache.result); assert(nodeTo); - - __context.graph->addConnection(*nodeTo, *nodeFromPacked, DFGConnection::PROTOTYPE); + + __context.graph->addConnection(*nodeTo, *nodeFromPacked, DFGConnection::PROTOTYPE); break; } - + default: 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); } - + for (SymbolNode &block: cache.blocks) { __context.graph->addDependencyConnection(cache.result, block); } - + switch(expression.__state) { case Expression::IDENT: { const string& identName = expression.getValueString(); - + SymbolNode identSymbol = clasp->pack(context.scope->findSymbol(identName), context.function->getName() + ":" + identName); __context.graph->addDependencyConnection(cache.result, identSymbol); } - + default: 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; - + default: break; } } - + 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)); } ++arg; ++tag; } //TODO represent RET connection // Expression retTag = *scheme.getOperands().begin(); // if (retTag.__state != Expression::INVALID) { // __context.graph->addAnnotation(node, move(retTag)); // } } } 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)); } } void DFAPass::run() { init(); return AbstractPass::run(); } void DFAPass::init() { for (const Expression& scheme: man->root->__dfadata) { __signatures.emplace(scheme.op, scheme); } } void DFAPass::finish() { man->clasp->setDFAData(move(__context.graph)); } template<> SymbolNode defaultValue(){return SymbolInvalid();}; } - - - - -/* -if (SymbolTransient* symbT = boost::get(&symbolRet)){ - std::vector tags; - tags.reserve(symbT->tags.size()); - - const std::string stmntRetTag = Config::get("clasp.ret.tag"); - std::transform(symbT->tags.begin(), symbT->tags.end(), std::inserter(tags, tags.begin()), - [&stmntRetTag](const Expression& e) { - Expression tag(Operator::CALL, {Atom(string(stmntRetTag)), e}); - return Tag{e, TagModifier::NONE}; - }); - - clasp->cfagraph->addFunctionAnnotations(function->getName(), tags); -} -*/ \ No newline at end of file diff --git a/cpp/src/pass/interpretationpass.cpp b/cpp/src/pass/interpretationpass.cpp index 968efa4..b4d399e 100644 --- a/cpp/src/pass/interpretationpass.cpp +++ b/cpp/src/pass/interpretationpass.cpp @@ -1,334 +1,406 @@ /* * File: interpretationpass.cpp * Author: pgess * * Created on July 5, 2016, 5:21 PM */ #include "pass/interpretationpass.h" #include "compilation/transformations.h" #include #include "ast.h" //DEBT implement InterpretationPass purely in clasp //DEBT represent InterpretationPass as general type inference using namespace std; namespace xreate{ enum InterpretationQuery{QUERY_INTR_ONLY, QUERY_CMPL_ONLY}; template<> InterpretationResolution defaultValue(){ return CMPL_ONLY; } InterpretationResolution unify(InterpretationResolution flag) { return flag; } template InterpretationResolution unify(FLAG_A flagA, FLAG_B flagB, FLAGS... flags) { - if (flagA== BOTH){ + if (flagA== ANY){ return unify(flagB, flags...); } - if (flagB == BOTH) { + if (flagB == ANY) { return unify(flagA, flags...); } 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) { assert(flags.size()); InterpretationResolution flag = flags.front(); return detail::checkConstraints(flag); } template bool checkConstraints(std::vector&& flags) { assert(flags.size()); InterpretationResolution flag = flags.front(); flags.pop_back(); if (detail::checkConstraints(flag)){ return checkConstraints(move(flags)); } return false; } -void -setSpecializedOperator(const Expression& expression, const InterpretationOperator& op){ - if (Attachments::exists(expression)){ - InterpretationData& data = Attachments::get(expression); - data.op = op; - - } else { - Attachments::put(expression, {BOTH, op}); - } +namespace details { + InterpretationResolution + recognizeTags(const map& tags){ + auto i = tags.find("interpretation"); + if (i== tags.end()){ + return ANY; + } - compilation::Transformations::subscribe(expression); -} + assert(i->second.op == Operator::CALL); + const string& cmd = i->second.operands.at(0).getValueString(); -InterpretationResolution -recognizeTags(const map& tags){ - auto i = tags.find("interpretation"); - if (i== tags.end()){ - return BOTH; - } + //TODO make consistent names of annotation and resolution + if (cmd == "force"){ + return INTR_ONLY; - 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; + } - } else if (cmd == "suppress"){ - return CMPL_ONLY; + return ANY; } - - return BOTH; } + void recognizeTags(const Expression& e){ - InterpretationData tag{recognizeTags(e.tags), NONE}; + InterpretationData tag{details::recognizeTags(e.tags), NONE}; Attachments::put(e, tag); } InterpretationResolution recognizeTags(const ManagedFnPtr& f){ - return recognizeTags(f->getTags()); + return details::recognizeTags(f->getTags()); } InterpretationPass::InterpretationPass(PassManager* manager) : AbstractPass(manager) {} +void InterpretationPass::run(){ + ManagedFnPtr f = man->root->begin(); + auto& visitedSymbols = getSymbolCache(); + + while (f.isValid()) { + const Symbol& symbolFunction{0, f->getEntryScope()}; + + if (!visitedSymbols.isCached(symbolFunction)){ + visitedSymbols.setCachedValue(symbolFunction, process(f)); + } + + ++f; + } +} + InterpretationResolution InterpretationPass::process(const Expression& expression, PassContext context, const std::string& decl){ recognizeTags(expression); - InterpretationResolution resolution = BOTH; + InterpretationResolution resolution = ANY; + InterpretationOperator op = NONE; switch (expression.__state){ case Expression::NUMBER: case Expression::STRING: { break; } case Expression::IDENT: { resolution = Parent::processSymbol(expression.getValueString(), context); break; } case Expression::COMPOUND: break; default: { resolution = INTR_ONLY; break;} } if (expression.__state == Expression::COMPOUND) switch(expression.op){ case Operator::EQU: case Operator::NE: { InterpretationResolution left = process(expression.operands[0], context); InterpretationResolution right = process(expression.operands[1], context); resolution = unify(left, right); break; } case Operator::LOGIC_AND: { assert(expression.operands.size() == 1); resolution = process (expression.operands[0], context); break; } case Operator::CALL: { - //TODO cope with static/dynamic context - - for (const Expression &op: expression.getOperands()) { - resolution = unify(resolution, process(op, context)); - } - + //TODO cope with static/dynamic context + //TODO BUG here: if several variants they all are processed as CMPL careless of signature list callees = man->root->getFunctionVariants(expression.getValueString()); if (callees.size()!=1){ resolution = CMPL_ONLY; break; } ManagedFnPtr callee = callees.front(); const Symbol& symbCalleeFunc{0, callee->getEntryScope()}; //recursion-aware processing: // - skip self recursion const Symbol& symbSelfFunc{0, context.function->getEntryScope()}; - if (symbSelfFunc == symbCalleeFunc){ - break; + 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); } - // - in order to recognize indirect recursion mark this function resolution as POSTPONED - auto& cache = getSymbolCache(); - if (!cache.isCached(symbSelfFunc)){ - cache.setCachedValue(symbSelfFunc, POSTPONED); + //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; + + assert(sig.signature[op] == argActual); } - InterpretationResolution resCallee = process(callee); - if (resCallee == POSTPONED){ - assert(false && "Indirect recursion detected: can't decide on interpretation resolution"); + if (FunctionInterpretationHelper::needPartialInterpretation(callee)){ + op= CALL_INTERPRET_PARTIAL; } - resolution = unify(resolution, resCallee); 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})){ - setSpecializedOperator(expression, IF_INTERPRET_CONDITION); - flagCondition = BOTH; + op= IF_INTERPRET_CONDITION; + flagCondition = ANY; } resolution = unify(flagCondition, flagScope1, flagScope2); break; } case Operator::FOLD: { InterpretationResolution flagInput = process(expression.getOperands()[0], context); InterpretationResolution flagAccumInit = process(expression.getOperands()[1], context); CodeScope* scopeBody = expression.blocks.front(); const std::string& nameEl = expression.bindings[0]; getSymbolCache().setCachedValue(scopeBody->findSymbol(nameEl), InterpretationResolution(flagInput)); const std::string& nameAccum = expression.bindings[1]; getSymbolCache().setCachedValue(scopeBody->findSymbol(nameAccum), InterpretationResolution(flagAccumInit)); InterpretationResolution flagBody = Parent::process(expression.blocks.front(), context); //special case: FOLD_INTERPRET_INPUT if (checkConstraints({flagInput})){ - setSpecializedOperator(expression, FOLD_INTERPRET_INPUT); - flagInput = BOTH; + op= FOLD_INTERPRET_INPUT; + flagInput = ANY; } resolution = unify(flagInput, flagAccumInit, flagBody); break; } case Operator::INDEX: { resolution = unify( process(expression.operands[0], context), Parent::processSymbol(expression.getValueString(), context) ); break; } case Operator::SWITCH: { InterpretationResolution flagCondition = process(expression.operands[0], context); bool hasDefaultCase = expression.operands[1].op == Operator::CASE_DEFAULT; //determine conditions resolution InterpretationResolution flagHeaders = flagCondition; for (size_t size = expression.operands.size(), i= hasDefaultCase? 2: 1; i({flagHeaders})){ - setSpecializedOperator(expression, SWITCH_INTERPRET_CONDITION); - flagHeaders = BOTH; + op= SWITCH_INTERPRET_CONDITION; + flagHeaders = ANY; } //determine body resolutions resolution = flagHeaders; for (size_t size = expression.operands.size(), i= 1; i(expression, {BOTH, NONE}) + InterpretationResolution resolutionExpected = Attachments::get(expression, {ANY, NONE}) .resolution; resolution = unify(resolution, resolutionExpected); + if (op!=NONE || resolution == INTR_ONLY ){ + Attachments::put(expression, {resolution, op}); + } + if (resolution == INTR_ONLY){ - Attachments::put(expression, {INTR_ONLY, NONE}); compilation::Transformations::subscribe(expression); } - return resolution; } InterpretationResolution - InterpretationPass::process(ManagedFnPtr function){ - InterpretationResolution resExpected = recognizeTags(function); + InterpretationPass::processFnCall(ManagedFnPtr function, PassContext context){ + const Symbol& symbolFunction{0, function->getEntryScope()}; + auto& visitedSymbols = getSymbolCache(); - //mark preliminary function resolution same as expected - if (resExpected != BOTH){ - const Symbol& symbSelfFunc{0, function->getEntryScope()}; - getSymbolCache().setCachedValue(symbSelfFunc, move(resExpected)); - } + if (visitedSymbols.isCached(symbolFunction)) + return visitedSymbols.getCachedValue(symbolFunction); + + PassContext context2; + context2.function = function; + return visitedSymbols.setCachedValue(symbolFunction, + Parent::process(function->getEntryScope(), context2)); + } + + InterpretationResolution + InterpretationPass::process(ManagedFnPtr function){ CodeScope* entry = function->getEntryScope(); + std::vector arguments = entry->__bindings; + const Symbol& symbSelfFunc{0, function->getEntryScope()}; auto& cache = getSymbolCache(); - std::vector args = entry->__bindings; - for (int argNo = 0, size = args.size(); argNo< size; ++argNo){ - Symbol symbArg = entry->findSymbol(args[argNo]); - InterpretationResolution resArg = recognizeTags(entry->findDeclaration(symbArg).tags); - cache.setCachedValue(symbArg, move(resArg)); + const FunctionInterpretationData& dataIntrpr = FunctionInterpretationHelper::getSignature(function); + InterpretationResolution resExpected = details::recognizeTags(function->getTags()); + + //mark preliminary function resolution as expected + if (resExpected != ANY){ + cache.setCachedValue(symbSelfFunc, move(resExpected)); + + } else { + // - in order to recognize indirect recursion mark this function resolution as POSTPONED + cache.setCachedValue(symbSelfFunc, FUNC_POSTPONED); + } + + //set resolution for function arguments as expected + for (int argNo = 0, size = arguments.size(); argNo< size; ++argNo){ + Symbol symbArg = entry->findSymbol(arguments[argNo]); + cache.setCachedValue(symbArg, InterpretationResolution(dataIntrpr.signature[argNo])); } InterpretationResolution resActual = Parent::process(function); return unify(resActual, resExpected); } + + const FunctionInterpretationData + FunctionInterpretationHelper::getSignature(ManagedFnPtr function){ + const Symbol& symbFunc{0, function->getEntryScope()}; + + if (Attachments::exists(symbFunc)){ + return Attachments::get(symbFunc); + } + + FunctionInterpretationData&& data = recognizeSignature(function); + Attachments::put(symbFunc, data); + return data; + } + + FunctionInterpretationData + FunctionInterpretationHelper::recognizeSignature(ManagedFnPtr function){ + CodeScope* entry = function->__entry; + FunctionInterpretationData result; + result.signature.reserve(entry->__bindings.size()); + + bool flagPartialInterpretation = false; + for(size_t no=0, size=entry->__bindings.size(); no < size; ++no){ + const std::string& argName = entry->__bindings[no]; + const Expression& arg = entry->findDeclaration(entry->findSymbol(argName)); + + InterpretationResolution argResolution = details::recognizeTags(arg.tags); + flagPartialInterpretation |= (argResolution == INTR_ONLY); + + result.signature.push_back(argResolution); + } + result.flagPartialInterpretation = flagPartialInterpretation; + return result; + } + + bool FunctionInterpretationHelper::needPartialInterpretation(ManagedFnPtr function){ + const FunctionInterpretationData& data = getSignature(function); + return data.flagPartialInterpretation; + } } -- \ No newline at end of file + +//if (res != INTR_ONLY){ +// argumentsActual.insert(no); +//} + + diff --git a/cpp/src/pass/interpretationpass.h b/cpp/src/pass/interpretationpass.h index 0992d6e..0d6ba84 100644 --- a/cpp/src/pass/interpretationpass.h +++ b/cpp/src/pass/interpretationpass.h @@ -1,47 +1,78 @@ /* * File: interpretationpass.h * Author: pgess * * Created on July 5, 2016, 5:21 PM */ #ifndef INTERPRETATIONPASS_H #define INTERPRETATIONPASS_H #include "abstractpass.h" +#include namespace xreate { - enum InterpretationResolution{BOTH, INTR_ONLY, CMPL_ONLY, POSTPONED}; - enum InterpretationOperator{NONE, IF_INTERPRET_CONDITION, FOLD_INTERPRET_INPUT, SWITCH_INTERPRET_CONDITION}; + enum InterpretationResolution{ANY, INTR_ONLY, CMPL_ONLY, FUNC_POSTPONED}; + enum InterpretationOperator{NONE, IF_INTERPRET_CONDITION, FOLD_INTERPRET_INPUT, SWITCH_INTERPRET_CONDITION, CALL_INTERPRET_PARTIAL}; struct InterpretationData{ InterpretationResolution resolution; InterpretationOperator op; }; 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; }; 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); + } } #endif /* INTERPRETATIONPASS_H */ diff --git a/cpp/src/query/context.cpp b/cpp/src/query/context.cpp index efa6af1..76d7b05 100644 --- a/cpp/src/query/context.cpp +++ b/cpp/src/query/context.cpp @@ -1,244 +1,207 @@ /* * 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; -bool operator < (const Expression&a, const Expression&b) { - if (a.__state != b.__state) return a.__state < b.__state; - assert(a.__state != Expression::INVALID); - switch(a.__state) { - case Expression::IDENT: - case Expression::STRING: - case Expression::VARIANT: - return a.getValueString() < b.getValueString(); - - case Expression::NUMBER: - return a.getValueDouble() < b.getValueDouble(); - - case Expression::COMPOUND: { - assert(a.op == Operator::CALL); - assert(a.blocks.size()==0); - assert(b.blocks.size()==0); - - if (a.operands.size() != b.operands.size()){ - return (a.operands.size() < b.operands.size()); - } - - if (a.getValueString() != b.getValueString()){ - return a.getValueString() < b.getValueString(); - } - - for(size_t i=0; ipack(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 + //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& atomEarlyBinding = Config::get("clasp.bindings.scope"); + const std::string& atomBinding = Config::get("clasp.bindings.scope"); this->clasp = clasp; - ClaspLayer::ModelFragment query = clasp->query(atomEarlyBinding); + 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; - tie(idScope, context) = ClaspLayer::parse(i->second); - dictContext[idScope].push_back(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 index b32a021..8dd6858 100644 --- a/cpp/src/query/context.h +++ b/cpp/src/query/context.h @@ -1,97 +1,95 @@ /* * 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(); }; -bool operator < (const Expression&, const Expression&); - } /* 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/tests/adhoc-skipdetection.cpp b/cpp/tests/adhoc-skipdetection.cpp index 603891c..6dcb4f5 100644 --- a/cpp/tests/adhoc-skipdetection.cpp +++ b/cpp/tests/adhoc-skipdetection.cpp @@ -1,34 +1,34 @@ /* * skipdetection.cpp * * Created on: Jul 10, 2015 * Author: pgess */ #include "passmanager.h" #include "clasplayer.h" #include "gtest/gtest.h" using namespace xreate; using namespace std; //TASK implement loop "skip" command -TEST(Adhoc_Loop_SkipDetection, testNoneValueTagExists){ +TEST(Adhoc_Loop_SkipDetection, DISABLED_testNoneValueTagExists){ PassManager* man = PassManager::prepareForCode - ("test = function():: int; entry {\n" + ("test = function:: int; entry {\n" " data = [1..5]::[int].\n" " \n" - " result = loop fold(data->i::int, 0->sum::int)::int{\n" - " if (i==3)::int {valNull = null. valNull} else {i+sum}\n" + " result = loop fold(data->i::int, 0->sum)::int{\n" + " if (i==3)::bool {valNull = null. valNull} else {i+sum}\n" " }.\n" " \n" " result\n" "}"); man->runWithoutCompilation(); ClaspLayer::ModelFragment answer = man->clasp->query(Config::get("clasp.nonevalue")); int countNoneValue = 0; if (answer) countNoneValue = std::distance(answer->first, answer->second); EXPECT_EQ(1, countNoneValue); } diff --git a/cpp/tests/adhoc.cpp b/cpp/tests/adhoc.cpp index 5719e57..eb9bafb 100644 --- a/cpp/tests/adhoc.cpp +++ b/cpp/tests/adhoc.cpp @@ -1,157 +1,160 @@ /* * 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()->__body; + 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" + "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" + "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" + "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" - " }" ); + "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()->__body; + 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/ast.cpp b/cpp/tests/ast.cpp index 4868d3a..46c637d 100644 --- a/cpp/tests/ast.cpp +++ b/cpp/tests/ast.cpp @@ -1,49 +1,48 @@ /* * ast.cpp * * Created on: Jun 11, 2015 * Author: pgess */ #include "gtest/gtest.h" #include "passmanager.h" #include "Parser.h" using namespace std; using namespace xreate; TEST(AST, Containers1){ FILE* input = fopen("scripts/testspass/Containers_Implementation_LinkedList1.xreate","r"); Scanner scanner(input); Parser parser(&scanner); parser.Parse(); + assert(!parser.errors->count && "Parser errors"); - const AST& ast = parser.root; - - fclose(input); + fclose(input); } TEST(AST, InterfacesDataCFA) { PassManager* man = PassManager::prepareForCode ("interface(cfa){\n" " operator map :: annotation1.\n" "}"); auto answer = man->root->__interfacesData.equal_range(CFA); EXPECT_EQ(1, std::distance(answer.first, answer.second)); Expression&& scheme = move(answer.first->second); EXPECT_EQ(Operator::MAP, scheme.op); EXPECT_EQ("annotation1", scheme.getOperands().at(0).getValueString()); } TEST(AST, DISABLED_InterfacesDataDFA){ } TEST(AST, DISABLED_InterfacesDataExtern){ } //TODO xreate.atg: replace all Type<> as ExprAnnotations<> diff --git a/cpp/tests/basic.cpp b/cpp/tests/basic.cpp index 1f1acb5..0deb63b 100644 --- a/cpp/tests/basic.cpp +++ b/cpp/tests/basic.cpp @@ -1,26 +1,26 @@ #include "gtest/gtest.h" #include "passmanager.h" #include "Scanner.h" #include "Parser.h" #include #include using namespace std; using namespace xreate; TEST(Basic, functionEntry1){ std::unique_ptr program(PassManager::prepareForCode( "func1 = function(a:: int):: int {a+8} \ - func2 = function()::int; entry {12 + func1(4)} \ + 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 e9b7e0c..f01028c 100644 --- a/cpp/tests/cfa.cpp +++ b/cpp/tests/cfa.cpp @@ -1,109 +1,119 @@ /* * testsCFG.cpp * * Created on: Jul 17, 2015 * Author: pgess */ #include "passmanager.h" #include "pass/dfapass.h" #include "pass/cfapass.h" #include "analysis/DominatorsTreeAnalysisProvider.h" #include "gtest/gtest.h" #include #include using namespace xreate; using namespace std; -TEST(CFG, testFunctionAnnotationsClasp){ - string&& program = - "f2 = function::int; annotationF2 {\n" - " 0\n" - "}\n" - "\n" - "f1 = function:: int; entry; annotationF1 {\n" - " f2() + 10\n" - "}"; - - - PassManager* man = PassManager::prepareForCode(move(program)); - man->runWithoutCompilation(); - - ClaspLayer::ModelFragment answer = man->clasp->query("annotationF1"); - int countNoneValue = 0; - if (answer) - countNoneValue = std::distance(answer->first, answer->second); - EXPECT_EQ(1, countNoneValue); - - answer = man->clasp->query("annotationF2"); - countNoneValue = 0; - if (answer) - countNoneValue = std::distance(answer->first, answer->second); +TEST(CFA, testFunctionAnnotationsClasp){ + string&& program = + "f2 = function::int; annotationF2 {\n" + " 0\n" + "}\n" + "\n" + "f1 = function:: int; entry; annotationF1 {\n" + " f2() + 10\n" + "}"; + + + PassManager* man = PassManager::prepareForCode(move(program)); + man->runWithoutCompilation(); + + ClaspLayer::ModelFragment answer = man->clasp->query("annotationF1"); + int countNoneValue = 0; + if (answer) countNoneValue = std::distance(answer->first, answer->second); + EXPECT_EQ(1, countNoneValue); + + answer = man->clasp->query("annotationF2"); + countNoneValue = 0; + if (answer) countNoneValue = std::distance(answer->first, answer->second); + EXPECT_EQ(1, countNoneValue); } -TEST(CFG, testLoopContextExists){ - PassManager* man = PassManager::prepareForCode ( - "interface(cfa){\n" - " operator fold:: annotation1.\n" - "}\n" - "\n" - "main = function:: int; entry {\n" - " x = [1..10]:: [int].\n" - " sum = loop fold (x->el:: int, 0->sum):: int {\n" - " el + sum + f1()\n" - " }. \n" - " sum\n" - "}" - "f1 = function::int {\n" - " x = 0:: int. " - " x\n" - "}" +TEST(CFA, testLoopContextExists){ + PassManager* man = PassManager::prepareForCode ( + "interface(cfa){\n" + " operator fold:: annotation1.\n" + "}\n" + "\n" + "main = function:: int; entry {\n" + " x = [1..10]:: [int].\n" + " sum = loop fold (x->el:: int, 0->sum):: int {\n" + " el + sum + f1()\n" + " }. \n" + " sum\n" + "}" + "case context:: annotation1 {" + " f1 = function::int {\n" + " x = 0:: int. " + " x\n" + " }" + "}" ); - man->runWithoutCompilation(); + man->runWithoutCompilation(); + ClaspLayer::ModelFragment model = man->clasp->query("annotation1"); + ScopePacked scopeIdActual = std::get<0>(ClaspLayer::parse(model->first->second)); + + CodeScope* scopeEntry = man->root->findFunction("main")->getEntryScope(); + Symbol symbSum = man->root->findFunction("main")->getEntryScope()->findSymbol("sum"); + CodeScope* scopeExpected = scopeEntry->findDeclaration(symbSum).blocks.front(); + + ScopePacked scopeIdExpected = man->clasp->pack(scopeExpected); + ASSERT_EQ(scopeIdExpected, scopeIdActual); } -TEST(CFG, CFGRoots){ - std::string program = +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"; - + boost::scoped_ptr manager (PassManager::prepareForCode(move(program))); - + manager->registerPass(new CFAPass(manager.get()) , PassId::CFGPass); manager->executePasses(); manager->clasp->run(); - + DominatorsTreeAnalysisProvider domProvider; domProvider.run(manager->clasp); - + DominatorsTreeAnalysisProvider::Dominators expectedFDom= { {0, {0, 9}} ,{1, {1, 4}} ,{2, {7, 8}} ,{3, {2, 3}} ,{4, {5, 6}} }; - + DominatorsTreeAnalysisProvider::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()); } diff --git a/cpp/tests/compilation.cpp b/cpp/tests/compilation.cpp index 58cb59d..e5371df 100644 --- a/cpp/tests/compilation.cpp +++ b/cpp/tests/compilation.cpp @@ -1,62 +1,80 @@ #include "passmanager.h" #include "gtest/gtest.h" using namespace xreate; +//DEBT implement no pkgconfig ways to link libs //TOTEST FunctionUnit::compileInline TEST(Compilation, DISABLED_functionInline1){ } -//DEBT implement no pkgconfig ways to link libs TEST(Compilation, Sequence1){ - PassManager* man = PassManager::prepareForCode( - "interface(extern-c){\n" - " libFake = library:: pkgconfig(\"libxml-2.0\").\n" - " \n" - " include {\n" - " libFake = [\"stdio.h\", \"stdlib.h\"]\n" - " }.\n" - "}" - - "main = function:: int; entry {\n" - " sequence [" - " printf(\"FIRST-\"),\n" - " printf(\">SECOND\")\n" - " ]" - "}" - ); - - int (*main)() = (int (*)()) man->run(); - - testing::internal::CaptureStdout(); - main(); - std::string output = testing::internal::GetCapturedStdout(); - - ASSERT_STREQ("FIRST->SECOND", output.c_str()); + PassManager* man = PassManager::prepareForCode( + "interface(extern-c){\n" + " libFake = library:: pkgconfig(\"libxml-2.0\").\n" + " \n" + " include {\n" + " libFake = [\"stdio.h\", \"stdlib.h\"]\n" + " }.\n" + "}" + + "main = function:: int; entry {\n" + " sequence [" + " printf(\"FIRST-\"),\n" + " printf(\">SECOND\")\n" + " ]" + "}" + ); + + int (*main)() = (int (*)()) man->run(); + + testing::internal::CaptureStdout(); + main(); + std::string output = testing::internal::GetCapturedStdout(); + + ASSERT_STREQ("FIRST->SECOND", output.c_str()); } +TEST(Compilation, 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" + "]" + "}" + ); + + int (*main)() = (int (*)()) man->run(); + main(); +} + + TEST(Compilation, full_IFStatementWithVariantType){ - PassManager* man = PassManager::prepareForCode( - "COLORS = type variant (RED, BLUE, GREEN).\n" - "\n" - " main = function(x::int):: int; entry {\n" - " color = if (x == 0 )::COLORS {RED} else {BLUE}.\n" - " if (color == BLUE)::int {1} else {0}\n" - " }" - ); - - int (*main)(int) = (int (*)(int)) man->run(); - ASSERT_EQ(0, main(0)); - ASSERT_EQ(1, main(1)); + PassManager* man = PassManager::prepareForCode( + "COLORS = type variant (RED, BLUE, GREEN).\n" + "\n" + " main = function(x::int):: int; entry {\n" + " color = if (x == 0 )::COLORS {RED} else {BLUE}.\n" + " if (color == BLUE)::int {1} else {0}\n" + " }" + ); + + int (*main)(int) = (int (*)(int)) man->run(); + ASSERT_EQ(0, main(0)); + ASSERT_EQ(1, main(1)); } -// "main = function:: int; entry {\n" -// " context:: expectNoErrors. " -// " buf1 = \"aaaaa\"::string.\n" -// " buf2 = \"aaaaa\"::string.\n" -// " sequence [" -// " sprintf(buf1, \"%d\", exec(\"bazaar --version\"))," -// " sprintf(buf2, \"%d\", exec(\"svn --version\"))," -// " printf(buf1),\n" -// " printf(buf2)\n" -// "]" -// "}" + diff --git a/cpp/tests/containers.cpp b/cpp/tests/containers.cpp index e2c3e76..2f21eee 100644 --- a/cpp/tests/containers.cpp +++ b/cpp/tests/containers.cpp @@ -1,54 +1,54 @@ /* * containers.cpp * * Created on: Jun 9, 2015 * Author: pgess */ #include "passmanager.h" #include "query/containers.h" #include "Parser.h" #include "gtest/gtest.h" using namespace std; using namespace xreate; using namespace containers; TEST(Containers, ContanierLinkedList1){ FILE* input = fopen("scripts/testspass/Containers_Implementation_LinkedList1.xreate","r"); assert(input != nullptr); Scanner scanner(input); Parser parser(&scanner); parser.Parse(); AST& ast = parser.root; CodeScope* body = ast.findFunction("test")->getEntryScope(); Symbol symb_chilrenRaw = body->findSymbol("childrenRaw"); containers::ImplementationLinkedList iLL(symb_chilrenRaw); ASSERT_EQ(true, static_cast(iLL)); ASSERT_EQ("next", iLL.fieldPointer); Implementation impl = Implementation::create(symb_chilrenRaw); ASSERT_NO_FATAL_FAILURE(impl.extract()); ImplementationRec recOnthefly = impl.extract(); ASSERT_EQ(symb_chilrenRaw, recOnthefly.source); } TEST(Containers, Implementation_LinkedListFull){ FILE* input = fopen("scripts/testspass/Containers_Implementation_LinkedList1.xreate","r"); assert(input != nullptr); std::unique_ptr program(PassManager::prepareForCode(input)); void* mainPtr = program->run(); int (*main)() = (int (*)())(intptr_t)mainPtr; int answer = main(); - ASSERT_EQ(16, answer); + ASSERT_EQ(17, answer); fclose(input); } diff --git a/cpp/tests/context.cpp b/cpp/tests/context.cpp index 4c05c02..9a3187c 100644 --- a/cpp/tests/context.cpp +++ b/cpp/tests/context.cpp @@ -1,370 +1,404 @@ /* * 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" -// " testC = function::int {\n" -// " context:: testC.\n" -// -// " 0\n" -// " }\n" -// -// " testA = function:: int {\n" -// " context:: testA; test.\n" -// -// " testC()\n" -// " }\n" -// -// " testB = function:: int {\n" -// " context:: testB; test.\n" -// -// " testC()\n" -// " }\n" -// ); -// -// ContextQuery* query = (ContextQuery*) man->clasp->registerQuery(new ContextQuery(), QueryId::ContextQuery); -// man->runWithoutCompilation(); -// -// CodeScope* scopeTestC = man->root->findFunction("testC")->getEntryScope(); -// const ContextDomain& context = query->getContext(man->clasp->pack(scopeTestC)); -// -// int contextSize = context.size(); -// EXPECT_EQ(2, contextSize); -//} -// -//TEST(Context, full_ContextBasedFunctionSpecialization){ -// -// PassManager* man = PassManager::prepareForCode( -// " case context::toMillimeters {\n" -// " convert = function(source:: num)::num {\n" -// " 10 * source \n" -// " }\n" -// " }\n" -// -// " case context::toInches {\n" -// " convert = function(source:: num)::num {\n" -// " 2 * source \n" -// " }\n" -// " }\n" -// -// "test = function(vrnt:: int)::int; entry {\n" -// " switch(vrnt):: int\n" -// " case 0 {\n" -// " context:: toMillimeters.\n" -// " convert(1)\n" -// " }\n" -// "\n" -// " case 1 {\n" -// " context:: toInches.\n" -// " convert(1)\n" -// " }\n" -// " case default {0}\n" -// " }" ); -// -// int (*main)(int) = (int (*)(int)) man->run(); -// ASSERT_EQ(10, main(0)); -// ASSERT_EQ(2, main(1)); -//} -// -//TEST(Context, full_LoopContext){ -// -// PassManager* man = PassManager::prepareForCode("case context:: a {\n" -// " print = function:: string {\n" -// " \"a\"\n" -// " }}\n" -// "\n" -// " case context:: b {\n" -// " print = function:: string {\n" -// " \"b\"\n" -// " }}\n" -// "\n" -// " case context:: c {\n" -// " print = function:: string {\n" -// " \"c\"\n" -// " }}\n" -// "\n" -// " case context:: d {\n" -// " print = function:: string {\n" -// " \"d\"\n" -// " }}\n" -// "\n" -// " start = function(command::int)::string; entry {\n" -// " switch (command) :: string \n" -// " case 0 {\n" -// " context:: print(a); print(b); print(d).\n" -// "\n" -// " loop context (\"print\") {\n" -// " print()\n" -// " }\n" -// " }\n" -// "\n" -// " case default {\n" -// " context:: print(c).\n" -// " loop context (\"print\") {\n" -// " print()\n" -// " }\n" -// " }\n" -// " }"); -// -// -// char* (*main)(int) =(char* (*)(int)) man->run(); -// ASSERT_STREQ("c", main(1)); -// ASSERT_STREQ("a", main(0)); -//} -// -//TEST(Context, full_RuleContext){ -// /* -// "rule context:: childs(Child)\n" -// " case artefact(Item)\n" -// " {\n" -// " artefact_depends(Item, Child)\n" -// " }"; -// */ -// -// PassManager* man = PassManager::prepareForCode( -// " case context:: toMilli {\n" -// " convert = function(length::int)::int{\n" -// " 10 * length\n" -// " }\n" -// " }\n" -// "\n" -// " case context:: toCenti {\n" -// " convert = function(length::int)::int{\n" -// " length\n" -// " }\n" -// " }\n" -// "\n" -// " main=function::int; entry {\n" -// " context:: output(milli).\n" -// "\n" -// " rule context::toMilli\n" -// " case output(milli) {true}\n" -// "\n" -// " convert(1)\n" -// " }" ); -// man->clasp->addRawScript("true."); -// -// int (*entry)() = (int (*)()) man->run(); -// ASSERT_EQ(10, entry()); -//} -// -//TEST(Context, full_InheritedRuleContext){ -// PassManager* man = PassManager::prepareForCode( -// " import raw (\"core/control-context.lp\") \n" -// -// " case context:: toMilli {\n" -// " convert = function(length::int)::int{\n" -// " 10 * length\n" -// " }\n" -// " }\n" -// -// " case context:: toCenti {\n" -// " convert = function(length::int)::int{\ n" -// " length\n" -// " }\n" -// " }\n" -// "\n" -// -// "main = function(comm:: num)::num; entry{\n" -// " rule context::X case output(X) {true}\n" -// "\n" -// " switch (comm)::num \n" -// " case 0 {\n" -// " context:: output(toMilli).\n" -// " convert(1)\n" -// " }\n" -// " case default {\n" -// " context:: output(toCenti).\n" -// " convert(1)\n" -// " }\n" -// " }"); -// -// man->clasp->addRawScript("true."); -// int (*entry)(int) = (int (*)(int)) man->run(); -// ASSERT_EQ(10, entry(0)); -// ASSERT_EQ(1, entry(1)); -//} -// -// -// -//TEST(Context, full_LateContext){ -// PassManager* man = PassManager::prepareForCode( -// "import raw (\"core/control-context.lp\")\n" -// -// " convert = function(length:: num)::num{\n" -// " 0\n" -// " }\n" -// -// "case context:: milli {\n" -// " convert = function(length:: num)::num{\n" -// " 1000 * length\n" -// " }\n" -// "}\n" -// "\n" -// "case context:: centi {\n" -// " convert = function(length:: num)::num{\n" -// " 100 * length\n" -// " }\n" -// "}\n" -// "\n" -// "calculate = function(length:: num)::num {\n" -// " convert(length)\n" -// "}\n" -// "\n" -// "main = function(com:: num):: num; entry {\n" -// " switch (com):: num \n" -// " case 0 {\n" -// " context:: milli.\n" -// " calculate(1)\n" -// " }\n" -// "\n" -// " case default{\n" -// " context:: centi. \n" -// " calculate(1)\n" -// " }\n" -// "}"); -// -// man->runWithoutCompilation(); -// ContextQuery* queryContext = reinterpret_cast(man->clasp->getQuery(QueryId::ContextQuery)); -// Expression exprSwitch = man->root->findFunction("main")->__entry->__body; -// CodeScope* blockDefault = man->root->findFunction("main")->__entry->__body.operands[1].blocks.front(); -// ScopePacked blockDefaultId = man->clasp->pack(blockDefault); -// const ContextDomain& domDefault = queryContext->getContext(blockDefaultId); -// ASSERT_EQ(1, domDefault.count(Expression(Atom("centi")))); -// -// std::list variants = man->root->getFunctionVariants("convert"); -// for (ManagedFnPtr f: variants){ -// const Expression guard = f->guardContext; -// bool result = (guard.getValueString() == "centi" || guard.getValueString() == "milli" || !guard.isValid()); -// ASSERT_TRUE(result); -// } -// -// const FunctionContextDemand& demMain = queryContext->getFunctionDemand("main"); -// ASSERT_EQ(0, demMain.size()); -// -// const FunctionContextDemand& demCalculate = queryContext->getFunctionDemand("calculate"); -// ASSERT_EQ(1, demCalculate.size()); -// ASSERT_EQ(1, demCalculate.right.count("convert")); -// -// int (*entry)(int) = (int (*)(int)) man->run(); -// ASSERT_EQ(1000, entry(0)); -// ASSERT_EQ(100, entry(1)); -//} +TEST(Context, frame_Context1){ + PassManager* man = PassManager::prepareForCode( + " import raw (\"core/control-context.lp\")\n" + " testC = function::int {\n" + " context:: testC.\n" + + " 0\n" + " }\n" + + " testA = function:: int {\n" + " context:: testA; test.\n" + + " testC()\n" + " }\n" + + " testB = function:: int {\n" + " context:: testB; test.\n" + + " testC()\n" + " }\n" + + "test = function(cmnd:: int):: int; entry {\n" + " if (cmnd > 0)::int {testA()} else {testB()} \n" + "}\n" + ); + + ContextQuery* query = (ContextQuery*) man->clasp->registerQuery(new ContextQuery(), QueryId::ContextQuery); + man->runWithoutCompilation(); + + CodeScope* scopeTestC = man->root->findFunction("testC")->getEntryScope(); + const Domain& context = query->getContext(man->clasp->pack(scopeTestC)); + + int contextSize = context.size(); + EXPECT_EQ(2, contextSize); +} + +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, DISABLED_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, testLoopContextExists){ + 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, pathDependent_context){ - std::string program = + 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} + 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) + 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 088bc40..f9a4fb8 100644 --- a/cpp/tests/dfa.cpp +++ b/cpp/tests/dfa.cpp @@ -1,42 +1,12 @@ /* * DFGtests.cpp * * Created on: Jul 23, 2015 * Author: pgess */ #include "passmanager.h" #include "pass/dfapass.h" #include "gtest/gtest.h" using namespace xreate; -using namespace std; - -TEST(DFG, testFunctionRetSymbolExists){ - PassManager* man = PassManager::prepareForCode - ("test = function():: int; entry {\n" - " data = [1..5]::[int].\n" - " \n" - " result = loop fold(data->i::int, 0->sum::int)::int{\n" - " if (i==3)::int {valNull = null. valNull} else {i+sum}\n" - " }.\n" - " \n" - " result\n" - "}"); - - man->runWithoutCompilation(); - ClaspLayer::ModelFragment answer = man->clasp->query(Config::get("clasp.ret.symbol")); - - if (answer) - EXPECT_EQ(1, std::distance(answer->first, answer->second)); - - for (auto functionIt = answer->first; functionIt != answer->second; ++functionIt){ - auto ret = ClaspLayer::parse(functionIt->second); - - ASSERT_EQ("test", std::get<0>(ret)); - - SymbolPacked symbolRet = std::get<0>(ClaspLayer::parse(std::get<1>(ret))); - ASSERT_EQ(3, symbolRet.identifier); - ASSERT_EQ(0, symbolRet.scope); - } -} - +using namespace std; \ No newline at end of file diff --git a/cpp/tests/diagnostic-messages.cpp b/cpp/tests/diagnostic-messages.cpp index dbd21a1..66d2db1 100644 --- a/cpp/tests/diagnostic-messages.cpp +++ b/cpp/tests/diagnostic-messages.cpp @@ -1,32 +1,32 @@ /* * diagnostic-messages.cpp * * Created on: Oct 27, 2015 * Author: pgess */ #include "passmanager.h" #include "pass/dfapass.h" #include "gtest/gtest.h" using namespace std; using namespace xreate; -TEST(Diagnostic_DFA, DISABLED_recursion1){ +TEST(Diagnostic, DISABLED_DFA_recursion1){ - //Error while processing recursion, There should be some diagnostic complaints - std::string code = \ - "test1 = function()::[int] {\n" - " varRecursion = loop map(varRecursion->el:: int)::[int]{\n" - " el\n" - " }.\n" - " \n" - " varRecursion\n" - "}"; + //TODO Error while processing recursion, There should be some diagnostic complaints here + std::string code = \ + "test1 = function::[int] {\n" + " varRecursion = loop map(varRecursion->el:: int)::[int]{\n" + " el\n" + " }.\n" + " \n" + " varRecursion\n" + "}"; - PassManager* man = PassManager::prepareForCode(move(code)); - DFAPass* pass = new DFAPass(man); - pass->run(); - pass->finish(); + PassManager* man = PassManager::prepareForCode(move(code)); + DFAPass* pass = new DFAPass(man); + pass->run(); + pass->finish(); } diff --git a/cpp/tests/externc.cpp b/cpp/tests/externc.cpp index 2ec0e44..2542a4e 100644 --- a/cpp/tests/externc.cpp +++ b/cpp/tests/externc.cpp @@ -1,104 +1,108 @@ #include "gtest/gtest.h" #include "passmanager.h" #include "Scanner.h" #include "Parser.h" #include #include using namespace std; -TEST(InterfaceExternC, testAST){ - std::string code = " \ +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()); + Scanner scanner(reinterpret_cast (code.c_str()), code.size()); Parser parser(&scanner); parser.Parse(); ASSERT_EQ(1, parser.root.__externdata.size()); - for (const ExternEntry& lib: parser.root.__externdata){ - ASSERT_EQ("libxml-2.0", lib.package); - ASSERT_EQ(1, lib.headers.size()); - ASSERT_EQ("libxml/tree.h", lib.headers.at(0)); + 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", {}}; +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)); + 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", {}}; +TEST(InterfaceExternC, testfetchPackageLibs) { + ExternEntry entry{"libxml-2.0", + {}}; - vector args = ExternLayer::fetchPackageLibs(entry); - ASSERT_EQ(1, args.size()); + 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); - } +TEST(InterfaceExternC, testLoadLib) { + std::string msgErr; + if (!llvm::sys::DynamicLibrary::LoadLibraryPermanently("-lpcre -lxml2", &msgErr)) { + cout << msgErr; + ASSERT_EQ("", msgErr); + } - ASSERT_TRUE(true); + ASSERT_TRUE(true); } -TEST(InterfaceExternC, testBSD1){ - std::string code = " \n\ - interface(extern-c){ \n\ - libbsd = library:: pkgconfig(\"libbsd\"). \n\ - \n\ - include { \n\ - libbsd = [\"bsd/stdlib.h\"] \n\ - }. \n\ - }\n" - "main= function():: int; entry{arc4random() }"; - - std::unique_ptr program(PassManager::prepareForCode(move(code))); - - void* entryPtr = program->run(); - int (*entry)() = (int (*)())(intptr_t)entryPtr; - - int answer = 24; - answer = entry(); - cout << answer; - ASSERT_NE(24, answer); +TEST(InterfaceExternC, 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))); + + 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"); - assert(input != nullptr); +TEST(InterfaceExternC, testStructFields1) { + FILE* input = fopen("scripts/testspass/Containers_Implementation_LinkedList1.xreate", "r"); + assert(input != nullptr); - Scanner scanner(input); - Parser parser(&scanner); - parser.Parse(); + Scanner scanner(input); + Parser parser(&scanner); + parser.Parse(); - AST& ast = parser.root; - CodeScope* body = ast.findFunction("test")->getEntryScope(); + AST& ast = parser.root; + CodeScope* body = ast.findFunction("test")->getEntryScope(); - Symbol symbTree = body->findSymbol("tree"); + Symbol symbTree = body->findSymbol("tree"); const TypeAnnotation& tTree = CodeScope::findDeclaration(symbTree).type; const ExpandedType& t2Tree = ast.expandType(tTree); LLVMLayer llvm(&ast); TypeUtils utils(&llvm); std::vectorfields = utils.getStructFields(t2Tree); auto field = std::find(fields.begin(), fields.end(), "children"); ASSERT_TRUE(field != fields.end()); } diff --git a/cpp/tests/installation.cpp b/cpp/tests/installation.cpp index dd2e1e2..19c48b8 100644 --- a/cpp/tests/installation.cpp +++ b/cpp/tests/installation.cpp @@ -1,22 +1,23 @@ /* * installation.cpp * * Created on: 26 Feb 2016 * Author: pgess */ #include "passmanager.h" #include "gtest/gtest.h" #include using namespace std; using namespace xreate; //TODO replace string identifiers with Atoms in order to hold position, etc -TEST(Sprint1, test1){ +//TODO enable tests. Depends on context loop(test: Context.full_LoopContext) +TEST(Sprint1, DISABLED_test1){ const string filenameSource("scripts/testspass/sprint1-Installation1.xreate"); FILE* fileSource; ASSERT_TRUE(fileSource = fopen(filenameSource.c_str(), "rb")); PassManager* man = PassManager::prepareForCode(fileSource); man->run(); } diff --git a/cpp/tests/interpretation.cpp b/cpp/tests/interpretation.cpp index d092f25..8cc549b 100644 --- a/cpp/tests/interpretation.cpp +++ b/cpp/tests/interpretation.cpp @@ -1,286 +1,352 @@ #include "attachments.h" using namespace xreate; #include "passmanager.h" #include "compilation/targetinterpretation.h" #include "gtest/gtest.h" #include "boost/scoped_ptr.hpp" #define private public #include "Parser.h" #include "pass/interpretationpass.h" using namespace xreate; using namespace xreate::compilation; TEST(Interpretation, Analysis_StatementIF_1){ PassManager* man = PassManager::prepareForCode( R"Code( main = function::int { x = "a":: string. y = if (x=="b"):: string; interpretation(force) { 1 } else { 0 }. 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); ASSERT_EQ(INTR_ONLY, dataSymbolY.resolution); } TEST(Interpretation, Compilation_StatementIF_1){ PassManager* man = PassManager::prepareForCode( R"Code( main = function::int; entry { x = "a":: string. y = if (x=="b"):: string; interpretation(force) { 1 } else { 0 }. y } )Code" ); man->runWithoutCompilation(); 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( R"Code( main = function::int { x = "a":: string; interpretation(force). y = if (x=="b"):: string { 1 } else { 0 }. 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); - ASSERT_EQ(BOTH, dataSymbolY.resolution); + ASSERT_EQ(ANY, dataSymbolY.resolution); ASSERT_EQ(IF_INTERPRET_CONDITION, dataSymbolY.op); } TEST(Interpretation, Compilation_StatementIF_InterpretCondition_1){ PassManager* man = PassManager::prepareForCode( R"Code( main = function::int; entry { x = "a":: string; interpretation(force). y = if (x=="b"):: string { 1 } else { 0 }. y } )Code" ); man->runWithoutCompilation(); 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, Compilation_StatementFOLD_INTERPRET_INPUT_1){ PassManager* man = PassManager::prepareForCode( R"Code( main = function::int; entry { commands = ["inc", "double", "dec"]:: [string]; interpretation(force). loop fold(commands->comm::string, 10->operand):: int{ switch(comm)::int case ("inc"){ operand + 1 } case ("dec"){ operand - 1 } case ("double"){ operand * 2 } } } )Code" ); man->runWithoutCompilation(); 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(21, result); } TEST(Interpretation, StatementCall_RecursionNo_1){ PassManager* man = PassManager::prepareForCode( R"Code( unwrap = function(data::undef, keys::undef):: undef; interpretation(force){ loop fold(keys->key::string, data->a):: undef { a[key] } } start = function::num; entry{ result = unwrap( { a = { b = { c = "core" } } }, ["a", "b", "c"])::undef. result == "core" } )Code" ); man->runWithoutCompilation(); 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( 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(); 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(BOTH, resolutionActual); + 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( 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( +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); + ASSERT_EQ(CMPL_ONLY, dataCallEv.resolution); + ASSERT_EQ(CALL_INTERPRET_PARTIAL, dataCallEv.op); +} + +TEST(Interpretation, PartialIntr_2){ + PassManager* man = PassManager::prepareForCode( +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} + } + + 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(); + + 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) + + + diff --git a/cpp/tests/loops.cpp b/cpp/tests/loops.cpp index 7d1d5d7..efa66a5 100644 --- a/cpp/tests/loops.cpp +++ b/cpp/tests/loops.cpp @@ -1,59 +1,59 @@ #include "passmanager.h" #include "gtest/gtest.h" using namespace std; TEST(Loop, Break1){ - string code = + string code = R"CODE( main = function:: int; entry { input = [0..10]:: [int]. - + loop fold(input->el::int, 0->a)::[int] { if (a>=5)::int { 5:: int; break - + } else {a+el} } } - + )CODE"; - + xreate::PassManager* man = xreate::PassManager::prepareForCode(move(code)); int (*funcMain)() = (int (*)()) man->run(); - + int answerActual = funcMain(); ASSERT_EQ(5, answerActual); } TEST(Loop, InfiniteLoop1){ - - string code = + + string code = R"Code( - interface(extern-c){ - libFake = library:: pkgconfig("libxml-2.0"). - - include { - libFake = ["math.h"] - }. + 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(0->state) :: int { - if (pow(2, state)==32)::int { + 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)); int (*funcMain)() = (int (*)()) man->run(); - + int answerActual = funcMain(); ASSERT_EQ(5, answerActual); } \ No newline at end of file diff --git a/cpp/tests/pass-Logger.cpp b/cpp/tests/pass-Logger.cpp index 46d4ba4..e74577b 100644 --- a/cpp/tests/pass-Logger.cpp +++ b/cpp/tests/pass-Logger.cpp @@ -1,85 +1,86 @@ /* * testLogging.cpp * * Created on: Jun 23, 2015 * Author: pgess */ #include #include "gtest/gtest.h" #include "passmanager.h" #include "llvmlayer.h" #include "Parser.h" using namespace std; using namespace xreate; -TEST(LoggerPass, simpleInjection){ +//TODO fix logger and enable tests. +TEST(LoggerPass, DISABLED_simpleInjection){ PassManager* man = PassManager::prepareForCode("test= function():: int; entry{x = 2+8::int. return x}"); man->runWithoutCompilation(); CompilePass* compiler = new CompilePass(man); compiler->run(); compilation::FunctionUnit* fTest = compiler->getFunctionUnit(man->root->findFunction("test")); ASSERT_NE(fTest, nullptr); compilation::CodeScopeUnit* scopeUnitTest = fTest->getEntry(); CodeScope* scopeTest = scopeUnitTest->scope; Symbol symbX = scopeTest->findSymbol("x"); TypeAnnotation typX = CodeScope::findDeclaration(symbX).type; llvm::Value* retRaw = scopeUnitTest->compile(); llvm::BasicBlock& blockTestRaw = fTest->raw->getEntryBlock(); LLVMLayer* llvm = man->llvm; //llvm->builder.SetInsertPoint(&blockTestRaw); compilation::Context params{scopeUnitTest, fTest, compiler}; LoggerPass l(man); l.inject(symbX, params); llvm->initJit(); int (*f)() = (int(*)()) llvm->getFunctionPointer(fTest->raw); testing::internal::CaptureStdout(); f(); std::string&& output = testing::internal::GetCapturedStdout(); EXPECT_STREQ("10\n", output.c_str()); } -TEST(LoggerPass, simpleInjection2){ +TEST(LoggerPass, DISABLED_simpleInjection2){ PassManager* man = PassManager::prepareForCode("test= function():: int; entry{x = 2+8::int; logging. x}"); man->runWithoutCompilation(); CompilePass* compiler= new CompilePass(man); compiler->run(); LoggerPass* logger = new LoggerPass(man); logger->initDependencies(compiler); logger->run(); man->llvm->initJit(); man->llvm->print(); int (*f)() = (int(*)()) man->llvm->getFunctionPointer(compiler->getEntryFunction()); testing::internal::CaptureStdout(); f(); std::string&& output = testing::internal::GetCapturedStdout(); EXPECT_STREQ("10\n", output.c_str()); } -TEST(LoggerPass, simpleInjection3){ +TEST(LoggerPass, DISABLED_simpleInjection3){ FILE* input = fopen("scripts/cases/log.xreate","r"); assert(input); std::unique_ptr program(PassManager::prepareForCode(input)); void* mainPtr = program->run(); int (*main)() = (int (*)())(intptr_t)mainPtr; int answer = main(); fclose(input); } diff --git a/cpp/tests/types.cpp b/cpp/tests/types.cpp index 97e2354..d90a673 100644 --- a/cpp/tests/types.cpp +++ b/cpp/tests/types.cpp @@ -1,167 +1,167 @@ /* * types.cpp * * Created on: Jun 4, 2015 * Author: pgess */ #include "gtest/gtest.h" #include "passmanager.h" #include "llvmlayer.h" #include "Parser.h" using namespace std; using namespace xreate; TEST(Types, DependantTypes1) { string&& code = "XmlNode = type alias {\n" " tag:: string,\n" " /* attrs:: [string],*/\n" " content:: string\n" "}.\n"; std::unique_ptr program(PassManager::prepareForCode(move(code))); ExpandedType typeXmlNode = program->root->findType("XmlNode"); ASSERT_EQ(TypeOperator::STRUCT, typeXmlNode->__operator); ASSERT_EQ(2, typeXmlNode->__operands.size()); ASSERT_EQ(TypePrimitive::String, typeXmlNode->__operands.at(0).__value); ASSERT_EQ(TypePrimitive::String, typeXmlNode->__operands.at(1).__value); } TEST(Types, DependantTypes2) { string&& code = "XmlNode = type alias {\n" " tag:: string,\n" " /* attrs:: [string],*/\n" " content:: string\n" "}.\n" "" "Template = type Template(Leaf) [Leaf, [Leaf[content]]]." "Concrete = type alias Template(XmlNode)."; std::unique_ptr program(PassManager::prepareForCode(move(code))); ExpandedType typeConcrete = program->root->findType("Concrete"); ASSERT_EQ(TypeOperator::TUPLE, typeConcrete->__operator); ASSERT_EQ(2, typeConcrete->__operands.size()); ASSERT_EQ(TypeOperator::STRUCT, typeConcrete->__operands.at(0).__operator); ASSERT_EQ(TypeOperator::ARRAY, typeConcrete->__operands.at(1).__operator); ASSERT_EQ(TypePrimitive::String, typeConcrete->__operands.at(1).__operands.at(0).__value); } TEST(Types, TreeType1) { string&& code = "XmlNode = type alias {\n" " tag:: string,\n" " /* attrs:: [string],*/\n" " content:: string\n" "}.\n" "" "Tree = type Tree(Leaf) [Leaf, [Tree(Leaf)]]." "Concrete = type alias Tree(XmlNode)."; std::unique_ptr program(PassManager::prepareForCode(move(code))); ExpandedType typeConcrete = program->root->findType("Concrete"); ASSERT_EQ(TypeOperator::TUPLE, typeConcrete->__operator); ASSERT_EQ(2, typeConcrete->__operands.size()); ASSERT_EQ(TypeOperator::STRUCT, typeConcrete->__operands.at(0).__operator); ASSERT_EQ(TypeOperator::ARRAY, typeConcrete->__operands.at(1).__operator); auto typeLink = typeConcrete->__operands.at(1).__operands.at(0); ASSERT_EQ(TypeOperator::LINK, typeLink.__operator); ASSERT_EQ(typeConcrete->conjuctionId,typeLink.conjuctionId); } TEST(Types, TreeType1LLvm){ string&& code = "XmlNode = type alias {\n" " tag:: string,\n" " /* attrs:: [string],*/\n" " content:: string\n" "}.\n" "" "Tree = type Tree(Leaf) [Leaf, [Tree(Leaf)]]." "Concrete = type alias Tree(XmlNode)."; std::unique_ptr program(PassManager::prepareForCode(move(code))); ExpandedType typeConcrete = program->root->findType("Concrete"); llvm::Type* raw = program->llvm->toLLVMType(typeConcrete); } TEST(Types, ArrayOfExternal1){ FILE* input = fopen("scripts/testspass/Containers_Implementation_LinkedList1.xreate","r"); assert(input != nullptr); Scanner scanner(input); Parser parser(&scanner); parser.Parse(); AST& ast = parser.root; CodeScope* body = ast.findFunction("test")->getEntryScope(); Symbol symb = body->findSymbol("childrenRaw"); const TypeAnnotation& t = CodeScope::findDeclaration(symb).type; const ExpandedType& t2 = ast.expandType(t); EXPECT_EQ(t2->__operator, TypeOperator::ARRAY); } TEST(Types, ExternType1){ FILE* input = fopen("scripts/testspass/Containers_Implementation_LinkedList1.xreate","r"); assert(input != nullptr); Scanner scanner(input); Parser parser(&scanner); parser.Parse(); AST& ast = parser.root; CodeScope* body = ast.findFunction("test")->getEntryScope(); Symbol symbTree = body->findSymbol("tree"); const TypeAnnotation& t = CodeScope::findDeclaration(symbTree).type; const ExpandedType& t2 = ast.expandType(t); EXPECT_EQ(t2->__operator, TypeOperator::CUSTOM); } TEST(Types, ast_VariantType1){ string&& code = " colors = type variant (RED, BLUE, GREEN).\n" " test = function:: colors; entry {GREEN}"; std::unique_ptr program(PassManager::prepareForCode(move(code))); ExpandedType typ = program->root->findType("colors"); EXPECT_EQ(TypeOperator::VARIANT, typ->__operator); - Expression eRed = program->root->findFunction("test")->getEntryScope()->__body; + Expression eRed = program->root->findFunction("test")->getEntryScope()->getBody(); EXPECT_EQ(Expression::VARIANT, eRed.__state); const ExpandedType& typ2 = program->root->expandType(eRed.type); EXPECT_EQ(TypeOperator::VARIANT, typ2->__operator); program->run(); } TEST(Types, full_VariantType_Switch1){ string&& code = - " colors = type variant (RED, BLUE, GREEN).\n" - " test = function:: colors; entry {GREEN}" + " colors = type variant (RED, BLUE, GREEN). \n" + " test = function:: colors {GREEN} \n" - "main = function:: int; entry {\n" - " switch(test():: color)\n" - " case GREEN {0}\n" - " case default {1}\n" + "main = function:: int; entry { \n" + " switch(test()):: int \n" + " case GREEN {0} \n" + " case default {1} \n" "}"; PassManager* man = PassManager::prepareForCode(move(code)); int (*main)() = (int (*)()) man->run(); EXPECT_EQ(0, main()); } //TOTEST string type diff --git a/cpp/tests/xml.cpp b/cpp/tests/xml.cpp index 653f60e..13b312a 100644 --- a/cpp/tests/xml.cpp +++ b/cpp/tests/xml.cpp @@ -1,29 +1,29 @@ #include "passmanager.h" #include "gtest/gtest.h" #include using namespace xreate; -TEST(Xml, Main){ +TEST(Xml, DISABLED_Main){ FILE* input = fopen("scripts/testspass/xml-test1.xreate", "r"); assert(input); std::unique_ptr program(PassManager::prepareForCode(input)); void* mainPtr = program->run(); int (*main)() = (int (*)())(intptr_t)mainPtr; int answer = main(); } TEST(Xml, DISABLED_AliasTuple){ } TEST(Xml, DISABLED_FoldProtoEnhanced){ } TEST(Xml, DISABLED_TransfucPropagation){ } diff --git a/documentation-tools/RemarkupParser/CMakeLists.txt b/documentation-tools/RemarkupParser/CMakeLists.txt index d2f6ef6..3ddbfbe 100644 --- a/documentation-tools/RemarkupParser/CMakeLists.txt +++ b/documentation-tools/RemarkupParser/CMakeLists.txt @@ -1,23 +1,23 @@ project(RemarkupParser) aux_source_directory(cpp/ SRC_LIST) set(SRC_LIST ${SRC_LIST} gen-cpp/PhabricatorParserPrivate.cpp gen-cpp/remarkup_constants.cpp gen-cpp/remarkup_types.cpp ) include_directories(cpp/ gen-cpp/) set(REMARKUP_PARSER_INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/cpp/ ${CMAKE_CURRENT_SOURCE_DIR}/gen-cpp/ CACHE INTERNAL "REMARKUP_PARSER: Include Directories" FORCE ) add_library(${PROJECT_NAME} SHARED ${SRC_LIST}) -target_link_libraries(${PROJECT_NAME} thrift-1.0.0-dev Qt5::Core) +target_link_libraries(${PROJECT_NAME} thrift Qt5::Core) set(CMAKE_BUILD_TYPE Debug) diff --git a/documentation-tools/RemarkupParser/shared.thrift b/documentation-tools/RemarkupParser/shared.thrift deleted file mode 100644 index 386000b..0000000 --- a/documentation-tools/RemarkupParser/shared.thrift +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -/** - * This Thrift file can be included by other Thrift files that want to share - * these definitions. - */ - -namespace cpp shared -namespace d share // "shared" would collide with the eponymous D keyword. -namespace dart shared -namespace java shared -namespace perl shared -namespace php shared -namespace haxe shared - -struct SharedStruct { - 1: i32 key - 2: string value -} - -service SharedService { - SharedStruct getStruct(1: i32 key) -} diff --git a/documentation-tools/RemarkupParser/test/main.cpp b/documentation-tools/RemarkupParser/test/main.cpp deleted file mode 100644 index 5361187..0000000 --- a/documentation-tools/RemarkupParser/test/main.cpp +++ /dev/null @@ -1,46 +0,0 @@ -#include - -#include -#include -#include - -#include "gen-cpp/PhabricatorParserPrivate.h" - -using namespace std; -using namespace apache::thrift; -using namespace apache::thrift::protocol; -using namespace apache::thrift::transport; - -int main() { - boost::shared_ptr socket(new TSocket("/tmp/phabricator-parser")); - boost::shared_ptr transport(new TBufferedTransport(socket)); - boost::shared_ptr protocol(new TBinaryProtocol(transport)); - PhabricatorParserPrivateClient client(protocol); - - string text = -"= Large Header = \n \ - \n\ -== Smaller Header == \n\ - \n\ -## This is a Header As Well\n\ - \n\ -Also a Large Header \n\ -=================== \n\ - \n\ -Also a Smaller Header \n\ ----------------------"; - try { - transport->open(); - - - for (int i=0; i Map from one type to another - * list Ordered list of one type - * set Set of unique elements of one type - * - * Did you also notice that Thrift supports C style comments? - */ - -// Just in case you were wondering... yes. We support simple C comments too. - -/** - * Thrift files can reference other Thrift files to include common struct - * and service definitions. These are found using the current path, or by - * searching relative to any paths specified with the -I compiler flag. - * - * Included objects are accessed using the name of the .thrift file as a - * prefix. i.e. shared.SharedObject - */ -include "shared.thrift" - -/** - * Thrift files can namespace, package, or prefix their output in various - * target languages. - */ -namespace cpp tutorial -namespace d tutorial -namespace dart tutorial -namespace java tutorial -namespace php tutorial -namespace perl tutorial -namespace haxe tutorial - -/** - * Thrift lets you do typedefs to get pretty names for your types. Standard - * C style here. - */ -typedef i32 MyInteger - -/** - * Thrift also lets you define constants for use across languages. Complex - * types and structs are specified using JSON notation. - */ -const i32 INT32CONSTANT = 9853 -const map MAPCONSTANT = {'hello':'world', 'goodnight':'moon'} - -/** - * You can define enums, which are just 32 bit integers. Values are optional - * and start at 1 if not supplied, C style again. - */ -enum Operation { - ADD = 1, - SUBTRACT = 2, - MULTIPLY = 3, - DIVIDE = 4 -} - -/** - * Structs are the basic complex data structures. They are comprised of fields - * which each have an integer identifier, a type, a symbolic name, and an - * optional default value. - * - * Fields can be declared "optional", which ensures they will not be included - * in the serialized output if they aren't set. Note that this requires some - * manual management in some languages. - */ -struct Work { - 1: i32 num1 = 0, - 2: i32 num2, - 3: Operation op, - 4: optional string comment, -} - -/** - * Structs can also be exceptions, if they are nasty. - */ -exception InvalidOperation { - 1: i32 whatOp, - 2: string why -} - -/** - * Ahh, now onto the cool part, defining a service. Services just need a name - * and can optionally inherit from another service using the extends keyword. - */ -service Calculator extends shared.SharedService { - - /** - * A method definition looks like C code. It has a return type, arguments, - * and optionally a list of exceptions that it may throw. Note that argument - * lists and exception lists are specified using the exact same syntax as - * field lists in struct or exception definitions. - */ - - void ping(), - - i32 add(1:i32 num1, 2:i32 num2), - - i32 calculate(1:i32 logid, 2:Work w) throws (1:InvalidOperation ouch), - - /** - * This method has a oneway modifier. That means the client only makes - * a request and does not listen for any response at all. Oneway methods - * must be void. - */ - oneway void zip() - -} - -/** - * That just about covers the basics. Take a look in the test/ folder for more - * detailed examples. After you run this file, your generated code shows up - * in folders with names gen-. The generated code isn't too scary - * to look at. It even has pretty indentation. - */ diff --git a/documentation-tools/conduit-client-example.cpp b/documentation-tools/conduit-client-example.cpp deleted file mode 100644 index 04bae68..0000000 --- a/documentation-tools/conduit-client-example.cpp +++ /dev/null @@ -1,16 +0,0 @@ -#include -#include "phrictionclient.h" -#include - -using namespace std; - -int main(int argc, char** argv) -{ - QCoreApplication a(argc, argv); - - PhrictionClient c("http://192.168.11.130:80/api", "user", "api-ko4x6j4hujleutuxlntdqj37wfjj", "bydxwfn7pey6ack274dilywrgakkhjpmwrgieedqxlnxpocwovisz3ysgndzagtmft33e2tx3xyatwklzbrrzhyyonibim7nwbnpqo36fmer7hjvv5mmmammxf3fybqn52dgsmczrj44e4l4r774ajyiydmcxughsttgonydjsgf3b2rmvtunjtez4zbtcqmwrhjl3aijv22jefvymu2oz3tzu3zlv4lk226riq5utudndd6ae4ixzqmzyo6pqr"); - c.create(); - - return a.exec(); -} - diff --git a/documentation-tools/juffed-lexers/qscilexerremarkup.cpp b/documentation-tools/juffed-lexers/qscilexerremarkup.cpp index 1e3c3b5..37f2e7e 100644 --- a/documentation-tools/juffed-lexers/qscilexerremarkup.cpp +++ b/documentation-tools/juffed-lexers/qscilexerremarkup.cpp @@ -1,171 +1,161 @@ #include "qscilexerremarkup.h" #include #include -enum - { - Default = 0, - Hidden, - Bold, - Italic, - Del, - DocumentLink, - EscapeRemarkup, - Hightlight, - HyperLink, - - Monospace, - Underline - }; - QRegularExpression patternBold("\\*\\*(.+?)\\*\\*"); QRegularExpression patternItalic("(?SendScintilla(QsciScintilla::SCI_GETTEXTRANGE, start, end, chars); QString source = QString::fromUtf8(chars); delete [] chars; runPhutilRemarkupBoldRule(source,start); runPhutilRemarkupItalicRule(source,start); } void QsciLexerRemarkup::runPhutilRemarkupBoldRule(const QString& source, int index){ int pos =0; while(true) { QRegularExpressionMatch result = patternBold.match(source, pos); if (!result.hasMatch()){break;} //hide: startStyling(index + result.capturedStart(0)); - setStyling(result.capturedLength(0), Hidden); + setStyling(result.capturedLength(0), (int) QsciLexerRemarkupStyles::Hidden); QString r = result.captured(1); startStyling(index + result.capturedStart(1)); - setStyling(result.capturedLength(1), Bold); + setStyling(result.capturedLength(1), (int) QsciLexerRemarkupStyles::Bold); pos = result.capturedEnd(1) + 1; } } void QsciLexerRemarkup::runPhutilRemarkupItalicRule(const QString& source, int index){ int pos =0; while(true) { QRegularExpressionMatch result = patternItalic.match(source, pos); if (!result.hasMatch()){break;} //hide: startStyling(index + result.capturedStart(0)); - setStyling(result.capturedLength(0), Hidden); + setStyling(result.capturedLength(0), (int) QsciLexerRemarkupStyles::Hidden); startStyling(index + result.capturedStart(1)); - setStyling(result.capturedLength(1), Italic); + setStyling(result.capturedLength(1), (int) QsciLexerRemarkupStyles::Italic); pos = result.capturedEnd(1) + 1; } } //"PhutilRemarkupBoldRule.php: **bold** //PhutilRemarkupItalicRule.php: //italic// /* "PhutilRemarkupDelRule.php" "PhutilRemarkupDocumentLinkRule.php" "PhutilRemarkupEscapeRemarkupRule.php" "PhutilRemarkupHighlightRule.php" "PhutilRemarkupHyperlinkRule.php" "PhutilRemarkupLinebreaksRule.php" "PhutilRemarkupMonospaceRule.php" "PhutilRemarkupRule.php" "PhutilRemarkupUnderlineRule.php" */ diff --git a/documentation-tools/juffed-lexers/qscilexerremarkup.h b/documentation-tools/juffed-lexers/qscilexerremarkup.h index 597319d..f815777 100644 --- a/documentation-tools/juffed-lexers/qscilexerremarkup.h +++ b/documentation-tools/juffed-lexers/qscilexerremarkup.h @@ -1,29 +1,45 @@ #ifndef QSCILEXERREMARKUP_H #define QSCILEXERREMARKUP_H #include #include class QsciLexerRemarkup : public QsciLexerCustom { Q_OBJECT public: virtual QColor defaultColor(int style) const; virtual QFont defaultFont(int style) const; virtual QColor defaultPaper(int style) const; QsciStyle getStyle(int style); QsciLexerRemarkup(QObject * parent = 0); ~QsciLexerRemarkup(); void styleText(int start, int end); QString description(int style) const; const char* language() const; private: void runPhutilRemarkupBoldRule(const QString& source, int index); void runPhutilRemarkupItalicRule(const QString& source, int index); }; +enum class QsciLexerRemarkupStyles + { + Default = 0, + Hidden, + Bold, + Italic, + Del, + DocumentLink, + EscapeRemarkup, + Hightlight, + HyperLink, + + Monospace, + Underline +}; + #endif // QSCILEXERREMARKUP_H diff --git a/scripts/metatests/exploitation-test1.lp b/scripts/metatests/exploitation-test1.lp deleted file mode 100644 index c217721..0000000 --- a/scripts/metatests/exploitation-test1.lp +++ /dev/null @@ -1,10 +0,0 @@ -#include "core/precompilation.lp". -#include "core/exploitation.lp". - -#include "scripts/exploitation/test1-fixture.lp". - -#show bind/2. -#show expl_sites/2. -#show expl_resources/2. -#show expl_parent/2. -#show bind_scope/2. diff --git a/scripts/metatests/tests1-context-latecontext3.lp b/scripts/metatests/tests1-context-latecontext3.lp deleted file mode 100644 index f344ff0..0000000 --- a/scripts/metatests/tests1-context-latecontext3.lp +++ /dev/null @@ -1,75 +0,0 @@ -#include "core/control-context-v3.lp". -function(a1;b1;a2;b2;a3;b3; sink; fnOut). -scope(0..7). - - %CFA -cfa_parent(0, function(a1)). -cfa_parent(1, function(b1)). -cfa_parent(2, function(a2)). -cfa_parent(3, function(b2)). -cfa_parent(4, function(a3)). -cfa_parent(5, function(b3)). - -cfa_parent(6, function(sink)). -cfa_parent(7, function(fnOut)). - -cfa_function_specializations(fnOut, keys(keyA1A2A3)). -cfa_function_specializations(fnOut, keys(keyA1A2B3)). -cfa_function_specializations(fnOut, keys(keyA1B2A3)). -cfa_function_specializations(fnOut, keys(keyA1B2B3)). -cfa_function_specializations(fnOut, keys(keyB1A2A3)). -cfa_function_specializations(fnOut, keys(keyB1A2B3)). -cfa_function_specializations(fnOut, keys(keyB1B2A3)). -cfa_function_specializations(fnOut, keys(keyB1B2B3)). - - -cfa_call(0, a2). -cfa_call(0, b2). -cfa_call(1, a2). -cfa_call(1, b2). -cfa_call(2, a3). -cfa_call(2, b3). -cfa_call(3, a3). -cfa_call(3, b3). -cfa_call(4, sink). -cfa_call(5, sink). -cfa_call(6, fnOut). - - %context rules - % r0: keyA->keyA0, keyB->keyB0 - % r1: keyA->keyA1, keyB->keyB1 -bind_scope(2, keys(keyA1A2), Info) :- bind_scope(2, keys(keyA1), Info). -bind_scope(2, keys(keyB1A2), Info) :- bind_scope(2, keys(keyB1), Info). -bind_scope(3, keys(keyA1B2), Info) :- bind_scope(3, keys(keyA1), Info). -bind_scope(3, keys(keyB1B2), Info) :- bind_scope(3, keys(keyB1), Info). - -bind_scope(4, keys(keyA1A2A3), Info):-bind_scope(4, keys(keyA1A2), Info). -bind_scope(4, keys(keyB1A2A3), Info):-bind_scope(4, keys(keyB1A2), Info). -bind_scope(4, keys(keyA1B2A3), Info):-bind_scope(4, keys(keyA1B2), Info). -bind_scope(4, keys(keyB1B2A3), Info):-bind_scope(4, keys(keyB1B2), Info). - -bind_scope(5, keys(keyA1A2B3), Info):-bind_scope(5, keys(keyA1A2), Info). -bind_scope(5, keys(keyB1A2B3), Info):-bind_scope(5, keys(keyB1A2), Info). -bind_scope(5, keys(keyA1B2B3), Info):-bind_scope(5, keys(keyA1B2), Info). -bind_scope(5, keys(keyB1B2B3), Info):-bind_scope(5, keys(keyB1B2), Info). - - - %initial context -keys( - keyA1; keyB1; - keyA1A2; - keyB1A2; - keyA1B2; - keyB1B2; - keyA1A2A3; - keyA1A2B3; - keyA1B2A3; - keyA1B2B3; - keyB1A2A3; - keyB1A2B3; - keyB1B2A3; - keyB1B2B3 -). - -bind_scope(0, keys(keyA1), strong). -bind_scope(1, keys(keyB1), strong). diff --git a/scripts/sprint1_environment/(invalid)tests-context.lp b/scripts/sprint1_environment/(invalid)tests-context.lp deleted file mode 100644 index 8559a15..0000000 --- a/scripts/sprint1_environment/(invalid)tests-context.lp +++ /dev/null @@ -1,28 +0,0 @@ -#include "control-context.lp". - -%body - function(a). - function(b). - function(c). - - scope(0..3). - cfa_call(0, c). - cfa_call(1, c). - cfa_parent(0, function(a)). - cfa_parent(1, function(b)). - cfa_parent(2, function(c)). - cfa_parent(3, scope(2)). - - bind_scope(0, weak(a)). - bind_scope(1, weak(b)). - - bind_scope(0, hard). - bind_scope(1, hard). - -%test weak and hard context - :- bind_scope(2, weak(_)). - :- not bind_scope(2, hard). - -%test rules: - bind_scope(X, rule) :- bind_scope(X, hard), context_rule_visibility(X, 2). - :- not bind_scope(3, rule). diff --git a/scripts/sprint1_environment/context-latecontext1.lp b/scripts/sprint1_environment/context-latecontext1.lp deleted file mode 100644 index 536cdd3..0000000 --- a/scripts/sprint1_environment/context-latecontext1.lp +++ /dev/null @@ -1,26 +0,0 @@ -#include "control-context.lp". - -%body -function(a;b;c;d). -scope(0..4). -cfa_parent(0, function(a)). -cfa_parent(1, function(b)). -cfa_parent(2, function(c)). -cfa_parent(3, function(d)). -cfa_parent(4, function(d)). - -cfa_call(0, c). -cfa_call(1, c). -cfa_call(2, d). - -bind_scope(0, a). -bind_scope(1, b). - -cfa_function_specializations(d, a). -cfa_function_specializations(d, b). - -#show bind_scope_decision/3. -%#show bind_scope_demand/2. -#show bind_function_demand/2. -%#show cfa_call/2. -%#show bind_function_demand/2. \ No newline at end of file diff --git a/scripts/sprint1_environment/context-latecontext2.lp b/scripts/sprint1_environment/context-latecontext2.lp deleted file mode 100644 index b8c9195..0000000 --- a/scripts/sprint1_environment/context-latecontext2.lp +++ /dev/null @@ -1,67 +0,0 @@ -%#include "control-context.lp". - -function(a;b;c). -scope(0..2). - - %general -cfa_parent(0, function(a)). -cfa_parent(1, function(b)). -cfa_parent(2, function(c)). - -cfa_call(0, c). -cfa_call(1, c). - - %additional -keys(key0; key1). -data(key0, x). -data(key0, y). -data(key1, m). -data(key1, n). - -bind_scope(0, keys(key0), strong). -bind_scope(1, keys(key1), strong). - -%bind_scope(0, a, strong). -%bind_scope(0, b, strong). -%bind_scope(1, a, strong). -%bind_scope(1, c, strong). - -bind_scope(2, set(X), Options):- bind_scope(2, keys(Key), Options), data(Key, X). - - %nested scope propagation: -bind_scope(Scope, Context, Info) :- bind_scope(ScopeParent, Context, Info), cfa_parent(Scope, scope(ScopeParent)). - - %strong inter-function propagation: -bind_scope(Scope, Context,strong) :- bind_scope(ScopeParent, Context, strong): cfa_call(ScopeParent, FnCurrent); cfa_parent(Scope, function(FnCurrent)); cfa_call(_, FnCurrent); bind_scope(_, Context, strong); 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(Id)):- nbind_scope(Scope, Context, strong), bind_scope(ScopeParent, Context, weak(Id)), 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). - - %demand -% bind_scope_demand(Scope, loop(Subject)):- cfa_contextloop(Scope, Subject), not bind_scope_decision(Scope, loop(Subject), _). - - %nested scope demand propagation -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, _). - - - -% GENERATED DECLARATIONS FOR DECISION DEPENDENCIES -% -- cfa_contextloop(Scope, $set) => demand_dependency(loop(set), X) :- bind_scope($ScopeId, X = $set(_), weak(_)). -demand_dependency(loop(set), X) :- bind_scope(2, X, weak(_)), X = set(_). - -% -- rule($Conditon, %Result) => demand_dependency(loop(X), $Condition) :- demand_dependency(loop(X), $Result) -demand_dependency(loop(X), keys(Key)) :- demand_dependency(loop(X), set(Y)), bind_scope(_, keys(Key), _). - - -cfa_contextloop(2, set). - -#show bind_scope/3. diff --git a/scripts/sprint1_environment/context-latecontext3.lp b/scripts/sprint1_environment/context-latecontext3.lp deleted file mode 100644 index ca81a77..0000000 --- a/scripts/sprint1_environment/context-latecontext3.lp +++ /dev/null @@ -1,48 +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. - %% - - %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_decision(ScopeSource, dependency(Subject, Scope), Dependency) :- Dependency = weak(ScopeSource), bind_scope_demand(Scope, dependency(Subject, Scope)), scope_dependencies(dependency(Subject, Scope), 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). - - %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/scripts/sprint1_environment/control-context.lp b/scripts/sprint1_environment/control-context.lp deleted file mode 120000 index 86bd292..0000000 --- a/scripts/sprint1_environment/control-context.lp +++ /dev/null @@ -1 +0,0 @@ -/private/prg/code/xreate/core/control-context.lp \ No newline at end of file diff --git a/scripts/sprint1_environment/dependencies.lp b/scripts/sprint1_environment/dependencies.lp deleted file mode 120000 index 5d00940..0000000 --- a/scripts/sprint1_environment/dependencies.lp +++ /dev/null @@ -1 +0,0 @@ -/private/prg/code/xreate/core/graphs_trees_depth.lp \ No newline at end of file diff --git a/scripts/sprint1_environment/solution-latecontext-3layers b/scripts/sprint1_environment/solution-latecontext-3layers deleted file mode 100644 index 2d13d91..0000000 --- a/scripts/sprint1_environment/solution-latecontext-3layers +++ /dev/null @@ -1,192 +0,0 @@ - -bind_function_demand(a2,dependency(dependency(specialization(fnOut,6),4),2)) -bind_function_demand(a2,dependency(dependency(specialization(fnOut,6),5),2)) -bind_function_demand(a2,dependency(specialization(fnOut,6),2)) -bind_function_demand(a3,dependency(specialization(fnOut,6),4)) -bind_function_demand(b2,dependency(dependency(specialization(fnOut,6),4),3)) -bind_function_demand(b2,dependency(dependency(specialization(fnOut,6),5),3)) -bind_function_demand(b2,dependency(specialization(fnOut,6),3)) -bind_function_demand(b3,dependency(specialization(fnOut,6),5)) -bind_function_demand(sink,specialization(fnOut,6)) - -bind_scope_demand(2,dependency(dependency(specialization(fnOut,6),4),2)) -bind_scope_demand(2,dependency(dependency(specialization(fnOut,6),5),2)) -bind_scope_demand(2,dependency(specialization(fnOut,6),2)) -bind_scope_demand(3,dependency(dependency(specialization(fnOut,6),4),3)) -bind_scope_demand(3,dependency(dependency(specialization(fnOut,6),5),3)) -bind_scope_demand(3,dependency(specialization(fnOut,6),3)) -bind_scope_demand(4,dependency(specialization(fnOut,6),4)) -bind_scope_demand(5,dependency(specialization(fnOut,6),5)) -bind_scope_demand(6,specialization(fnOut,6)) - -bind_scope_decision(0,dependency(dependency(specialization(fnOut,6),4),2),weak(0)) -bind_scope_decision(0,dependency(dependency(specialization(fnOut,6),4),3),weak(0)) -bind_scope_decision(0,dependency(dependency(specialization(fnOut,6),5),2),weak(0)) -bind_scope_decision(0,dependency(dependency(specialization(fnOut,6),5),3),weak(0)) -bind_scope_decision(0,dependency(specialization(fnOut,6),2),weak(0)) -bind_scope_decision(0,dependency(specialization(fnOut,6),3),weak(0)) -bind_scope_decision(1,dependency(dependency(specialization(fnOut,6),4),2),weak(1)) -bind_scope_decision(1,dependency(dependency(specialization(fnOut,6),4),3),weak(1)) -bind_scope_decision(1,dependency(dependency(specialization(fnOut,6),5),2),weak(1)) -bind_scope_decision(1,dependency(dependency(specialization(fnOut,6),5),3),weak(1)) -bind_scope_decision(1,dependency(specialization(fnOut,6),2),weak(1)) -bind_scope_decision(1,dependency(specialization(fnOut,6),3),weak(1)) -bind_scope_decision(2,dependency(specialization(fnOut,6),4),resolution_dependency(weak(2,weak(0)),weak(0))) -bind_scope_decision(2,dependency(specialization(fnOut,6),4),resolution_dependency(weak(2,weak(1)),weak(1))) -bind_scope_decision(2,dependency(specialization(fnOut,6),5),resolution_dependency(weak(2,weak(0)),weak(0))) -bind_scope_decision(2,dependency(specialization(fnOut,6),5),resolution_dependency(weak(2,weak(1)),weak(1))) -bind_scope_decision(3,dependency(specialization(fnOut,6),4),resolution_dependency(weak(3,weak(0)),weak(0))) -bind_scope_decision(3,dependency(specialization(fnOut,6),4),resolution_dependency(weak(3,weak(1)),weak(1))) -bind_scope_decision(3,dependency(specialization(fnOut,6),5),resolution_dependency(weak(3,weak(0)),weak(0))) -bind_scope_decision(3,dependency(specialization(fnOut,6),5),resolution_dependency(weak(3,weak(1)),weak(1))) -bind_scope_decision(4,specialization(fnOut,6),resolution_dependency(keys(keyA1A2A3),weak(2,weak(0)))) -bind_scope_decision(4,specialization(fnOut,6),resolution_dependency(keys(keyA1B2A3),weak(3,weak(0)))) -bind_scope_decision(4,specialization(fnOut,6),resolution_dependency(keys(keyB1A2A3),weak(2,weak(1)))) -bind_scope_decision(4,specialization(fnOut,6),resolution_dependency(keys(keyB1B2A3),weak(3,weak(1)))) -bind_scope_decision(5,specialization(fnOut,6),resolution_dependency(keys(keyA1A2B3),weak(2,weak(0)))) -bind_scope_decision(5,specialization(fnOut,6),resolution_dependency(keys(keyA1B2B3),weak(3,weak(0)))) -bind_scope_decision(5,specialization(fnOut,6),resolution_dependency(keys(keyB1A2B3),weak(2,weak(1)))) -bind_scope_decision(5,specialization(fnOut,6),resolution_dependency(keys(keyB1B2B3),weak(3,weak(1)))) - -scope_dependencies(dependency(dependency(specialization(fnOut,6),4),2),weak(0)) -scope_dependencies(dependency(dependency(specialization(fnOut,6),4),2),weak(1)) -scope_dependencies(dependency(dependency(specialization(fnOut,6),4),3),weak(0)) -scope_dependencies(dependency(dependency(specialization(fnOut,6),4),3),weak(1)) -scope_dependencies(dependency(dependency(specialization(fnOut,6),5),2),weak(0)) -scope_dependencies(dependency(dependency(specialization(fnOut,6),5),2),weak(1)) -scope_dependencies(dependency(dependency(specialization(fnOut,6),5),3),weak(0)) -scope_dependencies(dependency(dependency(specialization(fnOut,6),5),3),weak(1)) -scope_dependencies(dependency(specialization(fnOut,6),2),weak(0)) -scope_dependencies(dependency(specialization(fnOut,6),2),weak(1)) -scope_dependencies(dependency(specialization(fnOut,6),3),weak(0)) -scope_dependencies(dependency(specialization(fnOut,6),3),weak(1)) -scope_dependencies(dependency(specialization(fnOut,6),4),weak(2,weak(0))) -scope_dependencies(dependency(specialization(fnOut,6),4),weak(2,weak(1))) -scope_dependencies(dependency(specialization(fnOut,6),4),weak(3,weak(0))) -scope_dependencies(dependency(specialization(fnOut,6),4),weak(3,weak(1))) -scope_dependencies(dependency(specialization(fnOut,6),5),weak(2,weak(0))) -scope_dependencies(dependency(specialization(fnOut,6),5),weak(2,weak(1))) -scope_dependencies(dependency(specialization(fnOut,6),5),weak(3,weak(0))) -scope_dependencies(dependency(specialization(fnOut,6),5),weak(3,weak(1))) - -bind_scope(0,keys(keyA1),strong) -bind_scope(1,keys(keyB1),strong) -bind_scope(2,keys(keyA1),weak(0)) -bind_scope(2,keys(keyA1A2),weak(0)) -bind_scope(2,keys(keyB1),weak(1)) -bind_scope(2,keys(keyB1A2),weak(1)) -bind_scope(3,keys(keyA1),weak(0)) -bind_scope(3,keys(keyA1B2),weak(0)) -bind_scope(3,keys(keyB1),weak(1)) -bind_scope(3,keys(keyB1B2),weak(1)) -bind_scope(4,keys(keyA1),weak(0)) -bind_scope(4,keys(keyA1A2),weak(2,weak(0))) -bind_scope(4,keys(keyA1A2A3),weak(2,weak(0))) -bind_scope(4,keys(keyA1B2),weak(3,weak(0))) -bind_scope(4,keys(keyA1B2A3),weak(3,weak(0))) -bind_scope(4,keys(keyB1),weak(1)) -bind_scope(4,keys(keyB1A2),weak(2,weak(1))) -bind_scope(4,keys(keyB1A2A3),weak(2,weak(1))) -bind_scope(4,keys(keyB1B2),weak(3,weak(1))) -bind_scope(4,keys(keyB1B2A3),weak(3,weak(1))) -bind_scope(5,keys(keyA1),weak(0)) -bind_scope(5,keys(keyA1A2),weak(2,weak(0))) -bind_scope(5,keys(keyA1A2B3),weak(2,weak(0))) -bind_scope(5,keys(keyA1B2),weak(3,weak(0))) -bind_scope(5,keys(keyA1B2B3),weak(3,weak(0))) -bind_scope(5,keys(keyB1),weak(1)) -bind_scope(5,keys(keyB1A2),weak(2,weak(1))) -bind_scope(5,keys(keyB1A2B3),weak(2,weak(1))) -bind_scope(5,keys(keyB1B2),weak(3,weak(1))) -bind_scope(5,keys(keyB1B2B3),weak(3,weak(1))) -bind_scope(6,keys(keyA1),weak(0)) -bind_scope(6,keys(keyA1A2),weak(2,weak(0))) -bind_scope(6,keys(keyA1A2A3),weak(4,weak(2,weak(0)))) -bind_scope(6,keys(keyA1A2B3),weak(5,weak(2,weak(0)))) -bind_scope(6,keys(keyA1B2),weak(3,weak(0))) -bind_scope(6,keys(keyA1B2A3),weak(4,weak(3,weak(0)))) -bind_scope(6,keys(keyA1B2B3),weak(5,weak(3,weak(0)))) -bind_scope(6,keys(keyB1),weak(1)) -bind_scope(6,keys(keyB1A2),weak(2,weak(1))) -bind_scope(6,keys(keyB1A2A3),weak(4,weak(2,weak(1)))) -bind_scope(6,keys(keyB1A2B3),weak(5,weak(2,weak(1)))) -bind_scope(6,keys(keyB1B2),weak(3,weak(1))) -bind_scope(6,keys(keyB1B2A3),weak(4,weak(3,weak(1)))) -bind_scope(6,keys(keyB1B2B3),weak(5,weak(3,weak(1)))) -bind_scope(7,keys(keyA1),weak(0)) -bind_scope(7,keys(keyA1A2),weak(2,weak(0))) -bind_scope(7,keys(keyA1A2A3),weak(4,weak(2,weak(0)))) -bind_scope(7,keys(keyA1A2B3),weak(5,weak(2,weak(0)))) -bind_scope(7,keys(keyA1B2),weak(3,weak(0))) -bind_scope(7,keys(keyA1B2A3),weak(4,weak(3,weak(0)))) -bind_scope(7,keys(keyA1B2B3),weak(5,weak(3,weak(0)))) -bind_scope(7,keys(keyB1),weak(1)) -bind_scope(7,keys(keyB1A2),weak(2,weak(1))) -bind_scope(7,keys(keyB1A2A3),weak(4,weak(2,weak(1)))) -bind_scope(7,keys(keyB1A2B3),weak(5,weak(2,weak(1)))) -bind_scope(7,keys(keyB1B2),weak(3,weak(1))) -bind_scope(7,keys(keyB1B2A3),weak(4,weak(3,weak(1)))) -bind_scope(7,keys(keyB1B2B3),weak(5,weak(3,weak(1)))) - - - - -cfa_call(0,a2) -cfa_call(0,b2) -cfa_call(1,a2) -cfa_call(1,b2) -cfa_call(2,a3) -cfa_call(2,b3) -cfa_call(3,a3) -cfa_call(3,b3) -cfa_call(4,sink) -cfa_call(5,sink) -cfa_call(6,fnOut) -cfa_function_specializations(fnOut,keys(keyA1A2A3)) -cfa_function_specializations(fnOut,keys(keyA1A2B3)) -cfa_function_specializations(fnOut,keys(keyA1B2A3)) -cfa_function_specializations(fnOut,keys(keyA1B2B3)) -cfa_function_specializations(fnOut,keys(keyB1A2A3)) -cfa_function_specializations(fnOut,keys(keyB1A2B3)) -cfa_function_specializations(fnOut,keys(keyB1B2A3)) -cfa_function_specializations(fnOut,keys(keyB1B2B3)) -cfa_parent(0,function(a1)) -cfa_parent(1,function(b1)) -cfa_parent(2,function(a2)) -cfa_parent(3,function(b2)) -cfa_parent(4,function(a3)) -cfa_parent(5,function(b3)) -cfa_parent(6,function(sink)) -cfa_parent(7,function(fnOut)) -function(a1) -function(a2) -function(a3) -function(b1) -function(b2) -function(b3) -function(fnOut) -function(sink) -keys(keyA1) -keys(keyA1A2) -keys(keyA1A2A3) -keys(keyA1A2B3) -keys(keyA1B2) -keys(keyA1B2A3) -keys(keyA1B2B3) -keys(keyB1) -keys(keyB1A2) -keys(keyB1A2A3) -keys(keyB1A2B3) -keys(keyB1B2) -keys(keyB1B2A3) -keys(keyB1B2B3) -scope(0) -scope(1) -scope(2) -scope(3) -scope(4) -scope(5) -scope(6) -scope(7) - -true \ No newline at end of file diff --git a/scripts/sprint1_environment/tests1-context-latecontext3.lp b/scripts/sprint1_environment/tests1-context-latecontext3.lp deleted file mode 120000 index c21293f..0000000 --- a/scripts/sprint1_environment/tests1-context-latecontext3.lp +++ /dev/null @@ -1 +0,0 @@ -/private/prg/code/xreate/scripts/metatests/tests1-context-latecontext3.lp \ No newline at end of file diff --git a/scripts/testspass/Containers_Implementation_LinkedList1.xreate b/scripts/testspass/Containers_Implementation_LinkedList1.xreate index 7721ddc..2966ef4 100644 --- a/scripts/testspass/Containers_Implementation_LinkedList1.xreate +++ b/scripts/testspass/Containers_Implementation_LinkedList1.xreate @@ -1,47 +1,47 @@ // EXTERN INCLUDES interface(extern-c){ xml2 = library:: pkgconfig("libxml-2.0"). include { xml2 = ["libxml/tree.h"] }. } // CONTAINERS interface(dfa) { operator map:: (op(seqaccess)) -> impl(solid). operator list_range:: ()->impl(on_the_fly). operator list:: ()->impl(solid). operator fold:: (op(seqaccess)). operator index:: (op(randaccess)). /* operator map: (op(seqaccess)) -> impl(llvm_array | on_the_fly); */ } import raw("core/containers.lp") // PROGRAM XmlNode = type alias { tag:: string, /* attrs:: [string],*/ content:: string }. Tree = type Tree(Leaf) [Leaf, [Tree(Leaf)]]. XmlTree = type alias Tree(XmlNode). test= function:: num; entry { - filename = "project/documentation.fodt" :: string. + filename = "scripts/testspass/Containers_Implementation_LinkedList1-data.xml" :: string. docRaw = xmlParseFile(filename) :: xmlDocPtr. tree= xmlDocGetRootElement(docRaw) :: xmlNodePtr. childrenRaw = tree["children"]:: [xmlNodePtr]; containers:linkedlist(next, null). - size = loop fold(childrenRaw->child:: xmlNodePtr, 0->count::int):: int { + size = loop fold(childrenRaw->child:: xmlNodePtr, 0->count):: int { count +1::int }. size } diff --git a/scripts/testspass/xml-test1.xreate b/scripts/testspass/xml-test1.xreate index e763d7f..f5388c9 100644 --- a/scripts/testspass/xml-test1.xreate +++ b/scripts/testspass/xml-test1.xreate @@ -1,142 +1,142 @@ /* C++ SECTION Example of c++ code: xmlDocPtr doc; xmlNodePtr cur; doc = xmlParseFile(docname.c_str()); if (doc == NULL ) { fprintf(stderr,"Document not parsed successfully. \n"); return; } cur = xmlDocGetRootElement(doc); if (cur == NULL) { fprintf(stderr,"empty document\n"); xmlFreeDoc(doc); return; } cur = cur->xmlChildrenNode; while (cur != NULL) { printf("child: %s\n", cur->name); cur = cur->next; } */ /* FEATURES SECTION Default strategies: - what to do with unspecified nodes Node content strategy: - send as-is - apply transforms (all / named) - ?? skip Processing order: - dependencies Mapping: * tree -> list */ /* TODO SECTION -- gather types aliases (tree->list mapping) -- flyweight implementation ('doc' field calculation, for example. based on are there more than one opened document ) */ // REQUIREMENTS SECTION /* require ptrvalid */ /* local scope doc ptr */ /* singleton element check(::single) */ XmlAttr = type alias { name:: string, content:: string }. XmlNode = type alias { name:: string, /* the name of the node, or the entity */ content:: string, /* the content */ attributes::[XmlAttr] /* properties list */ /* children:: [xmlNode], // parent->childs link void *_private; // application data struct _xmlNode *parent; // child->parent link struct _xmlNode *next; // next sibling link struct _xmlNode *prev; // previous sibling link struct _xmlDoc *doc; // the containing document unsigned short line; // line number */ }. interface(extern-c){ xml2 = library:: pkgconfig("libxml-2.0"). include { xml2 = ["libxml/tree.h", "string.h"] }. } Tree = type Tree(Leaf) [Leaf, [Tree(Leaf)]]. XmlTree = type alias Tree(XmlNode). toXmlNode = function (nodeRaw:: xmlNodePtr):: XmlNode { propertiesRaw = nodeRaw["properties"]:: [xmlAttrPtr]; containers:linkedlist(next, null). properties = loop map(propertiesRaw -> property::xmlAttrPtr)::[XmlAttr]{ {name=property["name"], content=property["children", "content"]} }. {name = nodeRaw["name"], content=nodeRaw["content"], attributes=properties} } children = function(nodeRaw::xmlDocPtr)::[XmlTree] { childrenRaw = nodeRaw["children"]:: [xmlDocPtr]; containers:linkedlist(next, null). children = loop map(childrenRaw->child:: xmlDocPtr) :: [XmlTree]{ [toXmlNode(child), children(child)] }. children } document = function (filename:: string):: XmlTree { docRaw = xmlParseFile(filename) :: xmlDocPtr. nodeRaw= xmlDocGetRootElement(docRaw) :: xmlNodePtr. [toXmlNode(nodeRaw), children(nodeRaw)]:: XmlTree } traverse = function(tree:: XmlTree) :: [XmlNode] { - listOfNodes = loop fold(tree -> node:: XmlTree, []->acc:: [XmlNode]):: [XmlNode]{ + listOfNodes = loop fold(tree -> node:: XmlTree, []->acc):: [XmlNode]{ acc + node[0] + traverse(node[1]):: [XmlNode] }. listOfNodes } -test1 = function():: int; entry { +test1 = function:: int; entry { filename = "project/documentation.fodt" :: string. root = document(filename):: XmlTree. nodesAll = traverse(root):: [XmlNode]. - result = loop fold(nodesAll->node:: XmlNode, 0->count::int):: int{ + result = loop fold(nodesAll->node:: XmlNode, 0->count):: int{ count + if (0==strcmp(node["name"], "section")) :: int { 1 } else { 0 } }. result } diff --git a/tools/phabricator/administration/docker-compose.yml b/tools/phabricator/administration/docker-compose.yml new file mode 100644 index 0000000..caf839f --- /dev/null +++ b/tools/phabricator/administration/docker-compose.yml @@ -0,0 +1,28 @@ +version: '2' + +services: + mariadb: + image: bitnami/mariadb:latest + volumes: + - mariadb_data:/bitnami/mariadb + phabricator: + image: bitnami/phabricator:latest + depends_on: + - mariadb + ports: + - '1001:80' + - '1002:443' + environment: + - PHABRICATOR_USERNAME='admin' + - PHABRICATOR_PASSWORD='phabricator-1' + volumes: + - phabricator_data:/bitnami/phabricator + - apache_data:/bitnami/apache + +volumes: + mariadb_data: + driver: local + phabricator_data: + driver: local + apache_data: + driver: local