diff --git a/coco/xreate.ATG b/coco/xreate.ATG index 8b39f34..b50fb1b 100644 --- a/coco/xreate.ATG +++ b/coco/xreate.ATG @@ -1,570 +1,599 @@ //TODO add ListLiteral //TODO ExprTyped: assign default(none) type #include "ast.h" #include "ExternLayer.h" +#include "pass/adhocpass.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 nextToken() { scanner->ResetPeek(); return scanner->Peek()->kind; } bool checkParametersList() { return la->kind == _ident && nextToken() == _lparen; } bool checkInfix() { return la->kind == _ident && nextToken() == _ident; } bool checkIndex() { return la->kind == _ident && nextToken() == _lbrack; } bool checkFuncDecl() { if (la->kind != _ident) return false; int token2 = nextToken(); int token3 = scanner->Peek()->kind; return token2 == _assign && (token3 == _function || token3 == _pre); } bool checkAssignment() { if (la->kind != _ident) return false; scanner->ResetPeek(); int token2 = scanner->Peek()->kind; if (token2 == _lcurbrack) { scanner->Peek(); int token3 = scanner->Peek()->kind; if (token3 != _rcurbrack) return false; int token4 = scanner->Peek()->kind; return token4 == _assign; } return token2 == _assign; } void recognizeIdentifier(Expression& i){ - if (!context.scope->recognizeIdentifier(i)){ - root.postponeIdentifier(context.scope, i); + if (!context.scope->recognizeIdentifier(i)){ + if (!root.recognizeVariantIdentifier(i)){ + root.postponeIdentifier(context.scope, i); + } } } +enum SwitchKind{SWITCH_NORMAL, SWITCH_META}; + 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 )} (. root.recognizePostponedIdentifiers(); .) . Ident = ident (. name = t->val; .). VarIdent = ident (. e = Expression(Atom(t->val)); .) [ lcurbrack ( ident (. SemErr(coco_string_create("var version as ident is not implemented yet")); .) | number (. Attachments::put(e, Atom(t->val).get()); .) ) rcurbrack ] . FDecl = (. std::wstring fname; std::wstring argName; TypeAnnotation typIn; TypeAnnotation typOut; bool flagIsPrefunct = false; Expression binding; .) Ident assign [pre (. flagIsPrefunct = true; .)] function (. f = new Function(fname); f->isPrefunction = flagIsPrefunct; CodeScope* entry = f->getEntryScope(); .) ['(' Ident tagcolon ExprAnnotations (. f->addBinding(Atom(argName), move(binding)); .) {',' Ident tagcolon ExprAnnotations (. f->addBinding(Atom (argName), move(binding));.) } ')'] [ tagcolon ( IF(flagIsPrefunct) FnTag | Type ) {';' FnTag }] BDecl (. entry->getBody().bindType(move(typOut));.) . ContextSection<>= (. Expression context; Function* f; .) "case" "context" tagcolon MetaSimpExpr lcurbrack { FDecl (. f->guardContext = context; root.add(f); .) } rcurbrack. /** * TYPES * */ -TypeTerm = (. std::wstring tid; .) - ("string" | "num" | "int" | "i8" | "i32" | "float" | "bool") (. typ = Atom(t->val); .) -. +TypeTerm = (. std::wstring tid; .) + ("string" (. typ = TypePrimitive::String;.) + | "num" (. typ = TypePrimitive::Num;.) + | "int" (. typ = TypePrimitive::Int;.) + | "float" (. typ = TypePrimitive::Float;.) + | "bool" (. typ = TypePrimitive::Bool; .) + | "i8" (. typ = TypePrimitive::I8; .) + | "i32" (. typ = TypePrimitive::I32; .) + ). -Type = (. TypeAnnotation typ2; TypeAtom typ3; std::wstring tid, field; .) +Type = (. TypeAnnotation typ2; TypePrimitive typ3; std::wstring tid, field; .) ( TList | TStruct -| TypeTerm (. typ = TypeAnnotation(typ3); .) -|IF (checkIndex()) Ident lbrack +| TypeTerm (. typ = 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; .) lcurbrack 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()); .) rcurbrack. 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)); .) ) '.' . ContextDecl = (. Expression tag; .) context tagcolon MetaSimpExpr (. scope->tags.push_back(tag); .) {';' MetaSimpExpr (. scope->tags.push_back(tag); .) }. VDecl = (. std::wstring vname; Expression var, value;.) VarIdent assign ExprTyped (. f->addDeclaration(move(var), move(value)); .) . //TODO forbid multiple body declaration (ExprTyped) BDecl = lcurbrack (. Expression body; pushContextScope(scope); .) {(IF(checkAssignment()) VDecl '.' | RuleContextDecl | ContextDecl'.' | ExprTyped (. scope->setBody(body); .) )} (. popContextScope(); .) rcurbrack . IfDecl = (. Expression cond; ManagedScpPtr blockTrue = root.add(new xreate::CodeScope(context.scope)); ManagedScpPtr blockFalse = root.add(new xreate::CodeScope(context.scope)); .) "if" '(' Expr ')' (. e = Expression(Operator::IF, {cond}); .) tagcolon ExprAnnotations BDecl<&*blockTrue> "else" BDecl<&*blockFalse> (. e.addBlock(blockTrue); e.addBlock(blockFalse); .) . LoopDecl = (. Expression eIn, eAcc, eFilters; std::wstring varEl, varAcc, contextClass; Expression tagsEl; ManagedScpPtr block = root.add(new xreate::CodeScope(context.scope)); .) "loop" ("map" '(' Expr implic Ident (. e = Expression(Operator::MAP, {eIn}); .) tagcolon ExprAnnotations ')' tagcolon ExprAnnotations BDecl<&*block> (. e.addBindings({Atom(varEl)}); block->addBinding(Atom(varEl), move(tagsEl)); e.addBlock(block); .) |"fold" ("inf" '(' Expr implic Ident ')' (. e = Expression(Operator::FOLD_INF, {eAcc}); e.addBindings({Atom(varAcc)}); .) tagcolon ExprAnnotations BDecl<&*block> (. block->addBinding(Atom(varAcc), Expression()); e.addBlock(block); .) | '(' Expr implic Ident tagcolon ExprAnnotations ['|' Expr ] ',' Expr implic Ident')' (. e = Expression(Operator::FOLD, {eIn, eAcc}); e.addBindings({Atom(varEl), Atom(varAcc)}); .) tagcolon ExprAnnotations BDecl<&*block> (. block->addBinding(Atom(varEl), move(tagsEl)); block->addBinding(Atom(varAcc), Expression()); e.addBlock(block); .) ) | "context" '(' string (. contextClass = t->val; .) ')' BDecl<&*block> (. e = Expression(Operator::LOOP_CONTEXT, {Expression(Atom(std::move(contextClass)))}); e.addBlock(block); .) ). -SwitchDecl = (. TypeAnnotation typ; eSwitch = Expression(Operator::SWITCH, {}); Expression eCondition; Expression tag;.) +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)); .) + ( "ad" "hoc" lparen Expr tagcolon MetaSimpExpr rparen (. eSwitch.op = Operator::SWITCH_ADHOC; + eSwitch.operands.push_back(eCondition); + eSwitch.addTags({tag}); + flagSwitchKind = SWITCH_META; .) | lparen Expr rparen tagcolon ExprAnnotations (. eSwitch.operands.push_back(eCondition);.) ) ] - CaseDecl {CaseDecl} + CaseDecl {CaseDecl} . -CaseDecl = (. ManagedScpPtr scope = root.add(new xreate::CodeScope(context.scope)); .) +CaseDecl = (. ManagedScpPtr scope = root.add(new xreate::CodeScope(context.scope)); Expression condition; .) "case" - ( "default" BDecl<&*scope> (. Expression exprCase(Operator::CASE_DEFAULT, {}); + ( IF(flagSwitchKind == SWITCH_META) + lparen MetaSimpExpr rparen BDecl<&*scope> (. Expression exprCase(Operator::CASE, {}); exprCase.addTags({condition}); exprCase.addBlock(scope); outer.addArg(move(exprCase));.) + + | "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)); .) + | lparen CaseParams<&*scope> rparen (. ManagedScpPtr scopeBody = root.add(new xreate::CodeScope(&*scope)); Expression exprCase(Operator::CASE, {}); .) + BDecl<&*scopeBody> (. exprCase.addBlock(scope); exprCase.addBlock(scopeBody); outer.addArg(move(exprCase)); .) ). CaseParams = (. Expression condition; Expression guard(Operator::LOGIC_AND, {}); pushContextScope(scope); .) - ExprTyped (. guard.addArg(Expression(condition)); .) + ExprTyped (. guard.addArg(Expression(condition)); .) {',' ExprTyped (. guard.addArg(Expression(condition)); .) - } (. scope->setBody(guard); popContextScope(); .). - + } (. scope->setBody(guard); popContextScope(); .) +. + +IntrinsicDecl= (. std::wstring name; .) +"intrinsic" Ident< name> (. outer = Expression(Operator::CALL_INTRINSIC, {}); outer.setValue(Atom(name)); .) +lparen [CalleeParams] rparen . /*============================ 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 } '}'. PrefunctionSchemeDecl<> = (. TypeAnnotation typReturn; std::wstring prefName; Expression exprCases; .) pre function Ident tagcolon Type - '{' SwitchDecl '}' + lcurbrack SwitchDecl rcurbrack (. Expression prefData(Operator::CALL, {Atom(prefName), exprCases}); - prefData.type = typReturn; + prefData.bindType(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 +"case" lparen MetaSimpExpr rparen '{' 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 ] ')' +'(' [ MetaCalleeParams ] ')' | 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)); .) ). +MetaCalleeParams = (. Expression e2; .) + MetaSimpExpr (. e.addArg(Expression(e2)); .) + {',' MetaSimpExpr (. e.addArg(Expression(e2)); .) + }. + RBody = (. Expression e; std::wstring msg; .) "warning" MetaExpr ["message" string (. msg = t->val; .) ] (. root.add(new RuleWarning(RuleArguments(args), RuleGuards(guards), std::move(e), Atom(msg))); .) . MetaOp< Operator& op> = implic (. op = Operator::IMPL; .) . /*============================ Expressions ===============================*/ -ExprAnnotations = (. TypeAnnotation typ; Expression tag; e.tags.clear();.) +ExprAnnotations = (. TypeAnnotation typ; std::list tags; Expression tag; e.tags.clear();.) Type (. e.bindType(move(typ)); .) - {';' MetaSimpExpr (. e.tags.emplace(tag.getValueString(), tag); .) - }. + {';' MetaSimpExpr (. tags.push_back(tag); .) + } (. e.addTags(tags); .) +. ExprTyped = Expr [tagcolon ExprAnnotations]. Expr< Expression& e> (. Operator op; Expression e2; .) = ExprArithmAdd [ RelOp ExprArithmAdd (. e = Expression(op, {e, e2}); .) ]. ExprArithmAdd< Expression& e>= (. Operator op; Expression e2; .) ExprArithmMul< e> [ AddOp< op> ExprArithmAdd< e2> (. e = Expression(op, {e, e2});.) ]. ExprArithmMul< Expression& e> (. Operator op; Expression e2; .) = ExprPostfix< e> [ MulOp< op> ExprArithmMul< e2> (. e = Expression(op, {e, e2}); .) ]. ExprPostfix = Term [lbrack (. e = Expression(Operator::INDEX, {e}); .) CalleeParams rbrack ]. Term< Expression& e> (. std::wstring name; e = Expression(); .) = (IF (checkParametersList()) Ident< name> (. e = Expression(Operator::CALL, {Atom(name)}); .) '(' [CalleeParams] ')' | VarIdent (. recognizeIdentifier(e); .) | ListLiteral (. /* tuple */.) | StructLiteral (. /* struct */.) | LoopDecl | IfDecl - | SwitchDecl + | SwitchDecl | AdhocDecl + | IntrinsicDecl + | "true" (. e = Expression(Atom(1)); e.bindType(TypePrimitive::Bool); .) + | "false" (. e = Expression(Atom(0)); e.bindType(TypePrimitive::Bool); .) | number (. e = Expression(Atom(t->val)); .) | string (. e = Expression(Atom(t->val)); .) | '-' Term (. e = Expression(Operator::NEG, {e}); .) | '(' ExprTyped ')' ). StructLiteral = (. std::wstring key; Expression val; std::list> keys; .) '{' Ident '=' Expr (. keys.push_back(Atom(key)); e = Expression(Operator::LIST_NAMED, {val}); .) {',' Ident '=' Expr (.e.addArg(Expression(val)); keys.push_back(Atom(key)); .) } '}' (. e.addBindings(keys.begin(), keys.end()); .) . ListLiteral = (. Expression eFrom, eTo; .) '[' [ Expr (. e.addArg(Expression(eFrom)); .) (".." Expr (. e.addArg(Expression(eTo)); e.setOp(Operator::LIST_RANGE); .) |{',' Expr (. e.addArg(Expression(eFrom)); .) } (. e.setOp(Operator::LIST); .) ) ] ']'. AdhocDecl = (. Expression command; .) -"ad" "hoc" Expr (. e.setOp(Operator::ADHOC); e.addArg(std::move(command)); .). +"ad" "hoc" MetaSimpExpr (. AdhocExpression exprAdhoc; exprAdhoc.setCommand(command); e = exprAdhoc; .). CalleeParams = (. Expression e2; .) ExprTyped (. e.addArg(Expression(e2)); .) {',' ExprTyped (. e.addArg(Expression(e2)); .) }. AddOp< Operator& op> = (. op = Operator::ADD; .) ( '+' | '-' (. op = Operator::SUB; .) ). MulOp< Operator& op> = (. op = Operator::MUL; .) ( '*' | '/' (. op = Operator::DIV; .) ). RelOp< Operator& op> = (. op = Operator::EQU; .) ( equal | (ne1 | ne2) (. op = Operator::NE; .) | lse (. op = Operator::LSE; .) | lss (. op = Operator::LSS; .) | gte (. op = Operator::GTE; .) | gtr (. op = Operator::GTR; .) ). END Xreate. diff --git a/config/default.json b/config/default.json index f72b68e..6b05add 100644 --- a/config/default.json +++ b/config/default.json @@ -1,73 +1,71 @@ { "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": "containers", "templates": { "default": "*-", - "basic": "Basic.*", + "adhocs": "Adhoc.*", + "effects": "Effects.*", + "basic": "Attachments.*", "ast": "AST.*", "cfa": "CFA.*", "dfa": "DFA.*", - "compilation": "Compilation.*", - "containers": "Containers.ListAsArray2-", + "compilation": "Compilation.*", "diagnostic": "Diagnostic.*", - "serializer": "ExpressionSerializer.*", + "ExpressionSerializer": "ExpressionSerializer.*", "externc": "InterfaceExternC.*", - "context": "ExpressionSerializer.*:Context.*", - "types": "Types.*-", - "log": "Logging*", - "clang": "ClangAPI.*", - "skip": "SkipDetection*:Adhoc_Loop_SkipDetection.*", - "raw-xml": "libxml2*", - "xml": "Xml.*", - "installation": "Compilation.*:Sprint1.*", - "exploitation": "Exploitation.*", - "loops": "Loop.*", + "types": "Types.*-", + "vendorsAPI/clang": "ClangAPI.*", + "vendorsAPI/xml2": "libxml2*", "dsl": "Interpretation.*", - "adhocs": "Adhoc.*", + "context": "Context.*", + "containers": "Containers.ListAsArray2" + + "loops": "Loop.*", + } } } diff --git a/cpp/CMakeLists.txt b/cpp/CMakeLists.txt index beae275..0f5feae 100644 --- a/cpp/CMakeLists.txt +++ b/cpp/CMakeLists.txt @@ -1,34 +1,35 @@ +project(Xreate) cmake_minimum_required(VERSION 2.8.11) set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -g -Wall -fprofile-arcs -ftest-coverage -O0") set(CMAKE_BUILD_TYPE Debug) # 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 -fPIC -std=c++14) # XREATE #====================== add_subdirectory(src) # XREATE-TESTS #====================== if (BUILD_XREATE_TESTS) message ("Building xreate tests") add_subdirectory(tests) endif () # XREATE-SERVER #====================== if (BUILD_XREATE_SERVER) message ("Building xreate server") add_subdirectory(../tools/execution-server execution-server) endif () diff --git a/cpp/src/CMakeLists.txt b/cpp/src/CMakeLists.txt index 0e79032..7f4a3bf 100644 --- a/cpp/src/CMakeLists.txt +++ b/cpp/src/CMakeLists.txt @@ -1,216 +1,222 @@ cmake_minimum_required(VERSION 2.8.11) project(xreate) cmake_policy(SET CMP0022 NEW) message("MODULES" ${CMAKE_MODULE_PATH}) # LLVM #====================== FIND_PACKAGE (LLVM REQUIRED) set(LLVM_VERSION ${LLVM_VERSION_MAJOR}.${LLVM_VERSION_MINOR}) message(STATUS "Found LLVM ${LLVM_PACKAGE_VERSION}") message("LLVM LIB PATH:" ${LLVM_LIBRARY_DIRS}) message(STATUS "Using LLVMConfig.cmake in: ${LLVM_DIR}") INCLUDE_DIRECTORIES(${LLVM_INCLUDE_DIRS}) message(STATUS "INCLUDE DIR: ${LLVM_INCLUDE_DIRS}") add_definitions(${LLVM_DEFINITIONS}) message("LLVM DEFS: " ${LLVM_DEFINITIONS}) llvm_map_components_to_libnames(LLVM_LIBS core nativecodegen native executionengine mcjit support option) message("LLVM LIBS: " ${LLVM_LIBS}) # CLANG #====================== set(CLANG_LIBS clangCodeGen clangASTMatchers clangQuery clangTooling clangFrontend clangSerialization clangDriver clangParse clangSema clangAnalysis clangAST clangEdit clangLex clangBasic ) # 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_LIBS clingo clasp gringo program_opts reify lp ) message("CLASP LIBS: " ${LIBCLASP_LIBS}) # OTHER DEPENDENCIES #=========================== set(JEAYESON_INCLUDE_PATH ${CMAKE_HOME_DIRECTORY}/../vendors/jeayeson/include/ ) INCLUDE_DIRECTORIES(${JEAYESON_INCLUDE_PATH}) # COCO #=========================== set(COCO_EXECUTABLE "" CACHE PATH "Path to coco executable") set(COCO_FRAMES_PATH "" CACHE PATH "Path to coco frames") set(COCO_GRAMMAR_PATH ${CMAKE_HOME_DIRECTORY}/../coco/) set(COCO_SOURCE_FILES ${COCO_GRAMMAR_PATH}/Parser.cpp ${COCO_GRAMMAR_PATH}/Scanner.cpp) INCLUDE_DIRECTORIES(${COCO_GRAMMAR_PATH}) add_custom_command(OUTPUT ${COCO_SOURCE_FILES} COMMAND ${COCO_GRAMMAR_PATH}/gen-grammar ${COCO_EXECUTABLE} ${COCO_FRAMES_PATH} WORKING_DIRECTORY ${COCO_GRAMMAR_PATH} MAIN_DEPENDENCY ${COCO_GRAMMAR_PATH}/xreate.ATG ) message(STATUS "COCO GRAMMAR BUILD STATUS:" ${COCO_OUTPUT}) # XREATE #====================== set(SOURCE_FILES - -# attachments.cpp -# ast.cpp -# pass/compilepass.cpp - -# ExternLayer.cpp - -# analysis/cfagraph.cpp -# analysis/dfagraph.cpp -# analysis/aux.cpp -# compilation/containers.cpp -# compilation/advanced.cpp -# compilation/transformations.cpp -# clasplayer.cpp -# compilation/latecontextcompiler2.cpp -# query/context.cpp -# #compilation/latecontextcompiler.cpp -# serialization/expressionserializer2.cpp -# llvmlayer.cpp - utils.cpp -# passmanager.cpp -# pass/abstractpass.cpp pass/dfapass.cpp -# pass/cfapass.cpp -# pass/adhocpass.cpp -# contextrule.cpp -# query/containers.cpp -# #pass/loggerpass.cpp -# pass/interpretationpass.cpp -# serialization/expressionserializer.cpp -# compilation/targetinterpretation.cpp -# analysis/DominatorsTreeAnalysisProvider.cpp + pass/dfapass.cpp + analysis/dfagraph.cpp + pass/versionspass.cpp + compilation/targetinterpretation.cpp + pass/compilepass.cpp + attachments.cpp + ast.cpp + + ExternLayer.cpp + + analysis/cfagraph.cpp + + analysis/aux.cpp + compilation/containers.cpp + compilation/advanced.cpp + + clasplayer.cpp + compilation/latecontextcompiler2.cpp + query/context.cpp + + llvmlayer.cpp + utils.cpp + passmanager-bare.cpp + passmanager-full.cpp + pass/abstractpass.cpp + + pass/cfapass.cpp + pass/adhocpass.cpp + contextrule.cpp + query/containers.cpp + pass/interpretationpass.cpp + analysis/DominatorsTreeAnalysisProvider.cpp + serialization/expressionserializer.cpp + + #serialization/expressionserializer2.cpp + #compilation/latecontextcompiler.cpp + #pass/loggerpass.cpp + #compilation/transformations.cpp #query/ptrvalid.cpp - #pass/rulespass.cpp # + #pass/rulespass.cpp ) set(XREATE_INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/ ) INCLUDE_DIRECTORIES(${XREATE_INCLUDE_DIRS}) set(XREATE_PRIVATE_INCLUDE_DIRS ${XREATE_INCLUDE_DIRS} ${COCO_GRAMMAR_PATH} ${JEAYESON_INCLUDE_PATH} ${LLVM_INCLUDE_DIRS} ${POTASSCO_INCLUDE_PATH} ) -add_library(${PROJECT_NAME} SHARED ${SOURCE_FILES} ) -#${COCO_SOURCE_FILES} +add_library(${PROJECT_NAME} SHARED ${SOURCE_FILES} ${COCO_SOURCE_FILES}) target_link_libraries(${PROJECT_NAME}) target_include_directories(${PROJECT_NAME} INTERFACE ${XREATE_INCLUDE_DIRS} ${COCO_GRAMMAR_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 ${LIBCLASP_LIBS} ${CLANG_LIBS} ${LLVM_LIBS} tbb ) #${CLANG_LIBS} #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/analysis/aux.cpp b/cpp/src/analysis/aux.cpp index 6d5192c..7ac53fc 100644 --- a/cpp/src/analysis/aux.cpp +++ b/cpp/src/analysis/aux.cpp @@ -1,136 +1,136 @@ #include "aux.h" #include namespace xreate { namespace analysis { using namespace std; list multiplyLists(list> &&lists) { typedef list StringList; assert(lists.size()); StringList result(*lists.begin()); lists.pop_front(); boost::format concat("%s, %s"); for (StringList &list: lists) { StringList::const_iterator end = result.end(); for (StringList::iterator expr1I = result.begin(); expr1I != end; ++expr1I) { if (list.size() == 0) continue; StringList::const_iterator expr2I = list.begin(); for (int expr2No = 0, size = list.size() - 1; expr2No < size; ++expr2No, ++expr1I) result.push_back(str(concat %(*expr1I) %(*expr2I))); *expr1I = str(concat %(*expr1I) %(*expr2I)); } } return result; } std::list compile(const Expression &e){ list result; switch (e.op) { case Operator::CALL: { assert(e.__state == Expression::COMPOUND); std::list> operands; std::transform(e.operands.begin(), e.operands.end(), std::inserter(operands, operands.begin()), [](const Expression &e) { return compile(e); }); list &&operands_ = multiplyLists(std::move(operands)); result.push_back(boost::str(boost::format("%1%(%2%)") % (e.getValueString()) % (boost::algorithm::join(operands_, ", ")))); break; } case Operator::NEG: { assert(e.operands.size() == 1); const Expression &op = e.operands.at(0); list &&rawOp = compile(op); assert(rawOp.size() == 1); result.push_back((boost::format("not %1%")%(rawOp.front())).str()); break; }; case Operator::NONE: { switch (e.__state) { case Expression::IDENT: result.push_back(e.getValueString()); break; case Expression::NUMBER: result.push_back(to_string(e.getValueDouble())); break; default: assert(true); } break; } default: break; } //TODO Null ad hoc ClaspLayer implementation // if (e.isNone()){ // result.push_back(e.__valueS); // } assert(result.size()); return result; } std::list compileNeg(const Expression &e){ list result; switch (e.op) { case Operator::IMPL: { assert(e.__state == Expression::COMPOUND); assert(e.operands.size() == 2); list operands1 = compile(e.operands.at(0)); list operands2 = compile(e.operands.at(1)); boost::format formatNeg("%1%, not %2%"); for (const auto &op1: operands1) for (const auto &op2: operands2) { result.push_back(boost::str(formatNeg %(op1) % (op2))); } break; } case Operator::NEG: { assert(e.operands.size() == 1); const Expression &op = e.operands.at(0); list &&rawOp = compile(op); assert(rawOp.size() == 1); result.push_back(rawOp.front()); break; }; default: assert(true); } return result; } -boost::format +boost::format formatSymbol(const SymbolPacked& s){ - boost::format formatSymbNamed("(%1%, %2%)"); - boost::format formatSymbAnonymous("(anonym(%1%), %2%)"); + boost::format formatSymbNamed("(%1%, %2%, %3%)"); + boost::format formatSymbAnonymous("anonym(%1%, %2%)"); if (!s.categoryTransient){ - return formatSymbNamed % s.identifier % s.scope; + return formatSymbNamed % s.identifier % s.version % s.scope; } else { return formatSymbAnonymous % s.identifier % s.scope; } } - + }} \ No newline at end of file diff --git a/cpp/src/analysis/dfagraph.cpp b/cpp/src/analysis/dfagraph.cpp index 00a3006..b1f52dc 100644 --- a/cpp/src/analysis/dfagraph.cpp +++ b/cpp/src/analysis/dfagraph.cpp @@ -1,250 +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; output << endl << "%\t\tStatic analysis: DFA" << endl; std::vector>::const_iterator i1; std::vector::const_iterator i2; boost::format formatDfaConnection("dfa_connection(%1%, %2%, %3%)."); for (i1 = this->__edges.begin(), i2 = this->__data.begin(); i1 != this->__edges.end(); ++i1, ++i2) { string edgeName; switch (*i2) { case DFGConnection::WEAK: edgeName = "weak"; break; case DFGConnection::STRONG: edgeName = "strong"; break; case DFGConnection::PROTOTYPE: edgeName = "proto"; break; } output << formatDfaConnection % formatSymbol(i1->first) % formatSymbol(i1->second) % edgeName << " %" << this->__clasp->getHintForPackedSymbol(i1->first) << " - " << this->__clasp->getHintForPackedSymbol(i1->second) << endl; symbols.insert(i1->first); symbols.insert(i1->second); } boost::format formatDfaDependency("dfa_dependency(%1%, %2%)."); for (auto i = this->__dependencies.begin(); i != this->__dependencies.end(); ++i) { output << formatDfaDependency % formatSymbol(i->first) % formatSymbol(i->second) << " %" << this->__clasp->getHintForPackedSymbol(i->first) << " - " << this->__clasp->getHintForPackedSymbol(i->second) << endl; } boost::format formatBind("bind(%1%, %2%)."); for (const pair& tag : this->__tags) { for (string variant : xreate::analysis::compile(tag.second)) { output << formatBind % formatSymbol(tag.first) % (variant) << "%" << this->__clasp->getHintForPackedSymbol(tag.first) << endl; } symbols.insert(tag.first); } for (const SymbolPacked& s : symbols) { output << "v(" << formatSymbol(s) << ")." << " %" << this->__clasp->getHintForPackedSymbol(s) << endl; } } class VisitorAddTag : public boost::static_visitor<> { public: void operator()(const SymbolPacked& symbol) { __graph->__tags.emplace(symbol, move(__tag)); } - void operator()(SymbolTransient& symbol) { + void operator()(SymbolAnonymous& symbol) { symbol.tags.push_back(move(__tag)); } void operator()(const SymbolInvalid& symbol) { assert(false && "Undefined behaviour"); } VisitorAddTag(DFAGraph * const dfagraph, Expression&& tag) : __graph(dfagraph), __tag(tag) { } private: DFAGraph * const __graph; Expression __tag; }; class VisitorAddLink : public boost::static_visitor<> { public: void operator()(const SymbolPacked& nodeFrom) { if (!__graph->isConnected(__nodeTo, nodeFrom)) { __graph->__edges.emplace_back(__nodeTo, nodeFrom); __graph->__data.push_back(__link); DFAGraph::EdgeId eid = __graph->__edges.size() - 1; __graph->__outEdges.emplace(nodeFrom, eid); } } - void operator()(const SymbolTransient& symbolFrom) { + void operator()(const SymbolAnonymous& 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; assert(false && "Undefined behavior"); } VisitorAddLink(DFAGraph * const dfagraph, const SymbolPacked& nodeTo, DFGConnection link) : __graph(dfagraph), __nodeTo(nodeTo), __link(link) { } private: DFAGraph * const __graph; SymbolPacked __nodeTo; DFGConnection __link; }; class VisitorGetDependencyConnection : public boost::static_visitor> { public: list operator()(const SymbolPacked & nodeFrom) { return { nodeFrom }; } list - operator()(const SymbolTransient & nodeFrom) { + operator()(const SymbolAnonymous & 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); } } - void operator()(SymbolTransient& nodeTo) { + void operator()(SymbolAnonymous& nodeTo) { VisitorGetDependencyConnection visitorGetDepenencies(graph); auto deps = boost::apply_visitor(visitorGetDepenencies, nodeFrom); for (const SymbolPacked& dep : deps) { nodeTo.dependencies.push_back(dep); } } 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); + return SymbolPacked(ScopedSymbol{__countAnonymousSymbols++, 0}, scope, true); } } } \ No newline at end of file diff --git a/cpp/src/analysis/dfagraph.h b/cpp/src/analysis/dfagraph.h index 374ab14..7962c77 100644 --- a/cpp/src/analysis/dfagraph.h +++ b/cpp/src/analysis/dfagraph.h @@ -1,57 +1,60 @@ /* * File: dfa.h * Author: pgess * * Created on June 27, 2016, 1:50 PM */ #ifndef DFA_H #define DFA_H #include "clasplayer.h" namespace xreate {namespace analysis { - struct SymbolTransient { + struct SymbolAnonymous { + SymbolAnonymous(unsigned int symbolId): id(symbolId){} + + unsigned int id; std::list tags; ScopePacked scope; std::list dependencies; }; - + struct SymbolInvalid { }; - typedef boost::variant SymbolNode; + typedef boost::variant SymbolNode; class DFAGraph: public IAnalysisData{ friend class VisitorAddTag; friend class VisitorAddLink; friend class VisitorGetDependencyConnection; friend class VisitorSetDependencyConnection; public: DFAGraph(ClaspLayer* engine): __clasp(engine){} SymbolPacked createAnonymousSymbol(const ScopePacked& scope); void addAnnotation(SymbolNode& identifier, Expression&& tag); void addConnection(const SymbolPacked& identifierTo, const SymbolNode& identifierFrom, DFGConnection link); void addDependencyConnection(SymbolNode& identifierTo, SymbolNode& identifierFrom); bool isConnected(const SymbolPacked& identifierTo, const SymbolPacked& identifierFrom); void print(std::ostringstream& output) const; private: typedef unsigned int EdgeId; std::vector> __edges; std::multimap __outEdges; std::vector __data; std::multimap __tags; std::multimap __dependencies; unsigned int __countAnonymousSymbols=0; ClaspLayer* __clasp; }; }} #endif /* DFA_H */ diff --git a/cpp/src/ast.cpp b/cpp/src/ast.cpp index 918bb75..95f4f66 100644 --- a/cpp/src/ast.cpp +++ b/cpp/src/ast.cpp @@ -1,833 +1,890 @@ #include "ast.h" #include "ExternLayer.h" #include #include namespace std{ std::size_t hash::operator()(xreate::ScopedSymbol const& s) const {return s.id ^ (s.version << 2);} bool equal_to::operator()(const xreate::ScopedSymbol& __x, const xreate::ScopedSymbol& __y) const { return __x.id == __y.id && __x.version == __y.version; } } using namespace std; namespace xreate { +Atom::Atom(const std::wstring& value) { + __value = wstring_to_utf8(value); +} + +Atom::Atom(std::string && name) : __value(name) +{} + +const std::string& +Atom::get() const { + return __value; +} + +Atom::Atom(wchar_t* value) { + //DEBT reconsider number literal recognition + __value = wcstol(value, 0, 10); +} + +Atom::Atom(int value) +: __value(value) { +} + +double +Atom::get()const { + return __value; +} + +Atom::Atom(const std::wstring& value) { + assert(value.size() >=2); + __value = wstring_to_utf8(value.substr(1, value.size() -2)); +} + +const std::string& +Atom::get() const { + return __value; +} + 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: + case Expression::VARIANT: return false; case Expression::COMPOUND: { switch (e.op) { case Operator::CALL: return true; default: return false; } } } return false; } static bool isDoubleValueValid(const Expression& e) { switch (e.__state) { case Expression::NUMBER: + case Expression::VARIANT: 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 < args.size(); ++i) { scope[t.bindings.at(i)] = args.at(i); } switch (t.__operator) { case TypeOperator::ARRAY: { assert(t.__operands.size() == 1); Expanded elTy = expandType(t.__operands.at(0)); return ExpandedType(TypeAnnotation(tag_array, elTy, 0)); } case TypeOperator::STRUCT: { assert(t.__operands.size()); std::vector&& pack = expandOperands(t.__operands); auto tnew = TypeAnnotation(TypeOperator::STRUCT, move(pack)); tnew.fields = t.fields; return ExpandedType(move(tnew)); }; case TypeOperator::CALL: { std::string alias = t.__valueCustom; //find in local scope: TypeAnnotation ty; if (scope.count(alias)) { ty = scope.at(alias); } 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() + : __operator(TypeOperator::NONE), __value(TypePrimitive::Invalid) + {} 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::isValid() const{ + return !(__value == TypePrimitive::Invalid && __operator == TypeOperator::NONE); + } + 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(); }); } unsigned int Expression::nextVacantId = 0; Expression::Expression(const Atom& number) : Expression() { __state=NUMBER; op=Operator::NONE; __valueD=number.get(); } Expression::Expression(const Atom& a) : Expression(){ __state=STRING; op=Operator::NONE; __valueS=a.get(); } Expression::Expression(const Atom &ident) : Expression() { __state=IDENT; op=Operator::NONE; __valueS=ident.get(); } Expression::Expression(const Operator &oprt, std::initializer_list params) : Expression() { __state=COMPOUND; op=oprt; if (op == Operator::CALL) { assert(params.size() > 0); Expression arg = *params.begin(); assert(arg.__state == Expression::IDENT); __valueS = std::move(arg.__valueS); operands.insert(operands.end(), params.begin() + 1, params.end()); 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::addTags(const std::list tags) const{ + std::transform(tags.begin(), tags.end(), std::inserter(this->tags, this->tags.end()), + [](const Expression& tag){ + return make_pair(tag.getValueString(), tag); + }); + } + void Expression::addBindings(std::initializer_list> params) { addBindings(params.begin(), params.end()); } void Expression::bindType(TypeAnnotation t) { 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), id(nextVacantId++) { } 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->op != other.op) { + return false; + } + if (this->operands.size() != other.operands.size()) { return false; } for (size_t i = 0; ioperands.size(); ++i) { if (!(this->operands[i] == other.operands[i])) return false; } + assert(!this->blocks.size()); + assert(!other.blocks.size()); + return true; } AST::AST() { Attachments::init(); Attachments::init(); } 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 < size; ++i) { result.push_back(ManagedFnPtr(i, &this->__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 + bool AST::recognizeVariantIdentifier(Expression& identifier) { + assert(identifier.__state == Expression::IDENT); - // * move to codescope - // * register var as alias to + std::string variant = identifier.getValueString(); + if (!__dictVariants.count(variant)) { + return false; + } - assert(identifier.__state == Expression::IDENT); + auto record = __dictVariants.at(variant); + const TypeAnnotation& typ = record.first; - 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; - identifier.__state = Expression::VARIANT; - identifier.setValueDouble(record.second); - identifier.type = typ; - } + return true; } 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)); } const std::string& Function::getName() const { return __name; } ScopedSymbol CodeScope::registerIdentifier(const Expression& identifier) { VariableVersion version = Attachments::get(identifier, VERSION_NONE); auto result = __identifiers.emplace(identifier.getValueString(), __vCounter); if (result.second){ ++__vCounter; return {__vCounter-1, version}; } return {result.first->second, version}; } bool CodeScope::recognizeIdentifier(const Expression& identifier) const{ VariableVersion version = Attachments::get(identifier, VERSION_NONE); const std::string& name = identifier.getValueString(); //search identifier in the current block if (__identifiers.count(name)){ VNameId id = __identifiers.at(name); Symbol s; s.identifier = ScopedSymbol{id, version}; s.scope = const_cast(this); - Attachments::put(s); + Attachments::put(identifier, s); return true; } //search in the parent scope if (__parent) { return __parent->recognizeIdentifier(identifier); } return false; } + ScopedSymbol + CodeScope::getSymbol(const std::string& alias){ + assert(__identifiers.count(alias)); + VNameId id = __identifiers.at(alias); + + return {id, VERSION_NONE}; + } + void AST::postponeIdentifier(CodeScope* scope, const Expression& id) { binUnrecognizedIdentifiers.emplace(scope, id); } void AST::recognizePostponedIdentifiers() { for(const auto& identifier: binUnrecognizedIdentifiers){ if (!identifier.first->recognizeIdentifier(identifier.second)){ //exception: Ident not found std::cout << "Unknown symbol: "<< identifier.second.getValueString() << std::endl; assert(false && "Symbol not found"); } } } void CodeScope::addBinding(Expression&& var, Expression&& argument) { argument.__state = Expression::BINDING; __bindings.push_back(var.getValueString()); ScopedSymbol binding = registerIdentifier(var); __declarations[binding] = move(argument); } void CodeScope::addDeclaration(Expression&& var, Expression&& body) { ScopedSymbol s = registerIdentifier(var); __declarations[s] = move(body); } CodeScope::CodeScope(CodeScope* parent) : __parent(parent) { } CodeScope::~CodeScope() { } void CodeScope::setBody(const Expression &body) { __declarations[ScopedSymbol::RetSymbol] = body; } Expression& CodeScope::getBody() { return __declarations[ScopedSymbol::RetSymbol]; } const Expression& - CodeScope::findDeclaration(const Symbol& symbol) { + CodeScope::getDeclaration(const Symbol& symbol) { CodeScope* self = symbol.scope; - return self->__declarations.at(symbol.identifier); + return self->getDeclaration(symbol.identifier); + } + + const Expression& + CodeScope::getDeclaration(const ScopedSymbol& symbol){ + assert(__declarations.count(symbol) && "Symbol's declaration not found"); + + return __declarations.at(symbol); } 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 ScopedSymbol& s1, const ScopedSymbol& s2) { + return (s1.id < s2.id) || (s1.id==s2.id && s1.version < s2.version); + } + + bool operator==(const ScopedSymbol& s1, const ScopedSymbol& s2) { + return (s1.id == s2.id) && (s1.version == s2.version); + } + bool operator<(const Symbol& s1, const Symbol& s2) { return (s1.scope < s2.scope) || (s1.scope == s2.scope && s1.identifier < s2.identifier); } bool operator==(const Symbol& s1, const Symbol& s2) { return (s1.scope == s2.scope) && (s1.identifier == s2.identifier); } 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; i < a.operands.size(); ++i) { bool result = a.operands[i] < b.operands[i]; if (result) return true; } return false; } case Expression::BINDING: case Expression::INVALID: assert(false); } return false; } - 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; - } - }; - +const ScopedSymbol +ScopedSymbol::RetSymbol = ScopedSymbol{0, VERSION_NONE}; } + diff --git a/cpp/src/ast.h b/cpp/src/ast.h index 55866ba..7407463 100644 --- a/cpp/src/ast.h +++ b/cpp/src/ast.h @@ -1,604 +1,558 @@ #ifndef AST_H #define AST_H #include "attachments.h" #include #include #include #include #include #include #include #include "utils.h" #include namespace llvm { class Value; } namespace xreate { - struct 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); +struct String_t { +}; - __value = buffer; - } +struct Identifier_t { +}; - Atom(std::string && name) : __value(name) { - } +struct Number_t { +}; - const std::string& get() const { - return __value; - } - private: - std::string __value; - }; +struct Type_t { +}; - template<> class Atom { - public: +template +class Atom { +}; - 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() { - } +//DEBT hold for all atoms/identifiers Parser::Token data, like line:col position +template<> class +Atom { +public: + Atom(const std::wstring& value); + Atom(std::string && name); + const std::string& get() const; + +private: + std::string __value; +}; + +template<> +class Atom { +public: + Atom(wchar_t* value); + Atom(int value); + double get()const; + +private: + double __value; +}; - TypePrimitive get() const { - return __value; - } +template<> +class Atom { +public: + Atom(const std::wstring& value); + const std::string& get() const; - private: - TypePrimitive __value; - }; +private: + std::string __value; +}; - typedef Atom TypeAtom; +enum class TypePrimitive { + Invalid, Bool, I8, I32, Num, Int, Float, String +}; 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); + bool isValid() const; TypeOperator __operator = TypeOperator::NONE; std::vector __operands; TypePrimitive __value; std::string __valueCustom; int conjuctionId = -1; //conjunction point id (relevant for recursive types) uint64_t __size = 0; std::vector fields; std::vector bindings; private: }; enum class Operator { ADD, SUB, MUL, DIV, EQU, NE, NEG, LSS, LSE, GTR, GTE, LIST, LIST_RANGE, LIST_NAMED, CALL, CALL_INTRINSIC, NONE, IMPL/* implication */, MAP, FOLD, FOLD_INF, LOOP_CONTEXT, INDEX, IF, SWITCH, SWITCH_ADHOC, CASE, CASE_DEFAULT, LOGIC_AND, ADHOC, CONTEXT_RULE }; 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 addTags(const std::list tags) const; 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; unsigned int id; std::vector bindings; std::map __indexBindings; std::vector operands; TypeAnnotation type; mutable std::map tags; std::list blocks; private: std::string __valueS; double __valueD; static unsigned int nextVacantId; }; 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 VNameId; typedef int VariableVersion; const VariableVersion VERSION_NONE = -2; + const VariableVersion VERSION_INIT = 0; template<> struct AttachmentsDict { typedef VariableVersion Data; static const unsigned int key = 6; }; struct ScopedSymbol{ VNameId id; VariableVersion version; static const ScopedSymbol RetSymbol; }; struct Symbol { ScopedSymbol identifier; CodeScope * scope; }; template<> struct AttachmentsDict { typedef Symbol Data; static const unsigned int key = 7; }; } namespace std { template<> struct hash{ std::size_t operator()(xreate::ScopedSymbol const& s) const; }; template<> struct equal_to{ bool operator()(const xreate::ScopedSymbol& __x, const xreate::ScopedSymbol& __y) const; }; } namespace xreate { typedef std::pair Tag; + bool operator<(const ScopedSymbol& s1, const ScopedSymbol& s2); + bool operator==(const ScopedSymbol& s1, const ScopedSymbol& s2); bool operator<(const Symbol& s1, const Symbol& s2); bool operator==(const Symbol& s1, const Symbol& s2); - class CodeScope { - friend class Function; - friend class PassManager; +class CodeScope { + friend class Function; + friend class PassManager; - public: - CodeScope(CodeScope* parent = 0); - void setBody(const Expression& body); - Expression& getBody(); - void addDeclaration(Expression&& var, Expression&& body); - void addBinding(Expression&& var, Expression&& argument); - static const Expression& findDeclaration(const Symbol& symbol); - - ~CodeScope(); - - std::vector __bindings; - std::map __identifiers; - - //TODO move __definitions to SymbolsAttachments data - //NOTE: definition of return type has zero(0) variable index - std::unordered_map __declarations; - std::vector tags; - std::vector contextRules; - - private: - VNameId __vCounter = 1; - CodeScope* __parent; - - ScopedSymbol registerIdentifier(const Expression& identifier); - public: - bool recognizeIdentifier(const Expression& identifier) const; - }; +public: + CodeScope(CodeScope* parent = 0); + void setBody(const Expression& body); + Expression& getBody(); + void addDeclaration(Expression&& var, Expression&& body); + void addBinding(Expression&& var, Expression&& argument); + static const Expression& getDeclaration(const Symbol& symbol); + const Expression& getDeclaration(const ScopedSymbol& symbol); - class Function { - friend class Expression; - friend class CodeScope; - friend class AST; + ~CodeScope(); - public: - Function(const Atom& name); + std::vector __bindings; + std::map __identifiers; - void addBinding(Atom && name, Expression&& argument); - void addTag(Expression&& tag, const TagModifier mod); + //TODO move __definitions to SymbolsAttachments data + //NOTE: definition of return type has zero(0) variable index + std::unordered_map __declarations; + std::vector tags; + std::vector contextRules; - 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 +private: + VNameId __vCounter = 1; + CodeScope* __parent; - Expression guardContext; - private: + ScopedSymbol registerIdentifier(const Expression& identifier); - std::map __tags; - }; +public: + bool recognizeIdentifier(const Expression& identifier) const; + ScopedSymbol getSymbol(const std::string& alias); +}; +class Function { + friend class Expression; + friend class CodeScope; + friend class AST; - class ExternData; +public: + Function(const Atom& name); - struct ExternEntry { - std::string package; - std::vector headers; - }; + void addBinding(Atom && name, Expression&& argument); + void addTag(Expression&& tag, const TagModifier mod); - typedef Expanded ExpandedType; + 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 - enum ASTInterface { - CFA, DFA, Extern, Adhoc - }; + Expression guardContext; +private: - struct FunctionSpecialization { - std::string guard; - size_t id; - }; + std::map __tags; +}; - struct FunctionSpecializationQuery { - std::unordered_set context; - }; - template<> - struct AttachmentsId{ - static unsigned int getId(const Expression& expression){ - return expression.id; - } - }; - - template<> - struct AttachmentsId{ - static unsigned int getId(const Symbol& s){ - return s.scope->__declarations.at(s.identifier).id; - } - }; - - class AST { - public: - AST(); +class ExternData; + +struct ExternEntry { + std::string package; + std::vector headers; +}; + +typedef Expanded ExpandedType; - //TASK extern and DFA interfaces move into addInterfaceData - /** - * DFA Interface - */ - void addDFAData(Expression&& data); +enum ASTInterface { + CFA, DFA, Extern, Adhoc +}; - /** - * Extern Interface - */ - void addExternData(ExternData&& data); +struct FunctionSpecialization { + std::string guard; + size_t id; +}; - void addInterfaceData(const ASTInterface& interface, Expression&& data); - void add(Function* f); +struct FunctionSpecializationQuery { + std::unordered_set context; +}; - void add(MetaRuleAbstract* r); - ManagedScpPtr add(CodeScope* scope); +template<> +struct AttachmentsId{ + static unsigned int getId(const Expression& expression){ + return expression.id; + } +}; - std::string getModuleName(); - ManagedPtr findFunction(const std::string& name); +template<> +struct AttachmentsId{ + static unsigned int getId(const Symbol& s){ + return s.scope->__declarations.at(s.identifier).id; + } +}; - typedef std::multimap FUNCTIONS_REGISTRY; - std::list getAllFunctions() const; - std::list getFunctionVariants(const std::string& name) const; +template<> +struct AttachmentsId{ + static unsigned int getId(const ManagedFnPtr& f){ + const Symbol symbolFunction{ScopedSymbol::RetSymbol, f->getEntryScope()}; + + return AttachmentsId::getId(symbolFunction); + } +}; +class AST { +public: + AST(); - template - ManagedPtr begin(); + //TASK extern and DFA interfaces move into addInterfaceData + /** + * DFA Interface + */ + void addDFAData(Expression&& data); - 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. + /** + * Extern Interface + */ + void addExternData(ExternData&& data); - private: - std::vector __rules; - std::vector __functions; - std::vector __scopes; + void addInterfaceData(const ASTInterface& interface, Expression&& data); + void add(Function* f); - FUNCTIONS_REGISTRY __indexFunctions; + void add(MetaRuleAbstract* r); + ManagedScpPtr add(CodeScope* scope); + std::string getModuleName(); + ManagedPtr findFunction(const std::string& name); - // ***** TYPES SECTION ***** - public: - std::map __indexTypeAliases; - ExpandedType expandType(const TypeAnnotation &t) const; - ExpandedType findType(const std::string& name); - void add(TypeAnnotation t, Atom alias); - - //TODO revisit enums/variants - void recognizeVariantIdentifier(Expression& identifier); + typedef std::multimap FUNCTIONS_REGISTRY; + std::list getAllFunctions() const; + std::list getFunctionVariants(const std::string& name) const; - private: - std::map> __dictVariants; - ExpandedType expandType(const TypeAnnotation &t, std::map scope, - const std::vector &args = std::vector()) const; + template + ManagedPtr begin(); - // ***** SYMBOL RECOGNITION ***** - public: - std::set> binUnrecognizedIdentifiers; - - public: - void postponeIdentifier(CodeScope* scope, const Expression& id); - void recognizePostponedIdentifiers(); - }; + 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. - template<> - ManagedPtr - AST::begin(); +private: + std::vector __rules; + std::vector __functions; + std::vector __scopes; - template<> - ManagedPtr - AST::begin(); + FUNCTIONS_REGISTRY __indexFunctions; - template<> - ManagedPtr - AST::begin(); + + // ***** TYPES SECTION ***** +public: + std::map __indexTypeAliases; + ExpandedType expandType(const TypeAnnotation &t) const; + ExpandedType findType(const std::string& name); + void add(TypeAnnotation t, Atom alias); + + //TODO revisit enums/variants, move to codescope + bool recognizeVariantIdentifier(Expression& identifier); + + +private: + std::map> __dictVariants; + ExpandedType expandType(const TypeAnnotation &t, std::map scope, + const std::vector &args = std::vector()) const; + + // ***** SYMBOL RECOGNITION ***** +public: + std::set> binUnrecognizedIdentifiers; + +public: + void postponeIdentifier(CodeScope* scope, const Expression& id); + void recognizePostponedIdentifiers(); +}; + +template<> +ManagedPtr +AST::begin(); + +template<> +ManagedPtr +AST::begin(); + +template<> +ManagedPtr +AST::begin(); } #endif // AST_H diff --git a/cpp/src/attachments.cpp b/cpp/src/attachments.cpp index 6dd9515..61fcdcd 100644 --- a/cpp/src/attachments.cpp +++ b/cpp/src/attachments.cpp @@ -1,5 +1,10 @@ // // Created by pgess on 3/15/15. // -#include "attachments.h" \ No newline at end of file +#include "attachments.h" + +using namespace xreate; + +std::vector +Attachments::__storage = std::vector(); \ No newline at end of file diff --git a/cpp/src/attachments.h b/cpp/src/attachments.h index 6e09a7c..1fd3e48 100644 --- a/cpp/src/attachments.h +++ b/cpp/src/attachments.h @@ -1,125 +1,158 @@ // // Created by pgess on 3/15/15. // #ifndef _XREATE_ATTACHMENTS_H_ #define _XREATE_ATTACHMENTS_H_ -#include +#include #include #include #include namespace xreate { //Attachments dictionary template struct AttachmentsDict { // typedef void Data; - // static const unsigned int key (current unreserved - 8); + // static const unsigned int key (current unreserved - 9); }; template struct AttachmentsId{ //static unsigned int getId(const Object& object); }; - //TODO add specialization for pointers - template - class AttachmentsStorage - { + +template +class IAttachmentsContainer{ + protected: + virtual bool __exists(const unsigned int object)=0; + virtual Data& __get(const unsigned int object)=0; + virtual void __put(const unsigned int object, Data data)=0; + public: - void put(unsigned int id, Data data) - { - __data.emplace(id, data); + template + bool exists(const Id& object){ + unsigned int id = AttachmentsId::getId(object); + + return __exists(id); } - Data& get(unsigned int id) - { - return __data.at(id); + template + Data& get(const Id& object){ + unsigned int id = AttachmentsId::getId(object); + + return __get(id); } - - Data get(unsigned int id, Data dataDefault) - { - if (! exists(id)){ + + template + Data get(const Id& object, const Data& dataDefault){ + unsigned int id = AttachmentsId::getId(object); + + if (! __exists(id)){ return dataDefault; } - - return __data.at(id); + + return __get(id); } - bool exists(unsigned int id) - { - return __data.count(id); + template + void put(const Id& object, Data data){ + unsigned int id = AttachmentsId::getId(object); + + __put(id, data); } - private: - std::map __data; - }; + virtual ~IAttachmentsContainer(){}; +}; - class Attachments{ - public: - template - using Data = typename AttachmentsDict::Data; +template +class AttachmentsContainerDefault: public IAttachmentsContainer{ +private: + std::unordered_map __data; - template - static Data& get(const Id& object) - { - unsigned int id = AttachmentsId::getId(object); - AttachmentsStorage>* self = reinterpret_cast>*>(__storage[AttachmentsDict::key]); + virtual bool __exists(const unsigned int id){ + return __data.count(id); + } - return self->exists(id); - } - - template - static Data& get(const Id& object) - { - unsigned int id = AttachmentsId::getId(object); - AttachmentsStorage>* self = reinterpret_cast>*>(__storage[AttachmentsDict::key]); + virtual Data& __get(const unsigned int id){ + return __data.at(id); + } - return self->get(id); - } + virtual void __put(const unsigned int id, Data data){ + auto result = __data.emplace(id, data); + assert(result.second); + } +}; + + +class Attachments{ + private: + static std::vector __storage; + template + using Data = typename AttachmentsDict::Data; + + public: template - static Data get(const Id& object, Data dataDefault) - { - unsigned int id = AttachmentsId::getId(object); - AttachmentsStorage>* self = reinterpret_cast>*>(__storage[AttachmentsDict::key]); - - return self->get(id, dataDefault); + static bool exists(const Id& object) { + assert(AttachmentsDict::key < __storage.size()); + assert(__storage.at(AttachmentsDict::key)); + + IAttachmentsContainer>* self = reinterpret_cast>*>(__storage.at(AttachmentsDict::key)); + return self->exists(object); } template - static void put(const Id& object, Data data) - { - unsigned int id = AttachmentsId::getId(object); - AttachmentsStorage>* self = reinterpret_cast>*>(__storage[AttachmentsDict::key]); - - self->put(id, std::move(data)); + static Data& get(const Id& object){ + assert(AttachmentsDict::key < __storage.size()); + assert(__storage.at(AttachmentsDict::key)); + + IAttachmentsContainer>* self = reinterpret_cast>*>(__storage.at(AttachmentsDict::key)); + return self->get(object); } - + template - static void put(const Id& object) - { - unsigned int id = AttachmentsId::getId(object); - AttachmentsStorage>* self = reinterpret_cast>*>(__storage[AttachmentsDict::key]); - - return self->exists(id); + static Data get(const Id& object, const Data& dataDefault){ + assert(AttachmentsDict::key < __storage.size()); + assert(__storage.at(AttachmentsDict::key)); + + IAttachmentsContainer>* self = reinterpret_cast>*>(__storage.at(AttachmentsDict::key)); + return self->get(object, dataDefault); + } + + template + static void put(const Id& object, Data data){ + assert(AttachmentsDict::key < __storage.size()); + assert(__storage.at(AttachmentsDict::key)); + + IAttachmentsContainer>* self = reinterpret_cast>*>(__storage.at(AttachmentsDict::key)); + self->put(object, data); } template static void init(){ unsigned int keyStorage = AttachmentsDict::key; if (keyStorage+1 > __storage.size()){ __storage.resize(keyStorage + 1, nullptr); } - __storage[keyStorage] = new AttachmentsStorage>(); + __storage[keyStorage] = new AttachmentsContainerDefault>(); } - private: - static std::vector __storage; - }; + template + static void init(IAttachmentsContainer>* container){ + unsigned int keyStorage = AttachmentsDict::key; + if (keyStorage+1 > __storage.size()){ + __storage.resize(keyStorage + 1, nullptr); + } + + __storage[keyStorage] = container; + } +}; + } #endif //_XREATE_ATTACHMENTS_H_ \ No newline at end of file diff --git a/cpp/src/clasplayer.cpp b/cpp/src/clasplayer.cpp index 6434235..65ff3fb 100644 --- a/cpp/src/clasplayer.cpp +++ b/cpp/src/clasplayer.cpp @@ -1,275 +1,275 @@ #include "clasplayer.h" #include #include "utils.h" #include #include #include #include "analysis/aux.h" #include "analysis/DominatorsTreeAnalysisProvider.h" #include "analysis/cfagraph.h" #include "analysis/dfagraph.h" using namespace std; //TODO escape identifiers started from upper case symbol namespace xreate { void ClaspLayer::printWarnings(std::ostream& out) { const std::string warningTag = "warning"; auto warningsRange = __model.equal_range(warningTag); for (auto warning=warningsRange.first; warning!= warningsRange.second; ++warning) { unsigned int warningId; Gringo::Symbol params; std::tie(warningId, params) = parse(warning->second); cout << "Warning: " << __warnings.at(warningId) << " "; params.print(out); out< warnings; cout << "Model: " << endl; const string& atomBindVar = Config::get("clasp.bindings.variable"); const string& atomBindFunc = Config::get("clasp.bindings.function"); const string& atomBindScope = Config::get("clasp.bindings.scope"); for (Gringo::Symbol atom : model.atoms(clingo_show_type_atoms)) { atom.print(cout); cout <<" | "<< endl; string atomName(atom.name().c_str()); if (atomName == atomBindVar || atomName == atomBindFunc || atomName == atomBindScope){ string name = std::get<1>(parse(atom)).name().c_str(); __model.emplace(move(name), move(atom)); } __model.emplace(atomName, move(atom)); } return true; } void ClaspLayer::setCFAData(xreate::analysis::CFAGraph* graph) { dataCFA.reset(graph); } void ClaspLayer::setDFAData(xreate::analysis::DFAGraph* graph){ dataDFA.reset(graph); } void ClaspLayer::addRuleWarning(const RuleWarning &rule) { //__partGeneral << rule << endl; list domains; boost::format formatDef("%1%(%2%)"); std::transform(rule.__args.begin(), rule.__args.end(), std::inserter(domains, domains.begin()), [&formatDef](const std::pair &argument) { string domain; switch (argument.second) { case DomainAnnotation::FUNCTION: domain = "function"; break; case DomainAnnotation::VARIABLE: domain = "variable"; break; } return boost::str(formatDef % domain % argument.first); }); list vars; std::transform(rule.__args.begin(), rule.__args.end(), std::inserter(vars, vars.begin()), [](const std::pair &argument) { return argument.first.c_str(); }); list> guardsRaw; std::transform(rule.__guards.begin(), rule.__guards.end(), std::inserter(guardsRaw, guardsRaw.begin()), [this](const Expression &guard) { return xreate::analysis::compile(guard); }); const list& guards = xreate::analysis::multiplyLists(std::move(guardsRaw)); list &&branches = xreate::analysis::compileNeg(rule.__condition); boost::format formatWarning("warning(%1%, (%2%)):- %3%, %4%, %5%."); for (const string &guardsJoined: guards) for (const string &branch: branches) { unsigned int hook = registerWarning(string(rule.__message)); __partGeneral << formatWarning %(hook) %(boost::algorithm::join(vars, ", ")) %(branch) %(guardsJoined) %(boost::algorithm::join(domains, ", ")) <__rawImports) { std::ifstream file(fn); if (!file) continue; while(!file.eof()){ string line; std::getline(file, line); out << line << endl; } } } void ClaspLayer::addRawScript(std::string&& script){ __partGeneral << script; } void ClaspLayer::run() { involveImports(); if (this->dataDFA){ this->dataDFA->print(__partGeneral); } if (this->dataCFA){ this->dataCFA->print(__partGeneral); } DominatorsTreeAnalysisProvider providerDominators; providerDominators.run(this); providerDominators.print(__partGeneral); ostringstream program; program << __partTags.str() << __partGeneral.str(); cout << FYEL(program.str()) << endl; std::vector args{"clingo", nullptr}; DefaultGringoModule moduleDefault; Gringo::Scripts scriptsDefault(moduleDefault); ClingoLib ctl(scriptsDefault, 0, args.data(), {}, 0); ctl.add("base", {}, program.str()); ctl.ground({{"base", {}}}, nullptr); // solve Gringo::SolveResult result = ctl.solve([this](Gringo::Model const &model) { this->handleSolution(model); return true; }, {}); if (result.satisfiable() == Gringo::SolveResult::Satisfiable) { cout << FGRN("SUCCESSFULLY") << endl; } else { cout << FRED("UNSUCCESSFULLY") << endl; } // invoke all query plugins to process clasp data for (auto q: __queries) { q.second->init(this); } } ClaspLayer::ClaspLayer() { } ClaspLayer::ModelFragment ClaspLayer::query(const std::string& atom) { if (! __model.count(atom)){ return boost::none; } return ModelFragment(__model.equal_range(atom)); } ScopePacked ClaspLayer::pack(CodeScope* const scope) { auto pos = __indexScopes.emplace(scope, __indexScopes.size()); if (pos.second) __registryScopes.push_back(scope); return pos.first->second; } size_t ClaspLayer::getScopesCount() const{ return __registryScopes.size(); } SymbolPacked ClaspLayer::pack(const Symbol& symbol, std::string hintSymbolName) { - SymbolPacked result(symbol.identifier, pack(symbol.scope)); + SymbolPacked result(symbol.identifier.id, symbol.identifier.version, pack(symbol.scope)); __indexSymbolNameHints.emplace(result, hintSymbolName); return result; } Symbol ClaspLayer::unpack(const SymbolPacked& symbol) { - return Symbol{symbol.identifier, __registryScopes[symbol.scope]}; + return Symbol{ScopedSymbol{symbol.identifier, symbol.version}, __registryScopes[symbol.scope]}; }; std::string ClaspLayer::getHintForPackedSymbol(const SymbolPacked& symbol){ if (!symbol.categoryTransient) { auto result = __indexSymbolNameHints.find(symbol); return (result == __indexSymbolNameHints.end())? "" : result->second; } else { return "anonym(" + to_string(symbol.identifier) + ")"; } } bool operator==(const SymbolPacked& s1, const SymbolPacked& s2) { return s1.identifier == s2.identifier && s1.scope == s2.scope; } bool operator<(const SymbolPacked& s1, const SymbolPacked& s2) { return s1.scope < s2.scope || (s1.scope == s2.scope && s1.identifier < s2.identifier); } IQuery* ClaspLayer::registerQuery(IQuery *query, const QueryId& id) { return __queries.emplace(id, query).first->second; } IQuery* ClaspLayer::getQuery(const QueryId& id){ assert(__queries.count(id) && "Undefined query"); return __queries.at(id); } } \ No newline at end of file diff --git a/cpp/src/clasplayer.h b/cpp/src/clasplayer.h index eccdff9..1bfe432 100644 --- a/cpp/src/clasplayer.h +++ b/cpp/src/clasplayer.h @@ -1,230 +1,233 @@ #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 { - ScopedSymbol identifier; + VNameId identifier; + VariableVersion version; ScopePacked scope; bool categoryTransient; SymbolPacked(): categoryTransient(false){} - SymbolPacked(ScopedSymbol i, ScopePacked s, bool isTransient = false): identifier(i), scope(s), categoryTransient(isTransient){} + SymbolPacked(ScopedSymbol i, ScopePacked s, bool isTransient = false): identifier(i.id), version(i.version), scope(s), categoryTransient(isTransient){} + SymbolPacked(VNameId symbolId, VariableVersion symbolVersion, ScopePacked symbolScope, bool isTransient = false) + : identifier(symbolId), version(symbolVersion), scope(symbolScope), categoryTransient(isTransient){} }; bool operator==(const SymbolPacked& s1, const SymbolPacked& s2); bool operator<(const SymbolPacked& s1, const SymbolPacked& s2); enum class DFGConnection { STRONG, WEAK, PROTOTYPE }; class IAnalysisData { public: void print(std::ostringstream& output) const; virtual ~IAnalysisData(){}; }; class IQuery { public: virtual void init(ClaspLayer* clasp) = 0; virtual ~IQuery() {} }; enum class QueryId { ContainersQuery, ContextQuery, PtrvalidQuery }; namespace analysis{ class DFAGraph; class CFAGraph; } class ClaspLayer { friend class ContextRule; //PROVIDERS: public: boost::scoped_ptr dataDFA; void setDFAData(xreate::analysis::DFAGraph* graph); boost::scoped_ptr dataCFA; void setCFAData(xreate::analysis::CFAGraph* graph); void addRawScript(std::string&& script); private: void involveImports(); //QUERIES public: IQuery* registerQuery(IQuery* query, const QueryId& id); IQuery* getQuery(const QueryId& id); template static std::tuple parse(const Gringo::Symbol& atom); typedef std::multimap::const_iterator ModelIterator; typedef boost::optional> ModelFragment; ModelFragment query(const std::string& atom); size_t getScopesCount() const; SymbolPacked pack(const Symbol& symbol, std::string hintSymbolName = ""); ScopePacked pack(CodeScope * const scope); Symbol unpack(const SymbolPacked& symbol); std::string getHintForPackedSymbol(const SymbolPacked& symbol); private: std::map __queries; std::multimap __model; std::map __indexSymbolNameHints; std::unordered_map __indexScopes; std::vector __registryScopes; //WARNINGS //TODO move to separate provider/query public: void addRuleWarning(const RuleWarning &rule); unsigned int registerWarning(std::string &&message); private: std::map __warnings; void printWarnings(std::ostream& out); //DEFAULT public: AST *ast; ClaspLayer(); void run(); private: std::ostringstream __partTags; std::ostringstream __partGeneral; bool handleSolution(Gringo::Model const &model); }; template struct ParseImplAtom { static typ get(const Gringo::Symbol& atom) { return atom.num(); } }; template<> struct ParseImplAtom { static std::string get(const Gringo::Symbol& atom) { switch (atom.type()) { case Gringo::SymbolType::Str: return atom.string().c_str(); case Gringo::SymbolType::Fun: return atom.name().c_str(); default: break; } assert(false && "Inappropriate symbol type"); } }; template<> struct ParseImplAtom { static SymbolPacked get(const Gringo::Symbol& atom) { - auto result = ClaspLayer::parse(atom); - return SymbolPacked(std::get<0>(result), std::get<1>(result)); + auto result = ClaspLayer::parse(atom); + return SymbolPacked(std::get<0>(result), std::get<1>(result), std::get<2>(result)); } }; template<> struct ParseImplAtom { static Gringo::Symbol get(const Gringo::Symbol& atom) { return atom; } }; template<> struct ParseImplAtom { static Expression get(const Gringo::Symbol& atom) { switch (atom.type()) { case Gringo::SymbolType::Num: return Expression(atom.num()); case Gringo::SymbolType::Str: return Expression(std::string(atom.string().c_str())); case Gringo::SymbolType::Fun: { //ID if (!atom.args().size){ return Expression(std::string(atom.name().c_str())); } //FUNC Expression result(Operator::CALL,{Expression(std::string(atom.name().c_str()))}); for (const Gringo::Symbol& arg : atom.args()) { result.addArg(ParseImplAtom::get(arg)); } return result; } default: { assert(false); } } } }; template struct Parse_Impl { static void parse(Tuple& tup, Gringo::SymSpan::iterator arg) { const size_t tupleSize = std::tuple_size::value; typedef typename std::tuple_element < tupleSize - index, Tuple>::type ElType; ElType& el = std::get < tupleSize - index > (tup); Gringo::Symbol atom = *arg; el = ParseImplAtom::get(atom); Parse_Impl ::parse(tup, ++arg); } }; template struct Parse_Impl { static void parse(Tuple& tup, Gringo::SymSpan::iterator arg) { } }; template std::tuple ClaspLayer::parse(const Gringo::Symbol& atom) { typedef std::tuple < Types...> Tuple; Tuple tup; Parse_Impl::value>::parse(tup, atom.args().first); return tup; } } #endif \ No newline at end of file diff --git a/cpp/src/compilation/advanced.cpp b/cpp/src/compilation/advanced.cpp index 40465ac..afef03a 100644 --- a/cpp/src/compilation/advanced.cpp +++ b/cpp/src/compilation/advanced.cpp @@ -1,431 +1,404 @@ /* * File: InstructionsAdvanced.cpp * Author: pgess * * Created on June 26, 2016, 6:00 PM */ -#include +//#include #include "compilation/advanced.h" #include "compilation/containers.h" #include "query/context.h" #include "query/containers.h" #include "llvmlayer.h" #include "ast.h" using namespace std; using namespace llvm; using namespace xreate; using namespace xreate::containers; using namespace xreate::compilation; #define NAME(x) (hintRetVar.empty()? x : hintRetVar) #define UNUSED(x) (void)(x) #define EXPAND_CONTEXT \ LLVMLayer* llvm = context.pass->man->llvm; \ - compilation::CodeScopeUnit* scope = context.scope; \ + compilation::AbstractCodeScopeUnit* scope = context.scope; \ compilation::FunctionUnit* function = context.function; Advanced::Advanced(compilation::Context ctx) : context(ctx), tyNum(static_cast (ctx.pass->man->llvm->toLLVMType(ExpandedType(TypeAnnotation(TypePrimitive::Num))))) { } llvm::Value* Advanced::compileMapSolidOutput(const Expression &expr, const std::string hintRetVar) { EXPAND_CONTEXT //initialization Symbol symbolIn = Attachments::get(expr.getOperands()[0]); ImplementationRec implIn = containers::Query::queryImplementation(symbolIn).extract(); // impl of input list size_t size = implIn.size; CodeScope* scopeLoop = expr.blocks.front(); std::string varEl = scopeLoop->__bindings[0]; Iterator* it = Iterator::create(context, symbolIn); llvm::Value *rangeFrom = it->begin(); llvm::Value *rangeTo = it->end(); //definitions ArrayType* tyNumArray = (ArrayType*) (llvm->toLLVMType(ExpandedType(TypeAnnotation(tag_array, TypePrimitive::Num, size)))); llvm::IRBuilder<> &builder = llvm->builder; llvm::BasicBlock *blockLoop = llvm::BasicBlock::Create(llvm::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); + compilation::AbstractCodeScopeUnit* scopeLoopUnit = function->getScopeUnit(scopeLoop); scopeLoopUnit->bindArg(elIn, move(varEl)); Value* elOut = scopeLoopUnit->compile(); Value *pElOut = builder.CreateGEP(dataOut, ArrayRef(std::vector{ConstantInt::get(tyNum, 0), stateLoop})); builder.CreateStore(elOut, pElOut); //next iteration preparing Value *stateLoopNext = builder.CreateAdd(stateLoop, llvm::ConstantInt::get(tyNum, 1)); stateLoop->addIncoming(stateLoopNext, blockLoop); //next iteration checks: Value* condAfter = builder.CreateICmpSLE(stateLoopNext, rangeTo); builder.CreateCondBr(condAfter, blockLoop, blockAfterLoop); //finalization: builder.SetInsertPoint(blockAfterLoop); return dataOut; } Value* Advanced::compileArrayIndex(llvm::Value* aggregate, std::vector indexes, std::string hintRetVar) { EXPAND_CONTEXT UNUSED(function); indexes.insert(indexes.begin(), llvm::ConstantInt::get(tyNum, 0)); llvm::Value *pEl = llvm->builder.CreateGEP(aggregate, llvm::ArrayRef(indexes)); return llvm->builder.CreateLoad(pEl, NAME("el")); } Value* Advanced::compileStructIndex(llvm::Value* aggregate, const ExpandedType& t, const std::string& idx) { EXPAND_CONTEXT UNUSED(scope); TypeUtils types(llvm); std::vector&& fields = types.getStructFields(t); for (unsigned i = 0, size = fields.size(); i < size; ++i) { if (fields.at(i) == idx) { std::vector refs; llvm::IntegerType* tyInt = llvm::Type::getInt32Ty(llvm::getGlobalContext()); llvm::ConstantInt* zero = llvm::ConstantInt::get(tyInt, 0, false); llvm::BasicBlock *blockSafe = llvm::BasicBlock::Create(llvm::getGlobalContext(), "safe", function->raw); // TODO review safety check: validPtr for `aggregate` // SECTIONTAG validptr exception PointerType* tyAggr = dyn_cast(aggregate->getType()); llvm::Value* null = llvm::ConstantPointerNull::get(tyAggr); Value* condNull = llvm->builder.CreateICmpNE(aggregate, null); llvm::BasicBlock *blockException = llvm::BasicBlock::Create(llvm::getGlobalContext(), "exception", function->raw); llvm->builder.CreateCondBr(condNull, blockSafe, blockException); llvm->initExceptionBlock(blockException); llvm->builder.SetInsertPoint(blockSafe); std::vector indexes; //dereference pointer if (types.isPointer(t)) { indexes.push_back(zero); } indexes.push_back(ConstantInt::get(tyInt, i)); Value* addr = llvm->builder.CreateGEP(aggregate, indexes); return llvm->builder.CreateLoad(addr); } } assert(false && "not found required struct field"); return nullptr; } llvm::Value* Advanced::compileFold(const Expression& fold, const std::string& hintRetVar) { EXPAND_CONTEXT assert(fold.op == Operator::FOLD); //initialization: Symbol varInSymbol = Attachments::get(fold.getOperands()[0]); Implementation info = Query::queryImplementation(varInSymbol); Iterator* it = Iterator::create(context, varInSymbol); llvm::Value* rangeBegin = it->begin(); llvm::Value* rangeEnd = it->end(); llvm::Value* accumInit = scope->process(fold.getOperands()[1]); std::string varIn = fold.getOperands()[0].getValueString(); std::string varAccum = fold.bindings[1]; std::string varEl = fold.bindings[0]; - TransformerSaturation* transformerSaturation = context.pass->transformations->get(); + + //require transformers feature + //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); + compilation::AbstractCodeScopeUnit* 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); - } + + //reuiqre transformers feature +// 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(); + + //require transformers feature + //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); + compilation::AbstractCodeScopeUnit* 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); + + //require transformers feature +// assert(transformerSaturation->exists()); +// 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::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")); + llvm::PHINode *ret = builder.CreatePHI(resultTrue->getType(), 2, NAME("if")); ret->addIncoming(resultTrue, blockTrue); ret->addIncoming(resultFalse, blockFalse); return ret; } //TODO Switch: default variant no needed when all possible conditions are considered llvm::Value* Advanced::compileSwitch(const Expression& exprSwitch, const std::string& hintRetVar) { EXPAND_CONTEXT UNUSED(function); assert(exprSwitch.operands.size() >= 2); assert(exprSwitch.operands[1].op == Operator::CASE_DEFAULT && "No default case in Switch Statement"); int countCases = exprSwitch.operands.size() - 1; llvm::IRBuilder<>& builder = llvm->builder; llvm::BasicBlock* blockProlog = builder.GetInsertBlock(); llvm::BasicBlock *blockEpilog = llvm::BasicBlock::Create(llvm::getGlobalContext(), "switchAfter", function->raw); builder.SetInsertPoint(blockEpilog); llvm::Type* exprSwitchType = llvm->toLLVMType(ExpandedType(exprSwitch.type)); llvm::PHINode *ret = builder.CreatePHI(exprSwitchType, countCases, NAME("switch")); builder.SetInsertPoint(blockProlog); llvm::Value * conditionSwitch = scope->process(exprSwitch.operands[0]); llvm::BasicBlock *blockDefault = llvm::BasicBlock::Create(llvm::getGlobalContext(), "caseDefault", function->raw); llvm::SwitchInst * instructionSwitch = builder.CreateSwitch(conditionSwitch, blockDefault, countCases); for (int size = exprSwitch.operands.size(), i = 2; i < size; ++i) { llvm::BasicBlock *blockCase = llvm::BasicBlock::Create(llvm::getGlobalContext(), "case" + std::to_string(i), function->raw); llvm::Value* condCase = function->getScopeUnit(exprSwitch.operands[i].blocks.front())->compile(); builder.SetInsertPoint(blockCase); llvm::Value* resultCase = function->getScopeUnit(exprSwitch.operands[i].blocks.back())->compile(); builder.CreateBr(blockEpilog); ret->addIncoming(resultCase, builder.GetInsertBlock()); builder.SetInsertPoint(blockProlog); instructionSwitch->addCase(dyn_cast(condCase), blockCase); } //compile default block: builder.SetInsertPoint(blockDefault); CodeScope* scopeDefault = exprSwitch.operands[1].blocks.front(); llvm::Value* resultDefault = function->getScopeUnit(scopeDefault)->compile(); builder.CreateBr(blockEpilog); ret->addIncoming(resultDefault, builder.GetInsertBlock()); builder.SetInsertPoint(blockEpilog); return ret; } //TODO recognize cases to make const arrays/stored in global mem/stack alloced. llvm::Value* Advanced::compileListAsSolidArray(const Expression &expr, const std::string& hintRetVar) { EXPAND_CONTEXT UNUSED(scope); UNUSED(function); AST* root = context.pass->man->root; const size_t& length = expr.getOperands().size(); const Expression& expression = expr; llvm::Value* zero = ConstantInt::get(tyNum, 0); llvm::Value* one = ConstantInt::get(tyNum, 1); ExpandedType typAggrExpanded = root->expandType(expression.type); assert(typAggrExpanded->__operator == TypeOperator::ARRAY); llvm::Type* typEl = llvm->toLLVMType(ExpandedType(typAggrExpanded->__operands[0])); ArrayType* typAggr = (ArrayType*) llvm::ArrayType::get(typEl, length); llvm::Value* list = llvm->builder.CreateAlloca(typAggr, ConstantInt::get(Type::getInt32Ty(llvm::getGlobalContext()), length, false), hintRetVar); const std::vector& operands = expression.getOperands(); llvm::Value* addrOperand = llvm->builder.CreateGEP(typAggr, list, ArrayRef(std::vector{zero, zero})); llvm->builder.CreateStore(scope->process(operands.front()), addrOperand) ; for (auto i=++operands.begin(); i!=operands.end(); ++i){ addrOperand = llvm->builder.CreateGEP(typEl, addrOperand, ArrayRef(std::vector{one})); llvm->builder.CreateStore(scope->process(*i), addrOperand) ; } return list; // Value* listDest = l.builder.CreateAlloca(typList, ConstantInt::get(typI32, __size), *hintRetVar); // l.buil1der.CreateMemCpy(listDest, listSource, __size, 16); } llvm::Value* Advanced::compileConstantStringAsPChar(const string& data, const std::string& hintRetVar) { EXPAND_CONTEXT UNUSED(function); UNUSED(scope); Type* typPchar = PointerType::getUnqual(Type::getInt8Ty(llvm::getGlobalContext())); //ArrayType* typStr = (ArrayType*) (llvm->toLLVMType(ExpandedType(TypeAnnotation(tag_array, TypePrimitive::I8, size+1)))); /* std::vector chars; chars.reserve(size+1); for (size_t i=0; i< size; ++i){ chars[i] = ConstantInt::get(typI8, (unsigned char) data[i]); } chars[size] = ConstantInt::get(typI8, 0); */ Value* rawData = ConstantDataArray::getString(llvm::getGlobalContext(), data); Value* rawPtrData = llvm->builder.CreateAlloca(rawData->getType(), ConstantInt::get(Type::getInt32Ty(llvm::getGlobalContext()), 1, false)); llvm->builder.CreateStore(rawData, rawPtrData); return llvm->builder.CreateCast(llvm::Instruction::BitCast, rawPtrData, typPchar, hintRetVar); } diff --git a/cpp/src/compilation/advanced.h b/cpp/src/compilation/advanced.h index 373e825..5bef2ef 100644 --- a/cpp/src/compilation/advanced.h +++ b/cpp/src/compilation/advanced.h @@ -1,47 +1,49 @@ /* * File: InstructionsAdvanced.h * Author: pgess * * Created on June 26, 2016, 6:00 PM */ #ifndef INSTRUCTIONSADVANCED_H #define INSTRUCTIONSADVANCED_H #include "ast.h" #include "llvmlayer.h" #include "pass/compilepass.h" #include namespace xreate { namespace compilation { class Advanced { public: Advanced(compilation::Context ctx); llvm::Value* compileArrayIndex(llvm::Value* aggregate, std::vector indexes, std::string ident = ""); llvm::Value* compileStructIndex(llvm::Value* aggregate, const ExpandedType& t, const std::string& idx); /* * - map Computation -> Llvm_Array: Prohibited, we do not know a result size * - map Llvm_Array -> Computation: considered in `compileGetElement` * - map Llvm_Array -> Llvm_Array considered by this method */ llvm::Value* compileMapSolidOutput(const Expression &expr, const std::string hintRetVar = ""); llvm::Value* compileFold(const Expression& fold, const std::string& ident=""); llvm::Value* compileFoldInf(const Expression& fold, const std::string& ident=""); + + //DISABLEDFEATURE Context Loop llvm::Value* compileLoopContext(const Expression& expression, const std::string& hintRetVar); llvm::Value* compileIf(const Expression& exprIf, const std::string& ident); llvm::Value* compileSwitch(const Expression& exprSwitch, const std::string& hintRetVar); llvm::Value* compileConstantStringAsPChar(const std::string &data, const std::string& hintRetVar); llvm::Value* compileListAsSolidArray(const Expression &expr, const std::string& hintRetVar=""); private: compilation::Context context; llvm::IntegerType* const tyNum; }; }} #endif /* INSTRUCTIONSADVANCED_H */ diff --git a/cpp/src/compilation/containers.cpp b/cpp/src/compilation/containers.cpp index eb3c4cc..f60f5ed 100644 --- a/cpp/src/compilation/containers.cpp +++ b/cpp/src/compilation/containers.cpp @@ -1,195 +1,195 @@ #include "compilation/containers.h" using namespace std; using namespace llvm; using namespace xreate; using namespace xreate::containers; Iterator* Iterator::create(xreate::compilation::Context context, const xreate::Symbol& var){ const Implementation& data = Query::queryImplementation(var); switch(data.impl){ case ON_THE_FLY: return new IteratorForward(context, var, data.extract()); case SOLID: return new IteratorForward(context, var, data.extract()); default: assert(true); } assert(false && "Unknown declaration"); return nullptr; } llvm::Value* IteratorForward::begin() { switch(sourceDecl.op) { case xreate::Operator::LIST: { sourceRawType = llvm::Type::getInt32Ty(llvm::getGlobalContext()); return llvm::ConstantInt::get(Type::getInt32Ty(llvm::getGlobalContext()), 0); }; case xreate::Operator::LIST_RANGE:{ assert(sourceDecl.operands.size()==2); llvm::Value* result = sourceUnit->process(sourceDecl.operands.at(0)); sourceRawType = result->getType(); return result; }; default: break; } if (linkedlist){ llvm::Value* result = sourceUnit->process(sourceDecl); sourceRawType = result->getType(); return result; } assert(false); } llvm::Value* IteratorForward::end(){ switch(sourceDecl.op) { case xreate::Operator::LIST: { size_t idLast = sourceDecl.operands.size() - 1; return ConstantInt::get(sourceRawType, idLast); } case xreate::Operator::LIST_RANGE: { assert(sourceDecl.operands.size() == 2); llvm::Value* valueEndOfRange = sourceUnit->process(sourceDecl.operands.at(1)); llvm::Value* valueConstOne = llvm::ConstantInt::get(llvm::Type::getInt32Ty(llvm::getGlobalContext()), 1); return llvm->builder.CreateAdd(valueEndOfRange, valueConstOne); }; default: break; } //return null pointer if (linkedlist){ return ConstantPointerNull::getNullValue(sourceRawType); } assert(false && "Unknown declaration"); return nullptr; } llvm::Value* IteratorForward::get(Value* index,const std::string& hintRetVar){ - const Expression& currentDecl = CodeScope::findDeclaration(current); + const Expression& currentDecl = CodeScope::getDeclaration(current); switch (currentDecl.op) { case xreate::Operator::LIST: { //TODO re check is it right scope(source) to compile currentDecl. Provide unittests. - llvm::Value* currentValue = sourceUnit->compileSymbol(current); + llvm::Value* currentValue = sourceUnit->processSymbol(current); return xreate::compilation::Advanced(context).compileArrayIndex(currentValue, std::vector{index}); }; case xreate::Operator::LIST_RANGE: { return index; }; case xreate::Operator::MAP: { assert(currentDecl.getOperands().size()==1); assert(currentDecl.bindings.size()); assert(currentDecl.blocks.size()); CodeScope* scopeLoop = currentDecl.blocks.front(); std::string varEl = currentDecl.bindings[0]; const Symbol& symbIn = Attachments::get(currentDecl.getOperands()[0]); auto it = std::unique_ptr(Iterator::create(context, symbIn)); Value* elIn = it->get(index, varEl); - compilation::CodeScopeUnit* unitLoop = function->getScopeUnit(scopeLoop); + compilation::AbstractCodeScopeUnit* unitLoop = function->getScopeUnit(scopeLoop); unitLoop->bindArg(elIn, std::move(varEl)); return unitLoop->compile(); } case xreate::Operator::NONE: { //TODO review iterator determination strategy for case of Expression::BINDING assert(currentDecl.__state==Expression::IDENT); - + const Symbol& symbIn = Attachments::get(currentDecl); auto it = std::unique_ptr(Iterator::create(context, symbIn)); return it->get(index); }; default: break; } if (linkedlist){ return index; } assert(false && "Unknown declaration"); return nullptr; } llvm::Value* IteratorForward::advance(Value* index, const std::string& hintRetVar){ switch(sourceDecl.op) { case xreate::Operator::LIST: case xreate::Operator::LIST_RANGE: return llvm->builder.CreateAdd(index, llvm::ConstantInt::get(llvm::Type::getInt32Ty(llvm::getGlobalContext()), 1), hintRetVar); default: break; } if (linkedlist){ - ExpandedType tySource = llvm->ast->expandType(CodeScope::findDeclaration(source).type); + ExpandedType tySource = llvm->ast->expandType(CodeScope::getDeclaration(source).type); assert(tySource->__operator == TypeOperator::ARRAY && "Linked list implementation has to have ARRAY type"); assert(tySource->__operands.size()); return xreate::compilation::Advanced(context).compileStructIndex(index, ExpandedType(TypeAnnotation(tySource->__operands.at(0))), linkedlist.fieldPointer); } assert(false && "Unknown declaration"); return nullptr; } //const ImplementationRec& implementation IteratorForward::IteratorForward(const compilation::Context& ctx, const xreate::Symbol& symbolContainer, const ImplementationRec& implementation) - : Iterator(), llvm(ctx.pass->man->llvm), __length(implementation.size) + : Iterator(), __length(implementation.size), llvm(ctx.pass->man->llvm) { - __container = ctx.function->getScopeUnit(symbolContainer.scope)->compileSymbol(symbolContainer); + __container = ctx.function->getScopeUnit(symbolContainer.scope)->processSymbol(symbolContainer); } llvm::Value* IteratorForward::begin(){ //0 return llvm::ConstantInt::get(llvm::Type::getInt32Ty(llvm::getGlobalContext()), 0); } llvm::Value* IteratorForward::end(){ //length return llvm::ConstantInt::get(llvm::Type::getInt32Ty(llvm::getGlobalContext()), __length); } llvm::Value* IteratorForward::get(llvm::Value* index,const std::string& hintRetVar){ //GEP[index]] llvm::Type* tyNum = llvm::Type::getInt32Ty(llvm::getGlobalContext()); llvm::Value* pResult = llvm->builder.CreateGEP(__container, ArrayRef(std::vector{ConstantInt::get(tyNum, 0), index})); return llvm->builder.CreateLoad(pResult, hintRetVar); } llvm::Value* IteratorForward::advance(llvm::Value* index, const std::string& hintRetVar){ //index + 1 llvm::Type* tyNum = llvm::Type::getInt32Ty(llvm::getGlobalContext()); return llvm->builder.CreateAdd(index, llvm::ConstantInt::get(tyNum, 1), hintRetVar); } diff --git a/cpp/src/compilation/containers.h b/cpp/src/compilation/containers.h index 222be75..71815a7 100644 --- a/cpp/src/compilation/containers.h +++ b/cpp/src/compilation/containers.h @@ -1,80 +1,80 @@ #ifndef CODEINSTRUCTIONS_H #define CODEINSTRUCTIONS_H #include "ast.h" #include "llvmlayer.h" #include "pass/compilepass.h" #include "compilation/advanced.h" #include "query/context.h" #include "query/containers.h" namespace xreate { namespace containers { using namespace llvm; class Iterator{ public : virtual llvm::Value* begin() =0; virtual llvm::Value* end() = 0; virtual llvm::Value* get(llvm::Value* index,const std::string& hintRetVar="") = 0; virtual llvm::Value* advance(llvm::Value* index, const std::string& hintRetVar="")=0; virtual ~Iterator(){}; static Iterator* create(xreate::compilation::Context context, const xreate::Symbol& var); }; template class IteratorForward; template<> class IteratorForward : public Iterator { private: LLVMLayer* llvm; const xreate::Symbol current; const Symbol source; const ImplementationLinkedList linkedlist; CodeScope* const sourceScope; //TODO initialize and mark as const (three fields) - compilation::CodeScopeUnit* sourceUnit; + compilation::AbstractCodeScopeUnit* sourceUnit; compilation::FunctionUnit* function; //TODO is used somewhere? const Expression& sourceDecl; compilation::Context context; llvm::Type* sourceRawType =nullptr; public: IteratorForward(const compilation::Context& ctx, const xreate::Symbol& s, const ImplementationRec& implementation) : llvm(ctx.pass->man->llvm), current(s), source(implementation.source), linkedlist(source), sourceScope(source.scope), - sourceUnit(new compilation::CodeScopeUnit(source.scope, ctx.function, ctx.pass)), - sourceDecl(CodeScope::findDeclaration(source)), + sourceUnit(ctx.function->getScopeUnit(source.scope)), + sourceDecl(CodeScope::getDeclaration(source)), context(ctx) {} llvm::Value* begin() override; llvm::Value* end() override; llvm::Value* get(llvm::Value* index,const std::string& hintRetVar="") override; llvm::Value* advance(llvm::Value* index, const std::string& hintRetVar="") override; }; template<> class IteratorForward: public Iterator{ size_t __length; llvm::Value* __container; LLVMLayer* llvm; public: IteratorForward(const compilation::Context& ctx, const xreate::Symbol& symbolContainer, const ImplementationRec& implementation); llvm::Value* begin() override; llvm::Value* end() override; llvm::Value* get(llvm::Value* index,const std::string& hintRetVar="") override; llvm::Value* advance(llvm::Value* index, const std::string& hintRetVar="") override; }; }} #endif //CODEINSTRUCTIONS_H diff --git a/cpp/src/compilation/scopedecorators.h b/cpp/src/compilation/scopedecorators.h new file mode 100644 index 0000000..1bc15da --- /dev/null +++ b/cpp/src/compilation/scopedecorators.h @@ -0,0 +1,120 @@ +/* + * File: scopedecorators.h + * Author: pgess + * + * Created on February 24, 2017, 11:35 AM + */ + +#ifndef SCOPEDECORATORS_H +#define SCOPEDECORATORS_H + +#include "ast.h" +#include "compilation/targetinterpretation.h" +#include "compilation/versions.h" + +namespace xreate { + +class CompilePass; + +namespace compilation { + +class AbstractCodeScopeUnit; +class FunctionUnit; + +template +class CachedScopeDecorator: public Parent{ + typedef CachedScopeDecorator SELF; + +public: + CachedScopeDecorator(CodeScope* codeScope, FunctionUnit* f, CompilePass* compilePass): Parent(codeScope, f, compilePass){} + + void reset(){ + __rawVars.clear(); + } + + void bindArg(llvm::Value* value, std::string&& alias) + { + //ensure existence of an alias + assert(Parent::scope->__identifiers.count(alias)); + + //memorize new value for an alias + ScopedSymbol id{Parent::scope->__identifiers.at(alias), VERSION_NONE}; + __rawVars[id] = value; + } + + void bindArg(llvm::Value* value, const ScopedSymbol& s) { + __rawVars[s] = value; + } + + llvm::Value* compile(const std::string& hintBlockDecl="") override{ + if (__rawVars.count(ScopedSymbol::RetSymbol)){ + return __rawVars[ScopedSymbol::RetSymbol]; + } + + return Parent::compile(hintBlockDecl); + } + + llvm::Value* + processSymbol(const Symbol& s, std::string hintRetVar) override{ + CodeScope* scope = s.scope; + SELF* self = dynamic_cast(Parent::function->getScopeUnit(scope)); + + if (self->__rawVars.count(s.identifier)){ + return self->__rawVars[s.identifier]; + } + + //compilation transformations could override symbol declarations. + Expression declaration = CodeScope::getDeclaration(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] = Parent::processSymbol(s, hintRetVar); + } + + void + overrideDeclaration(const Symbol binding, Expression&& declaration){ + SELF* self = dynamic_cast(Parent::function->getScopeUnit(binding.scope)); + + self->__declarationsOverriden.emplace(binding.identifier, std::move(declaration)); + } + +private: + std::unordered_map __declarationsOverriden; + std::unordered_map __rawVars; + +}; + +typedef CachedScopeDecorator< + InterpretationScopeDecorator< + VersionsScopeDecorator>> + + DefaultScopeUnit; + +} //end of compilation namespace + +struct CachedScopeDecoratorTag; +struct VersionsScopeDecoratorTag; + +template<> +struct DecoratorsDict{ + typedef compilation::CachedScopeDecorator< + compilation::InterpretationScopeDecorator< + compilation::VersionsScopeDecorator>> result; +}; + +template<> +struct DecoratorsDict{ + typedef compilation::VersionsScopeDecorator< + compilation::VersionsScopeDecorator> result; +}; + +} //end of xreate + +#endif /* SCOPEDECORATORS_H */ + diff --git a/cpp/src/compilation/targetinterpretation.cpp b/cpp/src/compilation/targetinterpretation.cpp index 2825235..2969498 100644 --- a/cpp/src/compilation/targetinterpretation.cpp +++ b/cpp/src/compilation/targetinterpretation.cpp @@ -1,443 +1,432 @@ /* * 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 "compilation/scopedecorators.h" + #include #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); + Symbol symbEl{ScopedSymbol{scopeBody->__identifiers.at(nameEl), VERSION_NONE}, scopeBody}; const std::string& idAccum = expression.bindings[1]; llvm::Value* rawAccum = context.scope->process(expression.getOperands()[1]); - compilation::CodeScopeUnit* unitBody = context.function->getScopeUnit(scopeBody); + auto unitBody = Decorators::getInterface(context.function->getScopeUnit(scopeBody)); InterpretationScope* intrBody = function->getScope(scopeBody); const std::vector elementsInput= exprInput.getOperands(); for (size_t i=0; ireset(); intrBody->overrideBinding(exprElement, nameEl); - unitBody->overrideDeclaration(symbolEl, move(exprElement)); + unitBody->overrideDeclaration(symbEl, 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; + AbstractCodeScopeUnit* 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); + return context.scope->process(result); } Expression InterpretationScope::process(const Expression& expression){ switch (expression.__state){ - case Expression::VARIANT: case Expression::INVALID: assert(false); + case Expression::VARIANT: case Expression::NUMBER: case Expression::STRING: return expression; case Expression::IDENT:{ Symbol s = Attachments::get(expression); 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); InterpretationFunction* 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[1]); const Expression& exprData = process(expression.operands[0]); 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; ioverrideBinding(exprInput.getOperands()[i], argEl); body->overrideBinding(accum, argAccum); accum = body->processScope(); } return accum; } // case Operator::MAP: { // break; // } default: break; } return expression; } InterpretationFunction* TargetInterpretation::getFunction(FunctionUnit* unit){ if (__dictFunctionsByUnit.count(unit)) { return __dictFunctionsByUnit.at(unit); } InterpretationFunction* f = new InterpretationFunction(unit->function, this); __dictFunctionsByUnit.emplace(unit, f); assert(__functions.emplace(unit->function.id(), f).second); return f; } PIFunction* TargetInterpretation::getFunction(PIFSignature&& sig){ auto f = __pifunctions.find(sig); if (f != __pifunctions.end()){ return f->second; } PIFunction* result = new PIFunction(PIFSignature(sig), __pifunctions.size(), this); __pifunctions.emplace(move(sig), result); assert(__dictFunctionsByUnit.emplace(result->functionUnit, result).second); return result; } InterpretationScope* TargetInterpretation::transformContext(const Context& c){ 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, {ANY, NONE}); - - return (data.resolution == INTR_ONLY || data.op != InterpretationOperator::NONE); -} - InterpretationFunction::InterpretationFunction(const ManagedFnPtr& function, Target* target) : Function(function, target) {} Expression InterpretationFunction::process(const std::vector& args){ InterpretationScope* body = getScope(__function->__entry); for(size_t i=0, size = args.size(); ioverrideBinding(args.at(i), string(body->scope->__bindings.at(i))); } return body->processScope(); } // Partial function interpretation typedef BasicFunctionDecorator PIFunctionUnitParent; class PIFunctionUnit: public PIFunctionUnitParent{ public: PIFunctionUnit(ManagedFnPtr f, std::set&& arguments, size_t id, CompilePass* p) : PIFunctionUnitParent(f, p), argumentsActual(move(arguments)), __id(id) {} protected: 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: argumentsActual){ - Symbol arg = entry->findSymbol(entry->__bindings[no]); + VNameId argId = entry->__identifiers.at(entry->__bindings.at(no)); + ScopedSymbol arg{argId, VERSION_NONE}; - signature.push_back(llvm->toLLVMType(ast->expandType(entry->__declarations[arg.identifier].type))); + signature.push_back(llvm->toLLVMType(ast->expandType(entry->__declarations.at(arg).type))); } return signature; } llvm::Function::arg_iterator prepareBindings(){ CodeScope* entry = PIFunctionUnitParent::function->__entry; - CodeScopeUnit* entryCompilation = PIFunctionUnitParent::getScopeUnit(entry); + AbstractCodeScopeUnit* entryCompilation = PIFunctionUnitParent::getScopeUnit(entry); llvm::Function::arg_iterator fargsI = PIFunctionUnitParent::raw->arg_begin(); for(size_t no: argumentsActual){ - Symbol arg = entry->findSymbol(entry->__bindings[no]); + ScopedSymbol arg{entry->__identifiers.at(entry->__bindings.at(no)), VERSION_NONE}; - entryCompilation->__rawVars[arg.identifier] = &*fargsI; - fargsI->setName(entry->__bindings[no]); + entryCompilation->bindArg(&*fargsI, arg); + fargsI->setName(entry->__bindings.at(no)); ++fargsI; } return fargsI; } virtual std::string prepareName(){ return PIFunctionUnitParent::prepareName() + "_" + std::to_string(__id); } private: std::set argumentsActual; size_t __id; }; PIFunction::PIFunction(PIFSignature&& sig, size_t id, TargetInterpretation* target) : InterpretationFunction(sig.declaration, target), signatureInstance(move(sig)) { 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(); + auto entryUnit = Decorators::getInterface<>(functionUnit->getEntry()); InterpretationScope* entryIntrp = InterpretationFunction::getScope(entry); for(size_t no=0, sigNo=0, size = entry->__bindings.size(); no < size; ++no){ if (functionData.signature.at(no) == INTR_ONLY){ entryIntrp->overrideBinding(signatureInstance.bindings[sigNo], entry->__bindings[no]); - entryUnit->overrideDeclaration(entry->findSymbol(entry->__bindings[no]), Expression(signatureInstance.bindings[sigNo])); + + VNameId argId = entry->__identifiers.at(entry->__bindings[no]); + Symbol argSymbol{ScopedSymbol{argId, VERSION_NONE}, entry}; + entryUnit->overrideDeclaration(argSymbol, Expression(signatureInstance.bindings[sigNo])); ++sigNo; } } } 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; } }} \ No newline at end of file diff --git a/cpp/src/compilation/targetinterpretation.h b/cpp/src/compilation/targetinterpretation.h index 0ef32e7..7b7acdd 100644 --- a/cpp/src/compilation/targetinterpretation.h +++ b/cpp/src/compilation/targetinterpretation.h @@ -1,116 +1,134 @@ /* * 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 "pass/compilepass.h" #include "compilation/targets.h" -#include "transformations.h" #include "pass/interpretationpass.h" namespace xreate{ namespace compilation { class TargetInterpretation; class InterpretationScope; class InterpretationFunction; template <> struct TargetInfo { typedef Expression Result; typedef InterpretationScope Scope; typedef InterpretationFunction 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); CodeScope* processOperatorIf(const Expression& expression); CodeScope* processOperatorSwitch(const Expression& expression); }; class InterpretationFunction: public Function{ public: InterpretationFunction(const ManagedFnPtr& function, Target* target); Expression process(const std::vector& args); }; /* * Partially interpreted function signature */ struct PIFSignature{ ManagedFnPtr declaration; std::vector bindings; }; class PIFunctionUnit; class PIFunction: public InterpretationFunction{ public: PIFunctionUnit* functionUnit; PIFSignature signatureInstance; PIFunction(PIFSignature&& sig, size_t id, TargetInterpretation* target); llvm::Function* compile(); }; bool operator<(const PIFSignature& lhs, PIFunction* const rhs); bool operator<(PIFunction* const lhs, const PIFSignature& rhs); -class TargetInterpretation: public Target, public Transformer{ +class TargetInterpretation: public Target{ public: TargetInterpretation(AST* root, CompilePass* passCompilation): Target(root), pass(passCompilation){} - //transformer: -public: - virtual llvm::Value* transform(const Expression& expression, llvm::Value* raw, const Context& ctx) override; - virtual Expression transform(const Expression& expression, const Context& ctx) override; - virtual bool isAcceptable(const Expression& expression) override; - //target: public: InterpretationFunction* getFunction(FunctionUnit* unit); PIFunction* getFunction(PIFSignature&& sig); private: std::map __pifunctions; std::map __dictFunctionsByUnit; //self: public: CompilePass* pass; llvm::Value* compile(const Expression& expression, const Context& ctx); private: InterpretationScope* transformContext(const Context& c); }; +template +class InterpretationScopeDecorator: public Parent{ +public: + InterpretationScopeDecorator(CodeScope* codeScope, FunctionUnit* f, CompilePass* compilePass): Parent(codeScope, f, compilePass){} + + virtual llvm::Value* process(const Expression& expr, const std::string& hintVarDecl){ + const InterpretationData& data = Attachments::get(expr, {ANY, NONE}); + bool flagInterpretationEligible = (data.resolution == INTR_ONLY || data.op != InterpretationOperator::NONE); + + if (flagInterpretationEligible){ + Context ctx{this, this->function, this->pass}; + return Parent::pass->targetInterpretation->compile(expr, ctx); + } + + return Parent::process(expr, hintVarDecl); + } +}; + + + +} //end of compilation + +struct InterpretationScopeDecoratorTag; + +} //end of xreate +#endif /* TARGETSTATIC_H */ -}} -#endif /* TARGETSTATIC_H */ \ No newline at end of file +//transformers: +// template<> +// struct TransformerInfo { +// static const int id = 1; +// }; \ No newline at end of file diff --git a/cpp/src/compilation/targets.h b/cpp/src/compilation/targets.h index fbdf860..a871d44 100644 --- a/cpp/src/compilation/targets.h +++ b/cpp/src/compilation/targets.h @@ -1,161 +1,161 @@ /* * 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); + const Expression& declaration = CodeScope::getDeclaration(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->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 overrideBinding(typename TargetInfo::Result arg, const std::string& name){ assert(scope->__identifiers.count(name)); - ScopedSymbol id = scope->__identifiers.at(name); + ScopedSymbol id{scope->__identifiers.at(name), VERSION_NONE}; __bindings[id] = arg; //reset the result if any: raw.reset(); } protected: 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) {} virtual ~Function(){}; typename TargetInfo::Scope* getScope(CodeScope* scope){ if (!__scopes.count(scope)){ typename TargetInfo::Scope* unit = new typename TargetInfo::Scope(scope, this); __scopes.emplace(scope, std::unique_ptr::Scope>(unit)); } return __scopes.at(scope).get(); } virtual Result process(const std::vector& args)=0; 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, unit); return unit; } return __functions.at(id); } AST* ast; virtual ~Target(){ for (const auto& entry: __functions){ delete entry.second; } } protected: std::map __functions; }; }} #endif /* TARGETABSTRACT_H */ \ No newline at end of file diff --git a/cpp/src/compilation/transformations.cpp b/cpp/src/compilation/transformations.cpp deleted file mode 100644 index e179651..0000000 --- a/cpp/src/compilation/transformations.cpp +++ /dev/null @@ -1,144 +0,0 @@ -/* - * File: Transformations.cpp - * Author: pgess - * - * Created on June 18, 2016, 6:23 PM - */ - -#include "compilation/transformations.h" -#include "pass/compilepass.h" -#include "llvmlayer.h" -#include - -using namespace llvm; - -namespace xreate { namespace compilation { - -Transformations::Transformations(CompilePass* passCompilation): pass(passCompilation) { - Attachments::init(); -} - -void -Transformations::subscribe(const std::string& annotation, int handler){ - __subscriptions.emplace(annotation, handler); -} - -bool -Transformations::isAcceptable(const Expression& expression){ - //check subscription based on expression attachments - if (Attachments::get(expression, {false, 0}).flagSubscribed){ - return true; - } - - //subscription based on expression annotations; - if (expression.tags.size() == 0) return false; - - for (auto tag: expression.tags) { - if (__subscriptions.count(tag.first)){ - return true; - } - } - - return false; -} - -Expression -Transformations::transform(const Expression& expression, const Context& ctx){ - Expression result = expression; - - for (auto handler: getAppropriateTransformers(expression)){ - result = handler->transform(result, ctx); - } - - return result; -} - -llvm::Value* -Transformations::transform(const Expression& expression, llvm::Value* raw, const Context& ctx){ - for (auto handler: getAppropriateTransformers(expression)){ - raw = handler->transform(expression, raw, ctx); - } - - return raw; -} - -std::list -Transformations::getAppropriateTransformers(const Expression& expression){ - - std::list result; - - for (auto tag: expression.tags) { - if (__subscriptions.count(tag.first)){ - auto handlers = __subscriptions.equal_range(tag.first); - - for (auto handlerIt=handlers.first; handlerIt!= handlers.second; ++handlerIt){ - Transformer* handler = __transformers[handlerIt->second]; - - if (handler->isAcceptable(expression)){ - result.push_back(handler); - } - } - } - } - - auto subscriberInternal = Attachments::get(expression, {false, 0}); - if (subscriberInternal.flagSubscribed){ - result.push_back(__transformers[subscriberInternal.subscriberId]); - } - - return result; -} - -TransformerSaturation::TransformerSaturation(Transformations* man) - : __man(man) { - - man->subscribe("break", TransformerInfo::id); -} - -bool -TransformerSaturation::isAcceptable(const Expression& expression){ - return true; -} - -bool -TransformerSaturation::exists() const{ - return __block != nullptr; -} - -llvm::Value* -TransformerSaturation::transform(const Expression& expression, llvm::Value* raw, const Context& ctx){ - __block = __man->pass->man->llvm->builder.GetInsertBlock(); - - return raw; -} - -llvm::BasicBlock* -TransformerSaturation::getBlock() const{ - return __block; -} - -void -TransformerSaturation::inject(llvm::BasicBlock* blockAllocation, llvm::BasicBlock* blockExit, compilation::Context context){ - llvm::Type* tyInt1 = llvm::Type::getInt1Ty(llvm::getGlobalContext()); - llvm::Value* valueConstOne = llvm::ConstantInt::get(tyInt1, 1); - llvm::Value* valueConstFalse = llvm::ConstantInt::get(tyInt1, 0); - - //allocation of saturation flag - IRBuilder<> builderAlloca(blockAllocation, blockAllocation->getFirstInsertionPt()); - llvm::Value* flagSaturation = builderAlloca.CreateAlloca(tyInt1, valueConstOne, "flagSaturation"); - builderAlloca.CreateStore(valueConstFalse, flagSaturation, true); - - //set up saturation flag - llvm::BasicBlock* blockSaturation = __block; - IRBuilder<> builderSaturation(blockSaturation, blockSaturation->getFirstInsertionPt()); - builderSaturation.CreateStore(valueConstOne, flagSaturation, true); - - //check saturation flag: - //TODO remove blockContinue, receive from caller block to continue. - llvm::BasicBlock *blockContinue = llvm::BasicBlock::Create(llvm::getGlobalContext(), "continue", context.function->raw); - context.pass->man->llvm->builder.CreateCondBr(context.pass->man->llvm->builder.CreateLoad(flagSaturation), blockExit, blockContinue); - - context.pass->man->llvm->builder.SetInsertPoint(blockContinue); -} - -}} \ No newline at end of file diff --git a/cpp/src/compilation/transformations.h b/cpp/src/compilation/transformations.h deleted file mode 100644 index daec0bf..0000000 --- a/cpp/src/compilation/transformations.h +++ /dev/null @@ -1,119 +0,0 @@ -/* - * File: Transformations.h - * Author: pgess - * - * Created on June 18, 2016, 6:23 PM - */ - -#ifndef TRANSFORMATIONS_H -#define TRANSFORMATIONS_H - -#include "ast.h" -#include "pass/compilepass.h" -#include "attachments.h" - -namespace llvm { - class BasicBlock; -} - -namespace xreate { namespace compilation { - - class Transformer{ - public: - virtual llvm::Value* transform(const Expression& expression, llvm::Value* raw, const Context& ctx)=0; - virtual Expression transform(const Expression& expression, const Context& ctx){return expression;} - virtual bool isAcceptable(const Expression& expression)=0; - - virtual ~Transformer(){}; - }; - - class TransformerSaturation: public Transformer{ - public: - llvm::Value* transform(const Expression& expression, llvm::Value* raw, const Context& ctx); - bool isAcceptable(const Expression& expression); - - TransformerSaturation(Transformations*); - llvm::BasicBlock* getBlock() const; - bool exists() const; - void inject(llvm::BasicBlock* blockAllocation, llvm::BasicBlock* blockExit, compilation::Context context); - - private: - llvm::BasicBlock* __block = nullptr; - Transformations* __man; - }; - - template - struct TransformerInfo { - //static const int id = 1; (next vacant id) - }; - - template <> - struct TransformerInfo { - static const int id = 0; - }; - - class Transformations; - - struct SubscriberInfo{ - bool flagSubscribed; - int subscriberId; - }; - - class Transformations: public Transformer { - public: - xreate::CompilePass* pass; - - bool isAcceptable(const Expression& expression); - llvm::Value* transform(const Expression& expression, llvm::Value* raw, const Context& ctx) override; - Expression transform(const Expression& expression, const Context& ctx) override; - - Transformations(CompilePass*); - void subscribe(const std::string& annotation, int handler); - - template - void registerTransformer(TransformerType* t){ - const int id = TransformerInfo::id; - - __transformers[id] = t; - } - - template - static void subscribe(const Holder& holder){ - //assert(! Attachments::exists()); - - const int id = TransformerInfo::id; - - if (Attachments::exists(holder)){ - const int idOld = Attachments::get(holder).subscriberId; - assert(idOld == id); - return; - } - - Attachments::put(holder, {true, id}); - } - - template - TransformerType* get(){ - const int id = TransformerInfo::id; - return static_cast(__transformers.at(id)); - } - - private: - std::map __transformers; - std::multimap __subscriptions; - - std::list getAppropriateTransformers(const Expression& expression); - }; -}} - -namespace xreate { - template<> - struct AttachmentsDict - { - typedef xreate::compilation::SubscriberInfo Data; - static const unsigned int key = 4; - }; -} - -#endif /* TRANSFORMATIONS_H */ - diff --git a/cpp/src/compilation/versions.cpp b/cpp/src/compilation/versions.cpp deleted file mode 100644 index e69c7ec..0000000 --- a/cpp/src/compilation/versions.cpp +++ /dev/null @@ -1,56 +0,0 @@ - -/* - * versions.cpp - * - * Author: pgess - * Created on January 21, 2017, 1:24 PM - */ - -typename std::list VersionInferiorsList; - -template -class VersionsScopeDecorator: public Parent{ - llvm::Value* - compileSymbol(const Symbol& s, std::string hintSymbol=""){ - if (Attachments::exists(s)){ - const VersionInferiorsList& symbolsInf= Attachments::get(s); - - for (cont Symbol& inf: symbolsInf){ - Parent::compileSymbol(inf); - } - } - - return Parent::compileSymbol(s, hintSymbol); - } - -llvm::Value* -process(const Expression& expr, const std::string& hintVarDecl){ - case Operator::CALL_INTRINSIC: { - enum INRINSIC{INIT, COPY}; - const llvm::IntegerType* tyInt = llvm::Type::getInt32Ty(llvm::getGlobalContext()); - const llvm::ConstantInt* constOne = llvm::ConstantInt::get(tyInt, 1, false); - const ExpandedType& typSymbol = pass->man->root->expandType(expr.type); - - INTRINSIC op = (INTRINSIC) expr.getValueDouble(); - - switch (op){ - case INIT: { - llvm::Type* typSymbolRaw = l.toLLVMType(typSymbol); - llvm::Value* storage = l.builder.CreateAlloca(typSymbolRaw, constOne, hintVarDecl); - - return storage; - } - - case COPY: { - llvm::Type* typSymbolRaw = l.toLLVMType(typSymbol); - llvm::value* valueOriginal = process(expr.getOperands()[0], hintVarDecl); - llvm::Value* storage = l.builder.CreateAlloca(typSymbolRaw, constOne, hintVarDecl); - llvm::Value* valueCopy = l.builder.CreateStore(valueOriginal, storage); - - return valueCopy; - } - } - return; - } -} -}; \ No newline at end of file diff --git a/cpp/src/compilation/versions.h b/cpp/src/compilation/versions.h new file mode 100644 index 0000000..e1f9b0d --- /dev/null +++ b/cpp/src/compilation/versions.h @@ -0,0 +1,127 @@ + +/* + * versions.cpp + * + * Author: pgess + * Created on January 21, 2017, 1:24 PM + */ + +#include "pass/versionspass.h" +#include "pass/compilepass.h" + +namespace xreate { + +class CompilePass; + +namespace compilation { + +class AbstractCodeScopeUnit; +class FunctionUnit; + +template +class VersionsScopeDecorator: public Parent{ + typedef VersionsScopeDecorator SELF; + +public: + VersionsScopeDecorator(CodeScope* codeScope, FunctionUnit* f, CompilePass* compilePass): Parent(codeScope, f, compilePass){} + + virtual llvm::Value* processSymbol(const Symbol& s, std::string hintSymbol=""){ + if (Attachments::exists(s)){ + const std::list dependencies = Attachments::get(s); + + for(const Symbol& symbolDependent: dependencies){ + processSymbol(symbolDependent); + } + } + + llvm::Value* result = Parent::processSymbol(s, hintSymbol); + + if (s.identifier.version == VERSION_INIT){ + llvm::Value* storage = SELF::processIntrinsicInit(result->getType(), hintSymbol); + setSymbolStorage(s, storage); + + processIntrinsicCopy(result, storage); + return AbstractCodeScopeUnit::pass->man->llvm->builder.CreateLoad(storage); + + } else if (s.identifier.version != VERSION_NONE){ + Symbol symbolInitVersion = getSymbolInitVersion(s); + + llvm::Value* storage = getSymbolStorage(symbolInitVersion); + processIntrinsicCopy(result, storage); + + return AbstractCodeScopeUnit::pass->man->llvm->builder.CreateLoad(storage); + } + + return result; + } + + llvm::Value* + processIntrinsicInit(llvm::Type* typeStorage, const std::string& hintVarDecl=""){ + llvm::IntegerType* tyInt = llvm::Type::getInt32Ty(llvm::getGlobalContext()); + llvm::ConstantInt* constOne = llvm::ConstantInt::get(tyInt, 1, false); + + return AbstractCodeScopeUnit::pass->man->llvm->builder.CreateAlloca(typeStorage, constOne, hintVarDecl); + } + + void + processIntrinsicCopy(llvm::Value* value, llvm::Value* storage){ + AbstractCodeScopeUnit::pass->man->llvm->builder.CreateStore(value, storage); + } + +private: + std::map __symbolStorage; + + static Symbol + getSymbolInitVersion(const Symbol& s){ + return Symbol{ScopedSymbol{s.identifier.id, VERSION_INIT}, s.scope}; + } + + llvm::Value* + getSymbolStorage(const Symbol& s){ + return __symbolStorage.at(s); + } + + void setSymbolStorage(const Symbol& s, llvm::Value* storage){ + __symbolStorage[s] = storage; + } + +}; +} //end of compilation namespace +} //end of xreate namespace + + +// llvm::Value* +// processIntrinsicInitAndCopy(){ +// +// } + +//llvm::Value* +//process(const Expression& expr, const std::string& hintVarDecl){ +// case Operator::CALL_INTRINSIC: { +// enum INRINSIC{INIT, COPY}; +// +// const ExpandedType& typSymbol = pass->man->root->expandType(expr.type); +// +// INTRINSIC op = (INTRINSIC) expr.getValueDouble(); +// +// switch (op){ +// case INIT: { +// llvm::Type* typSymbolRaw = l.toLLVMType(typSymbol); +// +// +// return storage; +// } +// +// case COPY: { +// llvm::Type* typSymbolRaw = l.toLLVMType(typSymbol); +// llvm::value* valueOriginal = process(expr.getOperands()[0], hintVarDecl); +// llvm::Value* storage = l.builder.CreateAlloca(typSymbolRaw, constOne, hintVarDecl); +// llvm::Value* valueCopy = l.builder.CreateStore(valueOriginal, storage); +// +// return valueCopy; +// } +// } +// return; +// } +//} +//}; \ No newline at end of file diff --git a/cpp/src/pass/abstractpass.cpp b/cpp/src/pass/abstractpass.cpp index 057805a..ca6190a 100644 --- a/cpp/src/pass/abstractpass.cpp +++ b/cpp/src/pass/abstractpass.cpp @@ -1,56 +1,58 @@ #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 Symbol& symbol, PassContext context) +AbstractPass::processSymbol(const Symbol& symbol, PassContext context, const std::string& hintSymbol) { if (__visitedSymbols.isCached(symbol)) return; __visitedSymbols.setCachedValue(symbol); - const Expression& declaration = CodeScope::findDeclaration(symbol); + const Expression& declaration = CodeScope::getDeclaration(symbol); if (declaration.isDefined()){ PassContext context2 = context.updateScope(symbol.scope); - process(declaration, context2, ident); + process(declaration, context2, hintSymbol); } } template<> void -AbstractPass::process(const Expression& expression, PassContext context, const std::string& varDecl=""){ +AbstractPass::process(const Expression& expression, PassContext context, const std::string& varDecl){ if (expression.__state == Expression::COMPOUND){ for (const Expression &op: expression.getOperands()) { process(op, context); } for (CodeScope* scope: expression.blocks) { process(scope, context); } if (expression.op == Operator::CALL){ - return processExpressionCall(expression, context); + processExpressionCall(expression, context); } return; } - - assert(false); + if (expression.__state == Expression::IDENT){ + assert(context.scope); + processSymbol(Attachments::get(expression), context, expression.getValueString()); + } } } \ No newline at end of file diff --git a/cpp/src/pass/abstractpass.h b/cpp/src/pass/abstractpass.h index 61ca873..dfefc06 100644 --- a/cpp/src/pass/abstractpass.h +++ b/cpp/src/pass/abstractpass.h @@ -1,190 +1,194 @@ #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 updateScope(CodeScope* scopeNew) { PassContext context2{*this}; context2.scope = scopeNew; - return std::move(context2); + return 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)[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 Symbol& symbol, PassContext context, std::string hintSymbol=""){ - 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(); +template +class AbstractPass: public AbstractPassBase { + + SymbolCache __visitedSymbols; + +protected: + virtual Output processSymbol(const Symbol& symbol, PassContext context, const std::string& hintSymbol=""){ + if (__visitedSymbols.isCached(symbol)) + return __visitedSymbols.getCachedValue(symbol); + + + const Expression& declaration = CodeScope::getDeclaration(symbol); + if (declaration.isDefined()){ + PassContext context2 = context.updateScope(symbol.scope); + + Output&& result = process(declaration, context2, hintSymbol); + return __visitedSymbols.setCachedValue(symbol, std::move(result)); } - - Output processExpressionCall(const Expression& expression, PassContext context){ - const std::string &calleeName = expression.getValueString(); - std::list callees = man->root->getFunctionVariants(calleeName); - if (callees.size() == 1 && callees.front()){ - return processFnCall(callees.front(), context); - - } else { - for (const ManagedFnPtr& callee: callees){ - processFnCallUncertain(callee, context); - } - - return defaultValue(); + + return defaultValue(); + } + + Output processExpressionCall(const Expression& expression, PassContext context){ + const std::string &calleeName = expression.getValueString(); + std::list callees = man->root->getFunctionVariants(calleeName); + if (callees.size() == 1 && callees.front()){ + return processFnCall(callees.front(), context); + + } else { + for (const ManagedFnPtr& callee: callees){ + processFnCallUncertain(callee, context); } - } - - SymbolCache& getSymbolCache(){ - return __visitedSymbols; - } - - - - public: - AbstractPass(PassManager* manager) - : AbstractPassBase(manager){} - - virtual Output processFnCall(ManagedFnPtr function, PassContext context){ + return defaultValue(); } + } - virtual void processFnCallUncertain(ManagedFnPtr function, PassContext context) - {} + SymbolCache& getSymbolCache(){ + return __visitedSymbols; + } - virtual void process(ManagedRulePtr rule) - {} - virtual Output process(ManagedFnPtr function) - { - PassContext context; - context.function = function; - return process(function->getEntryScope(), context); - } +public: + AbstractPass(PassManager* manager) + : AbstractPassBase(manager){} - virtual Output process(CodeScope* scope, PassContext context, const std::string& hintBlockDecl=""){ - context.scope = scope; - - return processSymbol(Symbol{ScopedSymbol::RetSymbol, scope}, context); - } + virtual Output processFnCall(ManagedFnPtr function, PassContext context){ + return defaultValue(); + } - virtual Output process(const Expression& expression, PassContext context, const std::string& varDecl=""){ - if (expression.__state == Expression::IDENT){ - assert(context.scope); - return processSymbol(Attachments::get(expression), context, expression.getValueString()); - } - - assert(false); - return defaultValue(); + virtual void processFnCallUncertain(ManagedFnPtr function, PassContext context) + {} + + virtual void process(ManagedRulePtr rule) + {} + + virtual Output process(ManagedFnPtr function) + { + PassContext context; + context.function = function; + + return process(function->getEntryScope(), context); + } + + virtual Output process(CodeScope* scope, PassContext context, const std::string& hintBlockDecl=""){ + context.scope = scope; + + return processSymbol(Symbol{ScopedSymbol::RetSymbol, scope}, context); + } + + virtual Output process(const Expression& expression, PassContext context, const std::string& varDecl=""){ + if (expression.__state == Expression::IDENT){ + assert(context.scope); + return processSymbol(Attachments::get(expression), context, expression.getValueString()); } - void run() { - ManagedRulePtr rule = man->root->begin(); - while (rule.isValid()) { - process(rule); - ++rule; - } + assert(false); + return defaultValue(); + } - ManagedFnPtr f = man->root->begin(); - while (f.isValid()) { - process(f); - ++f; - } + void run() { + ManagedRulePtr rule = man->root->begin(); + while (rule.isValid()) { + process(rule); + ++rule; } - - private: - template<> - void - AbstractPass::processSymbol(const Symbol& symbol, PassContext context); - -} + ManagedFnPtr f = man->root->begin(); + while (f.isValid()) { + process(f); + ++f; + } + } + +}; + +template<> +void +AbstractPass::processSymbol(const Symbol& symbol, PassContext context, const std::string& hintSymbol); + +template<> +void +AbstractPass::process(const Expression& expression, PassContext context, const std::string& hintSymbol); + +} #endif //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 65cde19..35e3c50 100644 --- a/cpp/src/pass/adhocpass.cpp +++ b/cpp/src/pass/adhocpass.cpp @@ -1,81 +1,95 @@ /* * adhoc.cpp * * Created on: Nov 28, 2015 * Author: pgess */ #include "pass/adhocpass.h" #include "query/context.h" namespace xreate { - AdhocScheme* - AdhocPass::determineForScope(CodeScope* entry){ - const ScopePacked scopeId = man->clasp->pack(entry); - const Domain& domain = queryContext->getContext(scopeId); - AdhocScheme* scheme = nullptr; - - for (const Expression& context: domain){ - if (context.__state != Expression::IDENT) continue; - - if (__schemes.count(context.getValueString())){ - assert(!scheme && "ambiguous context"); - scheme = __schemes.at(context.getValueString()); - } - } - - assert(scheme && "Appropriate context not found"); - return scheme; - } - - const TypeAnnotation& - AdhocScheme::getResultType(){ - return __resultType; - } - - CodeScope* - AdhocScheme::getImplementationForCommand(const std::string& comm) { - assert(__commands.count(comm) && "Adhoc not defined"); - return __commands.at(comm); - } - - AdhocScheme::AdhocScheme(const Expression& scheme): - __resultType(scheme.type), __context(scheme.getValueString()) { - - Expression cases = scheme.getOperands()[0]; - for (const Expression& exprCase: cases.getOperands()){ - CodeScope* blockComm = exprCase.blocks.front(); - std::string nameCase = blockComm->getBody().operands[0].getValueString(); - - CodeScope* blockImpl = *(++exprCase.blocks.begin()); - __commands.emplace(nameCase, blockImpl); - } - } - - const std::string& - AdhocScheme::getContext(){ - return __context; - } - - /* - void - AdhocPass::process(const Expression& expression, PassContext context, const std::string& varDecl=""){ - if (expression == Exp) - } - */ - - void - AdhocPass::run(){ - queryContext = reinterpret_cast(man->clasp->registerQuery(new ContextQuery(), QueryId::ContextQuery)); - - auto range = man->root->__interfacesData.equal_range(ASTInterface::Adhoc); - for (auto i=range.first; i!= range.second; ++i){ - AdhocScheme* scheme = new AdhocScheme(i->second); - __schemes.emplace(scheme->getContext(), scheme); - } - } + +AdhocExpression::AdhocExpression(): Expression(Operator::ADHOC, {}) +{} + +AdhocExpression::AdhocExpression(const Expression& base): Expression(base) +{} + +void +AdhocExpression::setCommand(const Expression& comm){ + this->addTags({Expression(Operator::CALL, {Atom("adhoc"), comm})}); +} + +Expression +AdhocExpression::getCommand() const{ + assert(this->tags.count("adhoc")); + return this->tags.at("adhoc").getOperands().at(0); +} + +AdhocScheme* +AdhocPass::findAssotiatedScheme(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 && "Can't determine relevant scheme, ambiguous context"); + scheme = __schemes.at(context.getValueString()); + } + } + + assert(scheme && "Context doesn't define any ad hoc scheme"); + return scheme; +} + +const TypeAnnotation& +AdhocScheme::getResultType(){ + return __resultType; +} + +CodeScope* +AdhocScheme::getCommandImplementation(const Expression& comm) { + assert(comm.__state == Expression::IDENT); + + const std::string commSerialized = comm.getValueString(); + assert(__commands.count(commSerialized) && "Command isn't defined for a selected scheme"); + return __commands.at(commSerialized); +} + +AdhocScheme::AdhocScheme(const Expression& scheme): + __resultType(scheme.type), __name(scheme.getValueString()) { + + Expression exprCasesList = scheme.getOperands()[0]; + for (const Expression& exprSingleCase: exprCasesList.getOperands()){ + std::string command = exprSingleCase.tags.begin()->second.getValueString(); + + CodeScope* blockImpl = *(exprSingleCase.blocks.begin()); + __commands.emplace(command, blockImpl); + } +} + +const std::string& +AdhocScheme::getName(){ + return __name; +} + +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->getName(), scheme); + } +} + } diff --git a/cpp/src/pass/adhocpass.h b/cpp/src/pass/adhocpass.h index 45877ad..561ebfa 100644 --- a/cpp/src/pass/adhocpass.h +++ b/cpp/src/pass/adhocpass.h @@ -1,50 +1,59 @@ /* * adhoc.h * * Created on: Nov 28, 2015 * Author: pgess */ //SECTIONTAG adhoc pass #ifndef SRC_INSTRUCTIONS_ADHOC_H_ #define SRC_INSTRUCTIONS_ADHOC_H_ #include "abstractpass.h" -#ifndef FRIEND_ADHOC_UNITTESTS - #define FRIEND_ADHOC_UNITTESTS +#ifndef FRIENDS_ADHOC + #define FRIENDS_ADHOC #endif namespace xreate { - class ContextQuery; +class ContextQuery; + +class AdhocScheme { +public: + AdhocScheme(const Expression& scheme); + CodeScope* getCommandImplementation(const Expression& comm); + const TypeAnnotation& getResultType(); + const std::string& getName(); + +private: + TypeAnnotation __resultType; + std::string __name; + std::map __commands; +}; + +class AdhocExpression: public Expression{ +public: + AdhocExpression(); + AdhocExpression(const Expression& base); + + void setCommand(const Expression& comm); + Expression getCommand() const; +}; + +class AdhocPass: public AbstractPass { + FRIENDS_ADHOC + +public: + AdhocPass(PassManager* manager): AbstractPass(manager) {} + void run() override; + + AdhocScheme* findAssotiatedScheme(CodeScope* entry); + +private: + std::map __schemes; + ContextQuery* queryContext; +}; - class AdhocScheme { - public: - AdhocScheme(const Expression& scheme); - CodeScope* getImplementationForCommand(const std::string& comm); - const TypeAnnotation& getResultType(); - const std::string& getContext(); - - private: - TypeAnnotation __resultType; - std::string __context; - std::map __commands; - }; - - class AdhocPass: public AbstractPass { - FRIEND_ADHOC_UNITTESTS - - public: - AdhocPass(PassManager* manager): AbstractPass(manager) {} - AdhocScheme* determineForScope(CodeScope* entry); - - // virtual void process(const Expression& expression, PassContext context, const std::string& varDecl=""); - void run() override; - - private: - std::map __schemes; - ContextQuery* queryContext; - }; } #endif /* SRC_INSTRUCTIONS_ADHOC_H_ */ diff --git a/cpp/src/pass/cfapass.cpp b/cpp/src/pass/cfapass.cpp index c4afd00..07801b6 100644 --- a/cpp/src/pass/cfapass.cpp +++ b/cpp/src/pass/cfapass.cpp @@ -1,100 +1,100 @@ #include "cfapass.h" #include "analysis/cfagraph.h" #include using namespace std; using namespace xreate; void CFAPass::initSignatures(){ - auto range = man->root->__interfacesData.equal_range(CFA); - for (auto i = range.first; i!= range.second; ++i){ - __signatures.emplace(i->second.op, i->second); - } + auto range = man->root->__interfacesData.equal_range(CFA); + for (auto i = range.first; i!= range.second; ++i){ + __signatures.emplace(i->second.op, i->second); + } } void CFAPass::run(){ - initSignatures(); + initSignatures(); - return AbstractPass::run(); + return AbstractPass::run(); } void CFAPass::finish() { man->clasp->setCFAData(move(__context.graph)); return AbstractPass::finish(); } void CFAPass::processFnCall(ManagedFnPtr function, PassContext context) { - ClaspLayer* clasp = man->clasp; - __context.graph->addCallConnection(clasp->pack(context.scope), function->getName()); + ClaspLayer* clasp = man->clasp; + __context.graph->addCallConnection(clasp->pack(context.scope), function->getName()); - return AbstractPass::processFnCall(function, context); + return AbstractPass::processFnCall(function, context); } void CFAPass::processFnCallUncertain(ManagedFnPtr function, PassContext context){ - ClaspLayer* clasp = man->clasp; - __context.graph->addCallConnection(clasp->pack(context.scope), function->getName()); + ClaspLayer* clasp = man->clasp; + __context.graph->addCallConnection(clasp->pack(context.scope), function->getName()); - return AbstractPass::processFnCallUncertain(function, context); + return AbstractPass::processFnCallUncertain(function, context); } void CFAPass::process(CodeScope* scope, PassContext context, const std::string& hintBlockDecl){ - ClaspLayer* clasp = man->clasp; + ClaspLayer* clasp = man->clasp; - CodeScope* scopeParent = context.scope; - ScopePacked scopeId = clasp->pack(scope); + CodeScope* scopeParent = context.scope; + ScopePacked scopeId = clasp->pack(scope); - if (scopeParent){ - __context.graph->addParentConnection(scopeId, clasp->pack(scopeParent)); - } else { - __context.graph->addParentConnection(scopeId, context.function->getName()); - } + if (scopeParent){ + __context.graph->addParentConnection(scopeId, clasp->pack(scopeParent)); + } else { + __context.graph->addParentConnection(scopeId, context.function->getName()); + } - //TOTEST scope annotations - //SECTIONTAG context gather scope annotations - __context.graph->addScopeAnnotations(scopeId, scope->tags); + //TOTEST scope annotations + //SECTIONTAG context gather scope annotations + __context.graph->addScopeAnnotations(scopeId, scope->tags); - __context.graph->addContextRules(scopeId, scope->contextRules); + __context.graph->addContextRules(scopeId, scope->contextRules); - return AbstractPass::process(scope, context, hintBlockDecl); + return AbstractPass::process(scope, context, hintBlockDecl); } //TOTEST scope annotations via scheme void CFAPass::process(const Expression& expression, PassContext context, const std::string& varDecl){ - ClaspLayer* clasp = man->clasp; + ClaspLayer* clasp = man->clasp; - if (expression.__state == Expression::COMPOUND){ - Operator op= expression.op; + if (expression.__state == Expression::COMPOUND){ + Operator op= expression.op; - if (__signatures.count(op)) { - assert(expression.blocks.size()); + if (__signatures.count(op)) { + assert(expression.blocks.size()); - for (const auto& scheme: boost::make_iterator_range(__signatures.equal_range(expression.op))) { - __context.graph->addScopeAnnotations(clasp->pack(expression.blocks.front()), scheme.second.getOperands()); - } - } - } + for (const auto& scheme: boost::make_iterator_range(__signatures.equal_range(expression.op))) { + __context.graph->addScopeAnnotations(clasp->pack(expression.blocks.front()), scheme.second.getOperands()); + } + } + } - return AbstractPass::process(expression, context, varDecl); + return AbstractPass::process(expression, context, varDecl); } void CFAPass::process(ManagedFnPtr function) { - __context.graph->addFunctionAnnotations(function->getName(), function->getTags()); - return AbstractPass::process(function); + __context.graph->addFunctionAnnotations(function->getName(), function->getTags()); + return AbstractPass::process(function); } CFAPass::CFAPass(PassManager* manager) - : AbstractPass(manager) - , __context{new xreate::analysis::CFAGraph(manager->clasp)} -{} + : AbstractPass(manager) + , __context{new xreate::analysis::CFAGraph(manager->clasp)} +{} \ No newline at end of file diff --git a/cpp/src/pass/compilepass.cpp b/cpp/src/pass/compilepass.cpp index a0a44f9..a84bb49 100644 --- a/cpp/src/pass/compilepass.cpp +++ b/cpp/src/pass/compilepass.cpp @@ -1,784 +1,770 @@ #include "compilepass.h" #include "clasplayer.h" #include #include "llvmlayer.h" #include "query/containers.h" #include "query/context.h" #include "compilation/containers.h" -#include "compilation/transformations.h" #include "compilation/latecontextcompiler2.h" #include "ExternLayer.h" #include "pass/adhocpass.h" #include "compilation/targetinterpretation.h" +#include "pass/versionspass.h" +#include "compilation/scopedecorators.h" #include #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; } 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)); ScopedSymbol argid{entry->__identifiers.at(arg), VERSION_NONE}; return llvm->toLLVMType(ast->expandType(entry->__declarations.at(argid).type)); }); return signature; } llvm::Type* BasicFunctionDecorator::prepareResult(){ LLVMLayer* llvm = FunctionUnit::pass->man->llvm; AST* ast = FunctionUnit::pass->man->root; CodeScope* entry = FunctionUnit::function->__entry; return llvm->toLLVMType(ast->expandType(entry->__declarations.at(ScopedSymbol::RetSymbol).type)); } llvm::Function::arg_iterator BasicFunctionDecorator::prepareBindings(){ CodeScope* entry = FunctionUnit::function->__entry; - CodeScopeUnit* entryCompilation = FunctionUnit::getScopeUnit(entry); + AbstractCodeScopeUnit* entryCompilation = FunctionUnit::getScopeUnit(entry); llvm::Function::arg_iterator fargsI = FunctionUnit::raw->arg_begin(); for (std::string &arg : entry->__bindings) { - ScopedSymbol argid = entry->__identifiers[arg]; + ScopedSymbol argid{entry->__identifiers[arg], VERSION_NONE}; - entryCompilation->__rawVars[argid] = &*fargsI; + entryCompilation->bindArg(&*fargsI, argid); fargsI->setName(arg); ++fargsI; } return fargsI; } //SECTIONTAG late-context FunctionDecorator template class LateContextFunctionDecorator: public Parent{ public: LateContextFunctionDecorator(ManagedFnPtr f, CompilePass* p) : Parent(f, p), contextCompiler(this, p) {} 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; } public: LateContextCompiler2 contextCompiler; }; //SECTIONTAG adhoc FunctionDecorator template class AdhocFunctionDecorator: public Parent{ public: AdhocFunctionDecorator(ManagedFnPtr f, CompilePass* p) : Parent(f, p) {} protected: llvm::Type* prepareResult(){ PassManager* man = Parent::pass->man; CodeScope* entry = Parent::function->__entry; LLVMLayer* llvm = Parent::pass->man->llvm; AST* ast = Parent::pass->man->root; AdhocPass* adhocpass = reinterpret_cast(man->getPassById(PassId::AdhocPass)); if (! Parent::function->isPrefunction){ return Parent::prepareResult(); } - adhocImplementation = adhocpass->determineForScope(entry); + adhocImplementation = adhocpass->findAssotiatedScheme(entry); return llvm->toLLVMType(ast->expandType(adhocImplementation->getResultType())); } public: AdhocScheme* adhocImplementation=nullptr; }; +//DEBT compiler rigidly depends on exact definition of DefaultFunctionUnit typedef LateContextFunctionDecorator< AdhocFunctionDecorator< BasicFunctionDecorator>> DefaultFunctionUnit; -CodeScopeUnit::CodeScopeUnit(CodeScope* codeScope, FunctionUnit* f, CompilePass* compilePass) - : scope(codeScope), pass(compilePass), function(f) +AbstractCodeScopeUnit::AbstractCodeScopeUnit(CodeScope* codeScope, FunctionUnit* f, CompilePass* compilePass) + : pass(compilePass), function(f), scope(codeScope) {} 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 +//DESABLEDFEATURE implement inlining class CallStatementInline: public CallStatement{ public: CallStatementInline(FunctionUnit* caller, FunctionUnit* callee, LLVMLayer* l) : __caller(caller), __callee(callee), llvm(l) {} llvm::Value* operator() (std::vector&& args, const std::string& hintDecl) { //TOTEST inlining // CodeScopeUnit* entryCompilation = outer->getScopeUnit(function->__entry); // for(int i=0, size = args.size(); ibindArg(args.at(i), string(entryCompilation->scope->__bindings.at(i))); // } // // // return entryCompilation->compile(); + + return nullptr; } 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; } }; - } -void -CodeScopeUnit::overrideDeclaration(const Symbol binding, Expression&& declaration){ - function->getScopeUnit(binding.scope)->__declarationsOverriden.emplace(binding.identifier, move(declaration)); +BasicCodeScopeUnit::BasicCodeScopeUnit(CodeScope* codeScope, FunctionUnit* f, CompilePass* compilePass) + : AbstractCodeScopeUnit(codeScope, f, compilePass) +{} + +llvm::Value* +BasicCodeScopeUnit::processSymbol(const Symbol& s, std::string hintRetVar){ + Expression declaration = CodeScope::getDeclaration(s); + CodeScope* scope = s.scope; + AbstractCodeScopeUnit* self = AbstractCodeScopeUnit::function->getScopeUnit(scope); + + return self->process(declaration, hintRetVar); } + //SECTIONTAG late-context find callee function //TOTEST static late context decisions //TOTEST dynamic late context decisions - CallStatement* -CodeScopeUnit::findFunction(const std::string& calleeName){ +BasicCodeScopeUnit::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, llvm); } //no decisions required if (specializations.size()==1){ if (!specializations.front()->guardContext.isValid()) { 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 = function->contextCompiler.getFunctionDemandSize(); //decision made if static context found or no late context exists(and there is default variant) bool flagHasStaticDecision = variant || (variantDefault && !sizeDemand); //if no late context exists if (flagHasStaticDecision) { FunctionUnit* calleeUnit = pass->getFunctionUnit(variant? *variant: *variantDefault); //inlining possible based on static decision only // if (calleeUnit->isInline()) { // return new CallStatementInline(function, calleeUnit); // } return new CallStatementRaw(calleeUnit->compile(), llvm); } //require default variant if no static decision made assert(variantDefault); llvm::Function* functionVariantDefault = this->pass->getFunctionUnit(*variantDefault)->compile(); llvm::Value* resultFn = function->contextCompiler.findFunction(calleeName, functionVariantDefault, scopeCaller); llvm::PointerType *resultPTy = cast(resultFn->getType()); llvm::FunctionType *resultFTy = cast(resultPTy->getElementType()); return new CallStatementRaw(resultFn, resultFTy, llvm); } -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 - ScopedSymbol id = scope->__identifiers.at(alias); - __rawVars[id] = value; -} +//DISABLEDFEATURE transformations +// if (pass->transformations->isAcceptable(expr)){ +// return pass->transformations->transform(expr, result, ctx); +// } 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); - } - - 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){ +BasicCodeScopeUnit::process(const Expression& expr, const std::string& hintVarDecl){ #define DEFAULT(x) (hintVarDecl.empty()? x: hintVarDecl) llvm::Value *left; llvm::Value *right; LLVMLayer& l = *pass->man->llvm; xreate::compilation::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(); 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)); } 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")); + assert(false); + return nullptr; + //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.compileListAsSolidArray(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.compileMapSolidOutput(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()==2); assert(expr.operands[0].__state == Expression::IDENT); const std::string& hintIdent= expr.operands[0].getValueString(); Symbol s = Attachments::get(expr.operands[0]); - const ExpandedType& t2 = pass->man->root->expandType(CodeScope::findDeclaration(s).type); + const ExpandedType& t2 = pass->man->root->expandType(CodeScope::getDeclaration(s).type); - llvm::Value* aggr = compileSymbol(s, hintIdent); + llvm::Value* aggr = processSymbol(s, hintIdent); switch (t2.get().__operator) { case TypeOperator::STRUCT: case TypeOperator::CUSTOM: { const Expression& idx = expr.operands.at(1); assert(idx.__state == Expression::STRING); std::string idxField = idx.getValueString(); return instructions.compileStructIndex(aggr, t2, idxField); }; case TypeOperator::ARRAY: { std::vector indexes; std::transform(++expr.operands.begin(), expr.operands.end(), std::inserter(indexes, indexes.end()), [this] (const Expression& op){ return process(op); } ); return instructions.compileArrayIndex(aggr, indexes, DEFAULT(string("el_") + hintIdent)); }; default: assert(false); } }; //SECTIONTAG adhoc actual compilation //TODO a) make sure that it's correct: function->adhocImplementation built for Entry scope and used in another scope case Operator::ADHOC: { DefaultFunctionUnit* function = dynamic_cast(this->function); assert(function->adhocImplementation && "Adhoc implementation not found"); - string comm = expr.operands[0].getValueString(); + const Expression& comm = AdhocExpression(expr).getCommand(); - CodeScope* scope = function->adhocImplementation->getImplementationForCommand(comm); - CodeScopeUnit* unitScope = function->getScopeUnit(scope); + CodeScope* scope = function->adhocImplementation->getCommandImplementation(comm); + AbstractCodeScopeUnit* unitScope = function->getScopeUnit(scope); //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::CALL_INTRINSIC:{ + const std::string op = expr.getValueString(); + + if (op == "copy") { + llvm::Value* result = process(expr.getOperands().at(0)); + + auto decoratorVersions = Decorators::getInterface(this); + llvm::Value* storage = decoratorVersions->processIntrinsicInit(result->getType()); + decoratorVersions->processIntrinsicCopy(result, storage); + + return l.builder.CreateLoad(storage, hintVarDecl); + } + + assert(false && "undefined intrinsic"); + } + case Operator::NONE: assert(expr.__state != Expression::COMPOUND); switch (expr.__state) { case Expression::IDENT: { Symbol s = Attachments::get(expr); - return compileSymbol(s, expr.getValueString()); + return processSymbol(s, expr.getValueString()); } case Expression::NUMBER: { + llvm::Type* typConst; + + if (expr.type.isValid()){ + typConst = l.toLLVMType(pass->man->root->expandType(expr.type)); + + } else { + typConst = llvm::Type::getInt32Ty(llvm::getGlobalContext()); + } + int literal = expr.getValueDouble(); - return llvm::ConstantInt::get(llvm::Type::getInt32Ty(llvm::getGlobalContext()), literal); + return llvm::ConstantInt::get(typConst, 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; - - +BasicCodeScopeUnit::compile(const std::string& hintBlockDecl){ if (!hintBlockDecl.empty()) { llvm::BasicBlock *block = llvm::BasicBlock::Create(llvm::getGlobalContext(), hintBlockDecl, function->raw); pass->man->llvm->builder.SetInsertPoint(block); } - raw = process(scope->getBody()); - return raw; + Symbol symbScope = Symbol{ScopedSymbol::RetSymbol, scope}; + return processSymbol(symbScope); } -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); -} - - - llvm::Function* FunctionUnit::compile(){ if (raw != nullptr) return raw; LLVMLayer* llvm = pass->man->llvm; llvm::IRBuilder<>& builder = llvm->builder; 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 =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* +AbstractCodeScopeUnit* FunctionUnit::getScopeUnit(CodeScope* scope){ if (!scopes.count(scope)){ - CodeScopeUnit* unit = new CodeScopeUnit(scope, this, pass); - scopes.emplace(scope, std::unique_ptr(unit)); + AbstractCodeScopeUnit* unit = new DefaultScopeUnit(scope, this, pass); + scopes.emplace(scope, std::unique_ptr(unit)); } return scopes.at(scope).get(); } -CodeScopeUnit* +AbstractCodeScopeUnit* FunctionUnit::getEntry(){ return getScopeUnit(function->getEntryScope()); } -CodeScopeUnit* +AbstractCodeScopeUnit* 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); } void CompilePass::run(){ - transformations = new Transformations(this); - transformations->registerTransformer(new TransformerSaturation(transformations)); +// transformations = new Transformations(this); + + //DISABLEDFEATURE transformerSaturation + //transformations->registerTransformer(new TransformerSaturation(transformations)); 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); } \ No newline at end of file diff --git a/cpp/src/pass/compilepass.h b/cpp/src/pass/compilepass.h index 06ee8eb..1297617 100644 --- a/cpp/src/pass/compilepass.h +++ b/cpp/src/pass/compilepass.h @@ -1,162 +1,166 @@ #ifndef COMPILEPASS_H #define COMPILEPASS_H #include "abstractpass.h" + #include "llvm/IR/Function.h" namespace xreate { class AdhocScheme; class ClaspLayer; class ContextQuery; class LLVMLayer; } //namespace llvm { // class Function; // class Value; // class Type; //} namespace xreate { class CompilePass; namespace compilation { -class CodeScopeUnit; +class AbstractCodeScopeUnit; class FunctionUnit; class TargetInterpretation; struct Context{ - CodeScopeUnit* scope; + AbstractCodeScopeUnit* 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 { +class AbstractCodeScopeUnit{ public: - CodeScopeUnit(CodeScope* codeScope, FunctionUnit* f, CompilePass* compilePass); - - void bindArg(llvm::Value* value, std::string&& alias); - void overrideDeclaration(const Symbol binding, Expression&& declaration); - std::map __rawVars; - - void reset(){raw = nullptr;} - llvm::Value* compile(const std::string& hintBlockDecl=""); - llvm::Value* compileSymbol(const Symbol& s, std::string hintRetVar="");| - llvm::Value* process(const Expression& expr, const std::string& hintVarDecl=""); - llvm::Value* processLowlevel(const Expression& expr, const std::string& hintVarDecl=""); + CompilePass* const pass; + FunctionUnit* const function; + CodeScope* const scope; - CodeScope* scope; + AbstractCodeScopeUnit(CodeScope* codeScope, FunctionUnit* f, CompilePass* compilePass); + ~AbstractCodeScopeUnit(){} -private: - CompilePass* pass; - llvm::Value* raw = nullptr; - FunctionUnit* function; - std::unordered_map __declarationsOverriden; + virtual llvm::Value* compile(const std::string& hintBlockDecl="")=0; + virtual llvm::Value* processSymbol(const Symbol& s, std::string hintRetVar="")=0; + virtual llvm::Value* process(const Expression& expr, const std::string& hintVarDecl="")=0; + virtual void bindArg(llvm::Value* value, std::string&& alias)=0; + virtual void bindArg(llvm::Value* value, const ScopedSymbol& s)=0; - CallStatement* findFunction(const std::string& callee); +protected: + virtual CallStatement* findFunction(const std::string& callee)=0; }; -class IScopeDecorator{ - virtual llvm::Value* compile(const std::string& hintBlockDecl=""); - virtual llvm::Value* process(const Expression& expr, const std::string& hintVarDecl=""); +class BasicCodeScopeUnit: public AbstractCodeScopeUnit{ +public: + BasicCodeScopeUnit(CodeScope* codeScope, FunctionUnit* f, CompilePass* compilePass); + ~BasicCodeScopeUnit(){} + + llvm::Value* processSymbol(const Symbol& s, std::string hintRetVar=""); + llvm::Value* process(const Expression& expr, const std::string& hintVarDecl=""); + llvm::Value* compile(const std::string& hintBlockDecl=""); - virtual ~IScopeDecorator(){} +protected: + 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 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); + AbstractCodeScopeUnit* getEntry(); + AbstractCodeScopeUnit* getScopeUnit(CodeScope* scope); + AbstractCodeScopeUnit* getScopeUnit(ManagedScpPtr scope); ManagedFnPtr function; llvm::Function* raw = nullptr; protected: CompilePass* pass=nullptr; private: - std::map> scopes; + 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; + friend class LateContextCompiler; + friend class LateContextCompiler2; + friend class compilation::BasicCodeScopeUnit; + friend class compilation::FunctionUnit; public: - compilation::Transformations* transformations; +// compilation::Transformations* transformations; + compilation::TargetInterpretation* targetInterpretation; CompilePass(PassManager* manager): AbstractPass(manager) {} compilation::FunctionUnit* getFunctionUnit(const ManagedFnPtr& function); void run() override; llvm::Function* getEntryFunction(); static void prepareQueries(ClaspLayer* clasp); + + private: //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 f9d79c4..49a957a 100644 --- a/cpp/src/pass/dfapass.cpp +++ b/cpp/src/pass/dfapass.cpp @@ -1,238 +1,262 @@ #include "pass/dfapass.h" #include "analysis/dfagraph.h" #include "passmanager.h" #include "clasplayer.h" #include using namespace std; using namespace xreate::analysis; -namespace xreate{ +namespace xreate { -DFAPass::DFAPass(PassManager* manager) - : AbstractPass(manager) - , __context{new xreate::analysis::DFAGraph(manager->clasp)} - , clasp(manager->clasp) -{} + class DfaExpressionProcessor { + std::vector operands; + std::vector blocks; -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); + const Expression expression; + xreate::analysis::SymbolNode result; + DFAPass * const pass; + const PassContext context; - 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)); + public: + DfaExpressionProcessor(const Expression& expr, SymbolNode resInitial, DFAPass * const p, const PassContext c) + : expression(expr), result(resInitial), pass(p), context(c) { - } 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)); - } + operands.reserve(expression.getOperands().size()); + for (const Expression &op : expression.getOperands()) { + SymbolAnonymous symbOp(op.id); - cache.blocks.reserve(expression.blocks.size()); - for (CodeScope* scope: expression.blocks) { - cache.blocks.push_back(process(scope, context)); - } + operands.push_back(DfaExpressionProcessor(op, symbOp, pass, context).process()); + } - if (expression.__state == Expression::COMPOUND) { - processCompoundOp(expression, context, cache, decl); + blocks.reserve(expression.blocks.size()); + for (CodeScope* scope : expression.blocks) { + blocks.push_back(pass->process(scope, context)); + } + } - } else { - processElementaryOp(expression, context, cache, decl); - } + SymbolNode + process() { + if (expression.__state == Expression::COMPOUND) { + processCompoundOp(); - applyDependencies(expression, context, cache, decl); - applyStaticAnnotations(expression, context, cache, decl); - applySignatureAnnotations(expression, context, cache, decl); - applyInPlaceAnnotations(expression, context, cache, decl); + } else { + processElementaryOp(); + } -//TODO Null ad hoc DFG implementation -// if (expression.isNone()){ -// return SymbolTransient{{Atom(Config::get("clasp.nonevalue"))}}; -// } + applySignatureAnnotations(); + applyInPlaceAnnotations(); - //non initialized(SymbolInvalid) value + return result; + } - return cache.result; -} + private: + void + processElementaryOp() { + switch (expression.__state) { + case Expression::IDENT: + { + SymbolPacked symbFrom = pass->processSymbol(Attachments::get(expression), context, expression.getValueString()); + SymbolPacked* symbTo = boost::get(&result); + if (symbTo) { + pass->__context.graph->addConnection(*symbTo, SymbolNode(symbFrom), DFGConnection::STRONG); -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(); + } else { + result = SymbolNode(symbFrom); + } - SymbolNode nodeFrom = AbstractPass::process(expression, context, identifier); - if (SymbolPacked* nodeTo = boost::get(&cache.result)){ - __context.graph->addConnection(*nodeTo, nodeFrom, DFGConnection::STRONG); + break; + } - } else { - // cache.result = nodeFrom; + default: break; } - - 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; + void + processCompoundOp() { + switch (expression.op) { + + //DEBT provide CALL processing + // 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 ScopedSymbol symbolFormal{scopeRemote->__identifiers.at(identFormal), VERSION_NONE}; + // + // __context.graph->addConnection(clasp->pack(Symbol{symbolFormal, scopeRemote}, nameCalleeFunction + ":" + identFormal), *nodeActual, DFGConnection::WEAK); + // ++nodeActual; + // } + // + // //TODO add RET connection + // break; + // } + + //MAP processing: apply PROTOTYPE relation + case Operator::MAP: + { + SymbolNode nodeFrom = operands.front(); + + SymbolPacked* nodeTo = boost::get(&result); + assert(nodeTo); + + pass->__context.graph->addConnection(*nodeTo, nodeFrom, DFGConnection::PROTOTYPE); + break; + } + + default: break; } - - //TODO represent RET connection - break; } - //apply PROTOTYPE relation - case Operator::MAP: { - SymbolNode nodeFrom= cache.operands.front(); + void + applySignatureAnnotations() { + if (pass->__signatures.count(expression.op)) { + const Expression &scheme = pass->__signatures.at(expression.op); - SymbolPacked* nodeFromPacked = boost::get(&nodeFrom); - assert(nodeFromPacked); - - SymbolPacked* nodeTo = boost::get(&cache.result); - assert(nodeTo); - - __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); - } + std::vector::iterator arg = operands.begin(); + std::vector::const_iterator tag = scheme.getOperands().begin(); - for (SymbolNode &block: cache.blocks) { - __context.graph->addDependencyConnection(cache.result, block); - } + //Assign scheme RET annotation + Expression retTag = *scheme.getOperands().begin(); + if (retTag.__state != Expression::INVALID) { + pass->__context.graph->addAnnotation(result, move(retTag)); + } - switch(expression.__state) { - case Expression::IDENT: { - SymbolNode identSymbol = clasp->pack(Attachments::get(expression), context.function->getName() + ":" + expression.getValueString()); - __context.graph->addDependencyConnection(cache.result, identSymbol); - } + ++tag; + while (tag != scheme.getOperands().end()) { + if (tag->__state != Expression::INVALID) { + pass->__context.graph->addAnnotation(*arg, Expression(*tag)); + } - default: break; - } -} + ++arg; + ++tag; + } -void -DFAPass::applyStaticAnnotations(const Expression& expression, PassContext context, ExpressionCache& cache, const std::string& decl){ + // TODO add possibility to have specific 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, "")); + // } - 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); + void + applyInPlaceAnnotations() { + // write down in-place expression tags: + for (pair tag : expression.tags) { + pass->__context.graph->addAnnotation(result, Expression(tag.second)); + } + } + }; - //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(); + DFAPass::DFAPass(PassManager* manager) + : AbstractPass(manager) + , __context{new xreate::analysis::DFAGraph(manager->clasp)} + , clasp(manager->clasp) + {} - while (tag != scheme.getOperands().end()) { - if (tag->__state != Expression::INVALID) { - __context.graph->addAnnotation(*arg, Expression(*tag)); - } + SymbolPacked + DFAPass::process(CodeScope* scope, PassContext context, const std::string& hintBlockDecl) { + const SymbolPacked& symbRet = AbstractPass::process(scope, context, hintBlockDecl); + return symbRet; + } - ++arg; ++tag; - } + SymbolPacked + DFAPass::processSymbol(const Symbol& symbol, PassContext context, const std::string& hintSymbol) { + const Expression& declaration = CodeScope::getDeclaration(symbol); + const SymbolPacked& symbPacked = clasp->pack(symbol, hintSymbol); + DfaExpressionProcessor(declaration, symbPacked, this, context).process(); - //TODO represent RET connection -// Expression retTag = *scheme.getOperands().begin(); -// if (retTag.__state != Expression::INVALID) { -// __context.graph->addAnnotation(node, move(retTag)); -// } + return symbPacked; } -} -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::run() -{ - init(); - return AbstractPass::run(); -} -void -DFAPass::init() -{ - for (const Expression& scheme: man->root->__dfadata) - { - __signatures.emplace(scheme.op, scheme); + void + DFAPass::init() { + for (const Expression& scheme : man->root->__dfadata) { + __signatures.emplace(scheme.op, scheme); + } } -} -void DFAPass::finish() -{ - man->clasp->setDFAData(move(__context.graph)); -} + void + DFAPass::finish() { + clasp->setDFAData(move(__context.graph)); + } template<> -SymbolNode defaultValue(){return SymbolInvalid();}; - +SymbolPacked defaultValue(){ + assert(false); } +} //xreate namespace + + + + //DEBT represent VersionaPass in declarative form using applyDependencies + // applyDependencies(expression, context, cache, decl); + + //DEBT prepare static annotations and represent InterpretationPass in declarative form + // applyStaticAnnotations(expression, context, cache, decl); + + + + //TODO Null ad hoc DFG implementation/None symbol + //DISABLEDFEATURE None value + // if (expression.isNone()){ + // return SymbolTransient{{Atom(Config::get("clasp.nonevalue"))}}; + // } + + // non initialized(SymbolInvalid) value + + //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: { + // SymbolNode identSymbol = clasp->pack(Attachments::get(expression), context.function->getName() + ":" + expression.getValueString()); + // __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; + // } + //} \ No newline at end of file diff --git a/cpp/src/pass/dfapass.h b/cpp/src/pass/dfapass.h index cc26e8c..0bc50a4 100644 --- a/cpp/src/pass/dfapass.h +++ b/cpp/src/pass/dfapass.h @@ -1,49 +1,39 @@ // Data Flow Graph determination pass #ifndef DFGPASS_H #define DFGPASS_H #include "abstractpass.h" #include "analysis/dfagraph.h" namespace xreate { class ClaspLayer; +class DfaExpressionProcessor; -class DFAPass : public AbstractPass { +class DFAPass: public AbstractPass { + friend class DfaExpressionProcessor; + public: - xreate::analysis::SymbolNode process(CodeScope* scope, PassContext context, const std::string& hintBlockDecl="") override; - xreate::analysis::SymbolNode process(const Expression& expression, PassContext context, const std::string& varDecl="") override; - DFAPass(PassManager* manager); + + SymbolPacked processSymbol(const Symbol& symbol, PassContext context, const std::string& hintSymbol="") override; + SymbolPacked process(CodeScope* scope, PassContext context, const std::string& hintBlockDecl="") override; void init(); - void run(); - void finish(); + void run() override; + void finish() override; private: struct { xreate::analysis::DFAGraph* graph; } __context; - struct ExpressionCache{ - std::vector operands; - std::vector blocks; - xreate::analysis::SymbolNode result; - }; - std::map __signatures; //DFA data for particular operators ClaspLayer* clasp; - - void processCompoundOp(const Expression& expression, PassContext context, ExpressionCache& cache, const std::string& varDecl=""); - void processElementaryOp(const Expression& expression, PassContext context, ExpressionCache& cache, const std::string& varDecl=""); - - void applyDependencies(const Expression& expression, PassContext context, ExpressionCache& cache, const std::string& decl); - void applyInPlaceAnnotations(const Expression& expression, PassContext context, ExpressionCache& cache, const std::string& decl); - void applySignatureAnnotations(const Expression& expression, PassContext context, ExpressionCache& cache, const std::string& decl); - void applyStaticAnnotations(const Expression& expression, PassContext context, ExpressionCache& cache, const std::string& decl); -}; }; +}; //end of xreate namespace + #endif diff --git a/cpp/src/pass/interpretationpass.cpp b/cpp/src/pass/interpretationpass.cpp index 0fe16b4..e75520f 100644 --- a/cpp/src/pass/interpretationpass.cpp +++ b/cpp/src/pass/interpretationpass.cpp @@ -1,410 +1,423 @@ /* * File: interpretationpass.cpp * Author: pgess * * Created on July 5, 2016, 5:21 PM */ #include "pass/interpretationpass.h" -#include "compilation/transformations.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== ANY){ return unify(flagB, flags...); } 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; } +bool +InterpretationData::isDefault() const{ + return (resolution == ANY && op == NONE); +} + namespace details { InterpretationResolution recognizeTags(const map& tags){ auto i = tags.find("interpretation"); if (i== tags.end()){ return ANY; } assert(i->second.op == Operator::CALL); const string& cmd = i->second.operands.at(0).getValueString(); //TODO make consistent names of annotation and resolution if (cmd == "force"){ return INTR_ONLY; } else if (cmd == "suppress"){ return CMPL_ONLY; } return ANY; } } void recognizeTags(const Expression& e){ InterpretationData tag{details::recognizeTags(e.tags), NONE}; - Attachments::put(e, tag); + if (!tag.isDefault()) + Attachments::put(e, tag); } InterpretationResolution recognizeTags(const ManagedFnPtr& f){ return details::recognizeTags(f->getTags()); } InterpretationPass::InterpretationPass(PassManager* manager) : AbstractPass(manager) { Attachments::init(); Attachments::init(); } void InterpretationPass::run(){ ManagedFnPtr f = man->root->begin(); auto& visitedSymbols = getSymbolCache(); while (f.isValid()) { - const Symbol& symbolFunction{0, f->getEntryScope()}; + const Symbol& symbolFunction{ScopedSymbol::RetSymbol, 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 = ANY; InterpretationOperator op = NONE; switch (expression.__state){ + case Expression::VARIANT: case Expression::NUMBER: case Expression::STRING: { break; } case Expression::IDENT: { - resolution = Parent::processSymbol(expression.getValueString(), context); + resolution = Parent::processSymbol(Attachments::get(expression), context); break; } case Expression::COMPOUND: break; - default: { resolution = INTR_ONLY; break;} + default: { resolution = CMPL_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 //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()}; + const Symbol& symbCalleeFunc{ScopedSymbol::RetSymbol, callee->getEntryScope()}; //recursion-aware processing: // - skip self recursion - const Symbol& symbSelfFunc{0, context.function->getEntryScope()}; + const Symbol& symbSelfFunc{ScopedSymbol::RetSymbol, context.function->getEntryScope()}; if (!(symbSelfFunc == symbCalleeFunc)){ InterpretationResolution resCallee = processFnCall(callee, context); assert(resCallee != FUNC_POSTPONED && "Indirect recursion detected: can't decide on interpretation resolution"); resolution = unify(resolution, resCallee); } //check arguments compatibility - const FunctionInterpretationData& sig = FunctionInterpretationHelper::getSignature(callee); + const FunctionInterpretationData& calleeSignature = 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; + InterpretationResolution argExpected = calleeSignature.signature[op]; - assert(sig.signature[op] == argActual); + //TODO use args unification result to properly process function call + unify(argActual, argExpected); } if (FunctionInterpretationHelper::needPartialInterpretation(callee)){ op= CALL_INTERPRET_PARTIAL; } break; } case Operator::IF:{ InterpretationResolution flagCondition = process(expression.getOperands()[0], context); InterpretationResolution flagScope1 = Parent::process(expression.blocks.front(), context); InterpretationResolution flagScope2 = Parent::process(expression.blocks.back(), context); //special case: IF_INTERPRET_CONDITION if (checkConstraints({flagCondition})){ op= IF_INTERPRET_CONDITION; flagCondition = ANY; } 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)); + Symbol symbEl{ScopedSymbol{scopeBody->__identifiers.at(nameEl), VERSION_NONE}, scopeBody}; + getSymbolCache().setCachedValue(symbEl, InterpretationResolution(flagInput)); const std::string& nameAccum = expression.bindings[1]; - getSymbolCache().setCachedValue(scopeBody->findSymbol(nameAccum), InterpretationResolution(flagAccumInit)); + Symbol symbAccum{ScopedSymbol{scopeBody->__identifiers.at(nameAccum), VERSION_NONE}, scopeBody}; + getSymbolCache().setCachedValue(symbAccum, InterpretationResolution(flagAccumInit)); InterpretationResolution flagBody = Parent::process(expression.blocks.front(), context); //special case: FOLD_INTERPRET_INPUT if (checkConstraints({flagInput})){ op= FOLD_INTERPRET_INPUT; flagInput = ANY; } resolution = unify(flagInput, flagAccumInit, flagBody); break; } case Operator::INDEX: { resolution = unify( process(expression.operands[0], context), - process(expression.operands[1], context), + process(expression.operands[1], 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})){ op= SWITCH_INTERPRET_CONDITION; flagHeaders = ANY; } //determine body resolutions resolution = flagHeaders; for (size_t size = expression.operands.size(), i= 1; i(expression, {ANY, NONE}).resolution; resolution = unify(resolution, resolutionExpected); - if (op!=NONE || resolution == INTR_ONLY ){ + if (resolution != resolutionExpected && (op!=NONE || resolution == INTR_ONLY)){ Attachments::put(expression, {resolution, op}); } - if (resolution == INTR_ONLY){ - compilation::Transformations::subscribe(expression); - } - return resolution; } InterpretationResolution InterpretationPass::processFnCall(ManagedFnPtr function, PassContext context){ - const Symbol& symbolFunction{0, function->getEntryScope()}; + const Symbol symbolFunction{ScopedSymbol::RetSymbol, function->getEntryScope()}; auto& visitedSymbols = getSymbolCache(); 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()}; + const Symbol& symbSelfFunc{ScopedSymbol::RetSymbol, function->getEntryScope()}; auto& cache = getSymbolCache(); - const FunctionInterpretationData& dataIntrpr = FunctionInterpretationHelper::getSignature(function); - InterpretationResolution resExpected = details::recognizeTags(function->getTags()); + const FunctionInterpretationData& fnSignature = FunctionInterpretationHelper::getSignature(function); + InterpretationResolution fnResolutionExpected = details::recognizeTags(function->getTags()); //mark preliminary function resolution as expected - if (resExpected != ANY){ - cache.setCachedValue(symbSelfFunc, move(resExpected)); + if (fnResolutionExpected != ANY){ + cache.setCachedValue(symbSelfFunc, move(fnResolutionExpected)); } else { // - in order to recognize indirect recursion mark this function resolution as POSTPONED cache.setCachedValue(symbSelfFunc, FUNC_POSTPONED); } //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])); + Symbol symbArg{ScopedSymbol{entry->__identifiers.at(arguments[argNo]), VERSION_NONE}, entry}; + cache.setCachedValue(symbArg, InterpretationResolution(fnSignature.signature[argNo])); } - InterpretationResolution resActual = Parent::process(function); - return unify(resActual, resExpected); + PassContext context; + context.function = function; + context.scope = entry; + InterpretationResolution resActual = process(CodeScope::getDeclaration(symbSelfFunc), context); + resActual = unify(resActual, fnResolutionExpected); + return cache.setCachedValue(symbSelfFunc, move(resActual)); } const FunctionInterpretationData FunctionInterpretationHelper::getSignature(ManagedFnPtr function){ - const Symbol& symbFunc{0, function->getEntryScope()}; - - if (Attachments::exists(symbFunc)){ - return Attachments::get(symbFunc); + if (Attachments::exists(function)){ + return Attachments::get(function); } FunctionInterpretationData&& data = recognizeSignature(function); - Attachments::put(symbFunc, data); + Attachments::put(function, 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)); + Symbol symbArg{ScopedSymbol{entry->__identifiers.at(argName), VERSION_NONE}, entry}; + + const Expression& arg = CodeScope::getDeclaration(symbArg); 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; } } -//if (res != INTR_ONLY){ -// argumentsActual.insert(no); -//} - - diff --git a/cpp/src/pass/interpretationpass.h b/cpp/src/pass/interpretationpass.h index 0d6ba84..a6434e6 100644 --- a/cpp/src/pass/interpretationpass.h +++ b/cpp/src/pass/interpretationpass.h @@ -1,78 +1,80 @@ /* * 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{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; + + bool isDefault() const; }; template<> InterpretationResolution defaultValue(); struct FunctionInterpretationData{ typedef std::vector Signature; Signature signature; bool flagPartialInterpretation; }; template<> struct AttachmentsDict { typedef FunctionInterpretationData Data; static const unsigned int key = 5; }; class FunctionInterpretationHelper { public: static const FunctionInterpretationData getSignature(ManagedFnPtr function); static bool needPartialInterpretation(ManagedFnPtr function); private: static FunctionInterpretationData recognizeSignature(ManagedFnPtr function); }; template<> struct AttachmentsDict { typedef InterpretationData Data; static const unsigned int key = 3; }; 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/pass/loggerpass.cpp b/cpp/src/pass/loggerpass.cpp deleted file mode 100644 index c7124b5..0000000 --- a/cpp/src/pass/loggerpass.cpp +++ /dev/null @@ -1,110 +0,0 @@ -/* - * logging.cpp - * - * Created on: Jun 23, 2015 - * Author: pgess - */ - -#include -#include "compilation/containers.h" -#include "utils.h" - -using namespace std; -using namespace llvm; -namespace xreate { - - -void LoggerPass::init(ClaspLayer* clasp){ - auto model = clasp->query(Config::get("logging.id")); - if(!model) return; - - for (ClaspLayer::ModelIterator rec = model->first; rec!=model->second; ++rec){ - std::tuple _v =ClaspLayer::parse(rec->second); - Symbol v = clasp->unpack(get<0>(_v)); - - Attachments::put(v, true); - } -} - -void -LoggerPass::process(const Expression& expression, PassContext context, const std::string& varDecl){ - if (varDecl.size()){ - Symbol v = context.scope->findSymbol(varDecl); - if (Attachments::get(v, false)){ - compilation::FunctionUnit* func = compiler->getFunctionUnit(context.function); - compilation::CodeScopeUnit* scope = func->getScopeUnit(context.scope); - - compilation::Context compilationContext{scope, func, compiler}; - inject(v, compilationContext); - } - } - - return AbstractPass::process(expression, context, varDecl); -} - -void LoggerPass::inject(const Symbol& symbol, const compilation::Context& context){ - //TODO fix log injection - -// llvm::Value* source = context.scope->compileSymbol(symbol); -// ExpandedType typSource = man->root->expandType(CodeScope::findDefinition(symbol).type); -// string format = ""; -// switch (typSource->__value) { -// case TypePrimitive::Int : case TypePrimitive::Num : case TypePrimitive::I32: case TypePrimitive::I8: -// format = "%d\n"; -// break; -// -// case TypePrimitive::String: -// format = "%s\n"; -// break; -// -// default: -// assert(false && "No appropriate type for logging"); -// } -// -// xreate::compilation::Advanced instructions(context); -// -// LLVMLayer* llvm = context.pass->man->llvm; -// llvm->builder.SetInsertPoint(llvm->builder.GetInsertBlock(), *source->use_begin()); -// llvm::Value* formatRaw = instructions.compileConstantStringAsPChar(format, "logformat"); -// -// llvm->builder.CreateCall2(refPrintf, formatRaw, source); -} - -void -LoggerPass::initOutput(){ - LLVMLayer* llvm = man->llvm; - refPrintf = llvm->module->getFunction("printf"); - - if (!refPrintf) { - PointerType* typPtrI8 = PointerType::get(IntegerType::get(llvm->module->getContext(), 8), 0); - std::vectorargsPrintf{typPtrI8}; - FunctionType* signaturePrintf = FunctionType::get( - /*Result=*/IntegerType::get(llvm->module->getContext(), 32), - /*Params=*/argsPrintf, - /*isVarArg=*/true); - - refPrintf = llvm::Function::Create( - /*Type=*/signaturePrintf, - /*Linkage=*/GlobalValue::ExternalLinkage, - /*Name=*/"printf", llvm->module); // (external, no body) - - refPrintf->setCallingConv(CallingConv::C); - } -} - -LoggerPass::LoggerPass(PassManager* manager) - : AbstractPass(manager) -{ - initOutput(); - init(man->clasp); - - Attachments::init(); -} - -void -LoggerPass::initDependencies(CompilePass* pass){ - compiler = pass; -} - - -} /* namespace xreate */ diff --git a/cpp/src/pass/loggerpass.h b/cpp/src/pass/loggerpass.h deleted file mode 100644 index 252e9c8..0000000 --- a/cpp/src/pass/loggerpass.h +++ /dev/null @@ -1,44 +0,0 @@ -/* - * logging.h - * - * Created on: Jun 23, 2015 - * Author: pgess - */ - -#ifndef SRC_LOGGING_H_ -#define SRC_LOGGING_H_ - -#include "ast.h" -#include -#include "pass/compilepass.h" -#include "pass/abstractpass.h" -#include "clasplayer.h" - -namespace xreate { - -class LoggerPass:public AbstractPass, public IQuery { -public: - void inject(const Symbol& symbol, const compilation::Context& context); - LoggerPass(PassManager* manager); - - virtual void init(ClaspLayer* clasp); - void initDependencies(CompilePass* pass); - virtual void process(const Expression& expression, PassContext context, const std::string& varDecl=""); - -private: - CompilePass* compiler = nullptr; - llvm::Function* refPrintf; - void initOutput(); -}; - -struct IsLogging{}; - -template<> -struct AttachmentsDict { - typedef bool Data; - static const unsigned int key = 2; -}; - -} /* namespace xreate */ - -#endif /* SRC_LOGGING_H_ */ diff --git a/cpp/src/pass/rulespass.h b/cpp/src/pass/rulespass.h index fefd760..4bf4b5e 100644 --- a/cpp/src/pass/rulespass.h +++ b/cpp/src/pass/rulespass.h @@ -1,13 +1,14 @@ #ifndef RULESPASS_H #define RULESPASS_H #include "passmanager.h" +//DISABLEDFEATURE rulespass namespace xreate { class RulesPass : public ASTPass { public: void process(MetaRuleAbstract* rule, PassContext context); RulesPass(PassManager* manager); }; } #endif // RULESPASS_H diff --git a/cpp/src/pass/versionspass.cpp b/cpp/src/pass/versionspass.cpp index c02a007..65c6853 100644 --- a/cpp/src/pass/versionspass.cpp +++ b/cpp/src/pass/versionspass.cpp @@ -1,85 +1,377 @@ /* * versionspass.cpp * * Author: pgess * Created on January 4, 2017, 3:13 PM */ -#include "versionspass.h" -#include "ast.h" -#include "abstractpass.h" +#include + +#include "pass/versionspass.h" + +namespace std{ + std::size_t + hash::operator()(xreate::SymbolOrPlaceholder const& s) const + {return std::hash()(s.symbol) + (s.flagEndOfLifePlaceholder? 9849 : 1);} + + bool + equal_to::operator()(const xreate::SymbolOrPlaceholder& __x, const xreate::SymbolOrPlaceholder& __y) const + { return __x.flagEndOfLifePlaceholder == __y.flagEndOfLifePlaceholder && __x.symbol == __y.symbol; } + + size_t + hash::operator()(xreate::Symbol const& s) const{ + return hash()(s.identifier) ^ ((long int) s.scope << 1); + } + + bool + equal_to::operator()(const xreate::Symbol& __x, const xreate::Symbol& __y) const{ + return __x == __y; + }; +} + +using namespace std; namespace xreate { -Symbol -getNextVersion(const Symbol& s){ - return Symbol{ScopedSymbol{s.identifier.id, s.identifier.version+1}, s.scope}; +template<> +std::list +defaultValue>(){ + return std::list(); +}; + +inline std::string +printSymbol(const SymbolOrPlaceholder& s){ + switch(s.flagEndOfLifePlaceholder){ + case SYMBOL: return string("(") + std::to_string(s.symbol.identifier.id) + ", "+ std::to_string(s.symbol.identifier.version) + ")"; + case PLACEHOLDER: return string("(") + std::to_string(s.symbol.identifier.id) + ", "+ std::to_string(s.symbol.identifier.version) + ")+"; + } + + return ""; +} + +void +VersionsGraph::__debug_print(std::ostream& output) const{ + for(auto entry: __inferiors){ + output << printSymbol(entry.second) << " <-" << printSymbol(entry.first) << "\n"; + } +} + +void +VersionsGraph::defineEndOfLife(const Symbol& symbol, const Symbol& symbolSuccessor){ + if(__dictSuccessors.count(symbol)){ + assert("No version branches allowed yet" && false); + } + + const SymbolOrPlaceholder& placeholder = getEndOfLife(symbol); + + auto inferiorsDeferred = __inferiors.equal_range(placeholder); + std::unordered_multimap inferiorsReassigned; + + for (const auto& inf: boost::make_iterator_range(inferiorsDeferred)){ + inferiorsReassigned.emplace(SymbolOrPlaceholder{SYMBOL, symbolSuccessor}, inf.second); + } + + __inferiors.erase(placeholder); + __inferiors.insert(inferiorsReassigned.begin(), inferiorsReassigned.end()); + __inferiors.emplace(SymbolOrPlaceholder{SYMBOL, symbolSuccessor}, SymbolOrPlaceholder{SYMBOL, symbol}); + + __dictSuccessors.emplace(symbol, symbolSuccessor); +} + +SymbolOrPlaceholder +VersionsGraph::getEndOfLife(const Symbol& s){ + if (__dictSuccessors.count(s)){ + return SymbolOrPlaceholder{SYMBOL, __dictSuccessors.at(s)}; } + + + return SymbolOrPlaceholder{PLACEHOLDER, s}; } void -applyDependentUpperBound(const Symbol& symbol, const list& dependancies){ +VersionsGraph::applyNatualDependencies(const Symbol& symbol, const std::list& dependencies){ for (const Symbol& right: dependencies){ - auto rightEnd = right.getNextVersion(); + __inferiorsNatural.emplace(symbol, right); + } +} + +void +VersionsGraph::applyDependentEndOfLife(const SymbolOrPlaceholder& symbol, const list& dependencies){ + for (const Symbol& right: dependencies){ + auto rightEOF = getEndOfLife(right); - VersionInferiorsList& infs = Attachments::get(rightEnd); - infs.push_back(left); + __inferiors.emplace(rightEOF, symbol); } } +bool +VersionsGraph::tryEliminateEofAliases(const std::list& aliases){ + + if (aliases.size()==1){ + return true; + } + + boost::optional symbolActualEoF; + for(const SymbolOrPlaceholder alias: aliases){ + switch(alias.flagEndOfLifePlaceholder){ + case SYMBOL: + if(symbolActualEoF){ + return false; + } + + symbolActualEoF = alias.symbol; + break; + + case PLACEHOLDER: + continue; + } + } + + if(!symbolActualEoF){ + return false; + } + + for(const SymbolOrPlaceholder alias: aliases){ + switch(alias.flagEndOfLifePlaceholder){ + case SYMBOL: + continue; + + case PLACEHOLDER: + defineEndOfLife(alias.symbol, symbolActualEoF.get()); + break; + } + } + + return true; +} + +std::list +VersionsGraph::extractCycle(const Path& path, const SymbolOrPlaceholder& symbolBeginning){ + unsigned int posBeginning = path.at(symbolBeginning); + + std::list result; + + auto i=path.begin(); + while(true){ + i = std::find_if(i, path.end(), [&posBeginning](const auto& el){return el.second >=posBeginning;}); + + if (i!= path.end()){ + result.push_back(i->first); + ++i; + + } else {break; } + } + + return result; +} + + +bool +VersionsGraph::validateCycles(const SymbolOrPlaceholder& s, + std::unordered_multimap& graph, + std::unordered_set& symbolsVisited, + Path& path) +{ + if (symbolsVisited.count(s)) return true; + + symbolsVisited.insert(s); + path.emplace(s, path.size()); + + if (graph.count(s)){ + //iterate over imposed dependencies + auto candidates = graph.equal_range(s); + for (auto candidate = candidates.first; candidate != candidates.second; ++candidate){ + if (path.count(candidate->second)) { + std::list cycle = extractCycle(path, candidate->second); + if (!tryEliminateEofAliases(cycle)) return false; + continue; + } + + if(!validateCycles(candidate->second, graph, symbolsVisited, path)) return false; + } + } + + //iterate over natural dependencies + if (s.flagEndOfLifePlaceholder == SYMBOL) { + auto candidates = __inferiorsNatural.equal_range(s.symbol); + for (auto candidate = candidates.first; candidate != candidates.second; ++candidate){ + if (path.count(SymbolOrPlaceholder{SYMBOL, candidate->second})){ + return false; + } + + if(!validateCycles(SymbolOrPlaceholder{SYMBOL,candidate->second}, graph, symbolsVisited, path)) return false; + } + } + + //check previous version + if (s.flagEndOfLifePlaceholder == PLACEHOLDER){ + const Symbol& candidate = s.symbol; + + if (path.count(SymbolOrPlaceholder{SYMBOL, candidate})){ + std::list cycle = extractCycle(path, SymbolOrPlaceholder{SYMBOL, candidate}); + if (!tryEliminateEofAliases(cycle)) return false; + } + + if(!validateCycles(SymbolOrPlaceholder{SYMBOL,candidate}, graph, symbolsVisited, path)) return false; + } + + path.erase(s); + return true; +} + +bool +VersionsGraph::validateCycles(){ + std::unordered_set symbolsVisited; + Path path; + std::unordered_multimap graph(__inferiors); + + std::unordered_multimap::const_iterator s; + for (s = graph.begin(); s != graph.end(); ++s){ + if(!validateCycles(s->first, graph, symbolsVisited, path)) return false; + } + + return true; +} + +bool +VersionsGraph::validate(){ + return validateCycles(); +} + +std::list +VersionsGraph::expandPlaceholder(const SymbolOrPlaceholder& symbol, const Symbol& symbolPrev) const{ + std::list result; + + switch (symbol.flagEndOfLifePlaceholder){ + case SYMBOL: + //skip self-loops + if (symbol.symbol == symbolPrev) return {}; + + return {symbol.symbol}; + + case PLACEHOLDER: + for (const auto& entry: boost::make_iterator_range(__inferiors.equal_range(symbol))){ + list&& childResult = expandPlaceholder(entry.second, symbolPrev); + result.insert(result.end(), childResult.begin(), childResult.end()); + } + + if (__dictSuccessors.count(symbol.symbol)){ + Symbol knownSuccessor = __dictSuccessors.at(symbol.symbol); + + //skip alias loop + if (knownSuccessor == symbolPrev) return {}; + + for (const auto& entry: boost::make_iterator_range(__inferiors.equal_range(SymbolOrPlaceholder{SYMBOL, knownSuccessor}))){ + list&& childResult = expandPlaceholder(entry.second, knownSuccessor); + result.insert(result.end(), childResult.begin(), childResult.end()); + } + } + + break; + } + + return result; +} + +AttachmentsContainerDefault>* +VersionsGraph::representAsAttachments() const { + AttachmentsContainerDefault>* container = new AttachmentsContainerDefault>(); + + std::map> containerData; + + for(const auto& entry: __inferiors){ + if(entry.first.flagEndOfLifePlaceholder == PLACEHOLDER) continue; + + list& infs = containerData[entry.first.symbol]; + list&& infsExpanded = expandPlaceholder(entry.second, entry.first.symbol); + infs.insert(infs.begin(), infsExpanded.begin(), infsExpanded.end()); + } + + for(const auto& entry: containerData){ + container->put(entry.first, entry.second); + } + + return container; +} + std::list -VersionsPass::process(const Expression& expression, PassContext context, const std::string& varDecl = ""){ +VersionsPass::process(const Expression& expression, PassContext context, const std::string& hintSymbol){ if (expression.__state == Expression::COMPOUND){ std::list resultDependencies; for (const Expression &op: expression.getOperands()) { std::list deps = process(op, context); - resultDependencies.insert(std::inserter(resultDependencies, resultDependencies.end()), - deps.begin(), deps.end()); + resultDependencies.insert(resultDependencies.end(), deps.begin(), deps.end()); } for (CodeScope* scope: expression.blocks) { - std::list deps = process(scope, context); + std::list deps = Parent::process(scope, context); - resultDependencies.insert(std::inserter(resultDependencies, resultDependencies.end()), - deps.begin(), deps.end()); + resultDependencies.insert(resultDependencies.end(), deps.begin(), deps.end()); } return resultDependencies; } if (expression.__state == Expression::IDENT){ const Symbol symb = Attachments::get(expression); - processSymbol(symb, context, expression.getValueString()); - return {symb}; + return processSymbol(symb, context, expression.getValueString()); } return {}; } -void +//TODO versions, check (declaration.isDefined()) before processing declaration +list VersionsPass::processSymbol(const Symbol& symbol, PassContext context, const std::string& hintSymbol){ + list result{symbol}; + + if (__symbolsVisited.exists(symbol)){ + return result; + } enum {MODE_ALIAS, MODE_COPY } mode = MODE_ALIAS; - const Expression& declaration = CodeScope::findDeclaration(symbol); + const Expression& declaration = CodeScope::getDeclaration(symbol); if (declaration.op == Operator::CALL_INTRINSIC){ if (declaration.getValueString() == "copy"){ mode = MODE_COPY; } } if (symbol.identifier.version != VERSION_NONE){ mode = MODE_COPY; + + if (symbol.identifier.version > 0){ + Symbol versionPrev = Symbol{ScopedSymbol{symbol.identifier.id, symbol.identifier.version-1}, symbol.scope}; + __graph.defineEndOfLife(versionPrev, symbol); + } } - std::list dependencies = process(declaration); + PassContext context2 = context.updateScope(symbol.scope); + std::list dependencies = process(declaration, context2, hintSymbol); switch (mode) { - case MODE_COPY: applyDependentUpperBound(left, dependencies); break; - case MODE_ALIAS: applyDependentUpperBound(left.getNextVersion(), dependencies); break; + case MODE_COPY: __graph.applyDependentEndOfLife(SymbolOrPlaceholder{SYMBOL, symbol}, dependencies); break; + case MODE_ALIAS: __graph.applyDependentEndOfLife(__graph.getEndOfLife(symbol), dependencies); break; } + + __graph.applyNatualDependencies(symbol, dependencies); + __symbolsVisited.put(symbol, true); + return list{symbol}; +} + +VersionsGraph& +VersionsPass::getResultGraph(){ + return __graph; +} + +void +VersionsPass::finish(){ + assert(__graph.validate() && "Can't validate versions graph"); + + Attachments::init(__graph.representAsAttachments()); } } \ No newline at end of file diff --git a/cpp/src/pass/versionspass.h b/cpp/src/pass/versionspass.h index 2b7efeb..e13c62b 100644 --- a/cpp/src/pass/versionspass.h +++ b/cpp/src/pass/versionspass.h @@ -1,18 +1,115 @@ /* * File: versionspass.h * Author: v.melnychenko@xreate.org * * Created on January 4, 2017, 3:09 PM */ #ifndef VERSIONSPASS_H #define VERSIONSPASS_H +#include "pass/abstractpass.h" +#include +#include + namespace xreate { - class VersionsPass: public AbstractPass { - void process(const Expression& expression, PassContext context, const std::string& varDecl="") override; + + enum PlaceholderFlag {SYMBOL, PLACEHOLDER}; + + struct SymbolOrPlaceholder { + PlaceholderFlag flagEndOfLifePlaceholder; + Symbol symbol; + }; + + +} namespace std { + + template<> + struct hash{ + std::size_t operator()(xreate::SymbolOrPlaceholder const& s) const; }; -} + + template<> + struct equal_to{ + bool operator()(const xreate::SymbolOrPlaceholder& __x, const xreate::SymbolOrPlaceholder& __y) const; + }; + + template<> + struct hash{ + size_t operator()(xreate::Symbol const& s) const; + }; + + template<> + struct equal_to{ + bool operator()(const xreate::Symbol& __x, const xreate::Symbol& __y) const; + }; + +} namespace xreate { + +struct VersionImposedDependency{}; + +template<> +struct AttachmentsDict +{ + typedef std::list Data; + static const unsigned int key = 8; +}; + +class VersionsGraph{ + public: + //processing API: + void applyNatualDependencies(const Symbol& symbol, const std::list& dependencies); + void applyDependentEndOfLife(const SymbolOrPlaceholder& symbol, const std::list& dependencies); + + void defineEndOfLife(const Symbol& symbol, const Symbol& symbolSuccessor); + SymbolOrPlaceholder getEndOfLife(const Symbol& s); + + bool validate(); + + //examination API: + AttachmentsContainerDefault>* representAsAttachments() const; + void __debug_print(std::ostream& output) const; + + private: + typedef std::unordered_map Path; + + std::unordered_multimap __inferiorsNatural; + std::unordered_multimap __inferiors; + std::unordered_map __dictSuccessors; + + std::list expandPlaceholder(const SymbolOrPlaceholder& symbol, const Symbol& symbolPrev) const; + std::list extractCycle(const Path& path, const SymbolOrPlaceholder& symbolBeginning); + bool tryEliminateEofAliases(const std::list& aliases); + bool validateCycles(); + bool validateCycles(const SymbolOrPlaceholder& s, + std::unordered_multimap& graph, + std::unordered_set& symbolsVisited, + Path& path); +}; + +template<> +std::list +defaultValue>(); + +class VersionsPass: public AbstractPass> { + typedef AbstractPass> Parent; + +public: + VersionsPass(PassManager* manager): AbstractPass>(manager){} + std::list process(const Expression& expression, PassContext context, const std::string& hintSymbol="") override; + VersionsGraph& getResultGraph(); + virtual void finish(); + +protected: + std::list processSymbol(const Symbol& symbol, PassContext context, const std::string& hintSymbol="") override; + +private: + VersionsGraph __graph; + + AttachmentsContainerDefault __symbolsVisited; +}; + +} //end of xreate #endif /* VERSIONSPASS_H */ diff --git a/cpp/src/passmanager.cpp b/cpp/src/passmanager-bare.cpp similarity index 63% rename from cpp/src/passmanager.cpp rename to cpp/src/passmanager-bare.cpp index ccc9338..48c2715 100644 --- a/cpp/src/passmanager.cpp +++ b/cpp/src/passmanager-bare.cpp @@ -1,120 +1,84 @@ -#include -#include -#include "query/containers.h" -#include "passmanager.h" -#include "pass/compilepass.h" -#include "pass/adhocpass.h" +#include "passmanager.h" +#include #include "Parser.h" -#include "pass/cfapass.h" -#include "pass/dfapass.h" +#include "clasplayer.h" + #include #include using namespace xreate; using namespace std; PassManager* PassManager::prepareForCode(std::string&& code){ Scanner scanner(reinterpret_cast(code.c_str()), code.size()); return prepareForCode(&scanner); } PassManager* PassManager::prepareForCode(FILE* code){ Scanner scanner(code); return prepareForCode(&scanner); } PassManager* PassManager::prepareForCode(Scanner* code){ Parser parser(code); parser.Parse(); assert(!parser.errors->count && "Parser errors"); PassManager* man = new PassManager; AST* ast = new AST(parser.root); man->root = ast; man->clasp = new ClaspLayer(); man->clasp->ast = man->root; man->llvm = new LLVMLayer(man->root); - CompilePass::prepareQueries(man->clasp); return man; } void PassManager::registerPass(AbstractPassBase* pass, const PassId& id, AbstractPassBase* parent) { __passes.emplace(id, pass); __passDependencies.emplace(parent, pass); } AbstractPassBase* PassManager::getPassById(const PassId& id){ assert(__passes.count(id)); return __passes[id]; } bool PassManager::isPassRegistered(const PassId& id){ return __passes.count(id); } void PassManager::executePasses(){ std::list passes{nullptr}; while (passes.size()){ AbstractPassBase* parent = passes.front(); auto range = __passDependencies.equal_range(parent); for (auto i=range.first; i!=range.second; ++i){ AbstractPassBase* pass = i->second; pass->run(); pass->finish(); passes.push_back(pass); } passes.pop_front(); } } -void* -PassManager::run() -{ - runWithoutCompilation(); - CompilePass* compiler = new CompilePass(this); - compiler->run(); - - //Compiler Dependents: - LoggerPass* logger = new LoggerPass(this); - logger->initDependencies(compiler); - logger->run(); - - llvm->print(); - llvm->initJit(); - return llvm->getFunctionPointer(compiler->getEntryFunction()); -} - -void PassManager::runWithoutCompilation(){ - if (flagIsProcessed) return; - - CFAPass* passCFG = new CFAPass(this); - - //TODO is it really DFGPass needs CFGpass? - this->registerPass(new DFAPass(this), PassId::DFGPass, passCFG); - this->registerPass(passCFG, PassId::CFGPass); - this->registerPass(new AdhocPass(this), PassId::AdhocPass); - - this->executePasses(); - clasp->run(); - flagIsProcessed = true; -} PassManager::~PassManager(){} diff --git a/cpp/src/passmanager-full.cpp b/cpp/src/passmanager-full.cpp new file mode 100644 index 0000000..5bb70b2 --- /dev/null +++ b/cpp/src/passmanager-full.cpp @@ -0,0 +1,49 @@ +/* + * passmanager-full.cpp + * + * Author: Volodymyr Melnychenko + * Created on January 27, 2017, 7:10 PM + */ + +#include "passmanager.h" +#include "llvmlayer.h" +#include "pass/compilepass.h" +#include "pass/adhocpass.h" +#include "pass/cfapass.h" +#include "pass/dfapass.h" +#include "pass/interpretationpass.h" +#include "pass/versionspass.h" + +using namespace xreate; + +void PassManager::runWithoutCompilation(){ + if (flagIsProcessed) return; + + CFAPass* passCFG = new CFAPass(this); + + //TODO is it really DFGPass needs CFGpass? + this->registerPass(new DFAPass(this), PassId::DFGPass, passCFG); + this->registerPass(passCFG, PassId::CFGPass); + this->registerPass(new AdhocPass(this), PassId::AdhocPass); + this->registerPass(new InterpretationPass(this), PassId::InterpretationPass); + this->registerPass(new VersionsPass(this), PassId::VersionsPass); + + this->executePasses(); + + CompilePass::prepareQueries(clasp); + clasp->run(); + flagIsProcessed = true; +} + +void* +PassManager::run() +{ + runWithoutCompilation(); + + CompilePass* compiler = new CompilePass(this); + compiler->run(); + + llvm->print(); + llvm->initJit(); + return llvm->getFunctionPointer(compiler->getEntryFunction()); +} \ No newline at end of file diff --git a/cpp/src/passmanager.h b/cpp/src/passmanager.h index cb55967..0e67ba0 100644 --- a/cpp/src/passmanager.h +++ b/cpp/src/passmanager.h @@ -1,56 +1,57 @@ #ifndef PASSMANAGER_H #define PASSMANAGER_H #include #include //stdio external struct _IO_FILE; typedef struct _IO_FILE FILE; class Scanner; namespace xreate { class AbstractPassBase; class ClaspLayer; class LLVMLayer; class AST; enum class PassId { CFGPass, CompilePass, DFGPass, EnvironmentTestsPass, LoggerPass, AdhocPass, RulesPass, - InterpretationPass + InterpretationPass, + VersionsPass }; class PassManager { public: ~PassManager(); void*run(); void runWithoutCompilation(); void executePasses(); void registerPass(AbstractPassBase* pass, const PassId& id, AbstractPassBase* prerequisite=nullptr); AbstractPassBase* getPassById(const PassId& id); bool isPassRegistered(const PassId& id); static PassManager* prepareForCode(std::string&& code); static PassManager* prepareForCode(FILE* code); ClaspLayer* clasp; LLVMLayer* llvm; AST* root; private: //typedef std::multimap FILTERS_STORAGE; //FILTERS_STORAGE __filters; std::map __passes; std::multimap __passDependencies; bool flagIsProcessed = false; static PassManager* prepareForCode(Scanner* code); }; } #endif diff --git a/cpp/src/query/containers.cpp b/cpp/src/query/containers.cpp index 78b1321..d7dde42 100644 --- a/cpp/src/query/containers.cpp +++ b/cpp/src/query/containers.cpp @@ -1,167 +1,165 @@ // // Created by pgess on 3/14/15. // #include #include "query/containers.h" using namespace std; using namespace xreate::containers; using namespace xreate; Implementation Query::queryImplementation(xreate::Symbol const &s) { - typedef Attachments attach; - - if (attach::exists(s)) + if (Attachments::exists(s)) { - return attach::get(s); + return Attachments::get(s); } return Implementation::create(s); } Query::Query(){ Attachments::init(); } void Query::init(ClaspLayer* clasp) { if (flagIsDataLoaded) return; map prototypes; map roots; //read all proto data auto range = clasp->query(Config::get("containers.id.prototypes")); if (range) for(ClaspLayer::ModelIterator atom = range->first; atom != range->second; ++atom) { auto data = ClaspLayer::parse(atom->second); Symbol root = clasp->unpack(get<0> (data)); Symbol prototype = clasp->unpack(get<1> (data)); prototypes[root] = prototype; } // fill implementation data for a data sources: range = clasp->query(Config::get("containers.id.implementations")); if (range) for(ClaspLayer::ModelIterator atom = range->first; atom != range->second; ++atom) { auto data = ClaspLayer::parse(atom->second); Symbol var = clasp->unpack(get<0>(data)); string implSerialized = get<1>(data); //data source, has no prototypes: if (!prototypes.count(var)) { Implementation impl = Implementation::create(var); Attachments::put(var, move(impl)); continue; } roots.emplace(move(var), move(implSerialized)); } //fill implementation data for a cluster roots for (const pair & root: roots) { Symbol prototype = prototypes[root.first]; while (prototypes.count(prototype)) { prototype = prototypes.at(prototype); } Attachments::put(root.first, Implementation(Attachments::get(prototype))); } // read cluster data and fill implementation data for cluster members range = clasp->query(Config::get("containers.id.clusters")); if (range) for(ClaspLayer::ModelIterator atom = range->first; atom != range->second; ++atom) { auto info = ClaspLayer::parse(atom->second); Symbol root = clasp->unpack(get<0>(info)); Symbol child = clasp->unpack(get<1>(info)); if (!(child == root)) { Implementation rootImpl = Attachments::get(root); Attachments::put(child, move(rootImpl)); } } flagIsDataLoaded = true; } //static ImplementationData* create(Symbol var, std::string implSerialized, const ImplementationData* implPrototype); Implementation Implementation::create(const Symbol &var) { //TODO review implementation determination strategy - Expression varDecl = CodeScope::findDeclaration(var); + Expression varDecl = CodeScope::getDeclaration(var); switch (varDecl.op) { case Operator::LIST_RANGE: { ImplementationRec rec{var}; return {ON_THE_FLY, rec}; } case Operator::LIST: { return {SOLID, ImplementationRec {varDecl.getOperands().size()}}; } default: break; }; ImplementationLinkedList ill(var); if (ill){ return ill.getImplementationData(); } assert(false && "Unable to determine proper implementation for the symbol"); } Implementation Implementation::create(const Symbol& var, const std::string& implSerialized) { - Expression varDecl = CodeScope::findDeclaration(var); + Expression varDecl = CodeScope::getDeclaration(var); if (implSerialized == Config::get("containers.impl.solid")) { return {SOLID, ImplementationRec{varDecl.operands.size()}}; } else if (implSerialized == Config::get("containers.impl.onthefly")) { return {ON_THE_FLY, ImplementationRec{var}}; } assert(false && "unable to determine proper implementation for the symbol"); } ImplementationLinkedList::ImplementationLinkedList(const Symbol& source) : flagIsValid(false), s(source){ - const Expression& sourceExpr = CodeScope::findDeclaration(source); + const Expression& sourceExpr = CodeScope::getDeclaration(source); if (sourceExpr.tags.count(Config::get("containers.id.linkedlist"))){ flagIsValid = true; Expression tagLinkedlist = sourceExpr.tags.at(Config::get("containers.id.linkedlist")); assert(tagLinkedlist.operands.size() == 2); fieldPointer = tagLinkedlist.operands.at(0).getValueString(); terminator = tagLinkedlist.operands.at(1); } } ImplementationLinkedList:: operator bool () const{ return flagIsValid; } Implementation ImplementationLinkedList::getImplementationData() const { return {ON_THE_FLY, ImplementationRec{s}}; } diff --git a/cpp/src/utils.cpp b/cpp/src/utils.cpp index 693a00e..134ea62 100644 --- a/cpp/src/utils.cpp +++ b/cpp/src/utils.cpp @@ -1,9 +1,24 @@ #include "utils.h" +#include using namespace xreate; Config Config::__self = Config(); Config::Config() : __storage{json_file{ "config/default.json" }} {} + +using boost::locale::conv::utf_to_utf; + +std::wstring +utf8_to_wstring(const std::string& str) +{ + return utf_to_utf(str.c_str(), str.c_str() + str.size()); +} + +std::string +wstring_to_utf8(const std::wstring& str) +{ + return utf_to_utf(str.c_str(), str.c_str() + str.size()); +} \ No newline at end of file diff --git a/cpp/src/utils.h b/cpp/src/utils.h index a2f9b28..95bb82a 100644 --- a/cpp/src/utils.h +++ b/cpp/src/utils.h @@ -1,134 +1,159 @@ #ifndef UTILS_H #define UTILS_H #include "jeayeson/jeayeson.hpp" //TODO use type mark to mark dirty/mutable members /* template struct DdesctructableClass { } */ /* template struct TagUpdatable{ TagUpdatable(const OriginalType& source) : __source(source) {} TagUpdatable() = delete; const OriginalType& __source; }; struct Updatable; template struct TagsDictionary {}; template struct TagsDictionary { typedef TagUpdatable TagName; }; template struct awareOf { awareOf(OT& dest) : __dest(dest) {} awareOf& operator= (const typename TagsDictionary::TagName& source) { __dest = source.__source; } private: OT& __dest; }; template> const OT& awareOf(const Tag& holder) { return std::forward(holder.__source); } */ namespace xreate { template struct AddTag { explicit AddTag(const Source &src) : __src(src) { } explicit AddTag(Source &&src) : __src(std::move(src)) { } operator const Source&() const{ return __src; } const Source& get() const{ return __src; } const Source* operator->() const { return &__src; } private: Source __src; }; struct Expand_t{}; template using Expanded = AddTag; //DEBT move to resources compiler. https://github.com/markusfisch/cpprc class Config { private: json_map __storage; static Config __self; Config(); public: static std::string get(std::string key) { return __self.__storage.get_for_path(key).get(); } }; + + /** + * Decorators support + */ + template + struct DecoratorsDict{ + //typedef ConcreteDecoratorForTag result; + }; + + template + struct Decorators{ + typedef typename DecoratorsDict::result Instance; + + template + static Instance* getInterface(Base* obj){ + return dynamic_cast< Instance* > (obj); + } + }; } +std::wstring +utf8_to_wstring(const std::string& str); + +std::string +wstring_to_utf8(const std::wstring& str); + + #define RST "\x1B[0m" #define KRED "\x1B[31m" #define KGRN "\x1B[32m" #define KYEL "\x1B[33m" #define KBLU "\x1B[34m" #define KMAG "\x1B[35m" #define KCYN "\x1B[36m" #define KWHT "\x1B[37m" #define FRED(x) KRED << x << RST #define FGRN(x) KGRN <) # TESTS #========================= FIND_PACKAGE (LLVM REQUIRED) message("LLVM_LIBRARY_DIRS: " ${LLVM_LIBRARY_DIRS}) link_directories(${LLVM_LIBRARY_DIRS}) set (LIBCLASP_PATH ${POTASSCO_PATH}/build/debug) link_directories(${LIBCLASP_PATH}) #aux_source_directory(. TEST_FILES) set(TEST_FILES main.cpp + adhoc.cpp + attachments.cpp + ast.cpp + cfa.cpp + dfa.cpp + compilation.cpp + ExpressionSerializer.cpp + externc.cpp + context.cpp + types.cpp + vendorAPI/clangAPI.cpp + vendorAPI/xml2.cpp + vendorAPI/json.cpp + + containers.cpp + context.cpp + interpretation.cpp + loops.cpp + #supplemental/versions-algorithm-data_dependency.cpp effects-versions.cpp ) add_executable(${PROJECT_NAME} ${TEST_FILES}) target_link_libraries(${PROJECT_NAME} xreate ${GTEST_LIBRARIES} pthread xml2 gcov) add_custom_target (coverage COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/src/code-coverage.sh WORKING_DIRECTORY ${CMAKE_BINARY_DIR}) diff --git a/cpp/tests/adhoc.cpp b/cpp/tests/adhoc.cpp index eb9bafb..80d9ec5 100644 --- a/cpp/tests/adhoc.cpp +++ b/cpp/tests/adhoc.cpp @@ -1,160 +1,195 @@ /* * 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; +#define FRIENDS_ADHOC \ + friend class ::Adhoc_pass_Adhoc1_Test; #include "ast.h" #include "passmanager.h" #include "gtest/gtest.h" #include #include #include #include #include "pass/adhocpass.h" #include "pass/compilepass.h" #include "llvmlayer.h" using namespace xreate; using namespace std; TEST(Adhoc, ast_operatorAdhoc1){ - PassManager* man = PassManager::prepareForCode ( - " test = " - "function:: int {\n" - " ad hoc Exception(NonImplemented)\n" - " }" - ); - - Expression subject = man->root->findFunction("test")->getEntryScope()->getBody(); - ASSERT_EQ(Operator::ADHOC, subject.op); - ASSERT_EQ(1, subject.getOperands().size()); - - Expression exception = subject.getOperands()[0]; - ASSERT_EQ("Exception", exception.getValueString()); + PassManager* man = PassManager::prepareForCode ( + "test = function:: int {\n" + " ad hoc exception(nonImplemented)\n" + "}"); + + Expression subject = man->root->findFunction("test")->getEntryScope()->getBody(); + ASSERT_EQ(Operator::ADHOC, subject.op); + + Expression exception = AdhocExpression(subject).getCommand(); + 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); + 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()); + 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->getName()); } 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); + PassManager* man = PassManager::prepareForCode ( + " import raw (\"core/control-context.lp\")\n" + + " interface(adhoc){\n" + " pre function expectNoErrors:: bool {\n" + " case (error) {false}\n" + " case (success) {true}\n" + " }\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_2){ + PassManager* man = PassManager::prepareForCode ( + " import raw (\"core/control-context.lp\")\n" + + " interface(adhoc){\n" + " pre function expectNoErrors:: bool {\n" + " case (error) {false}\n" + " case (success) {true}\n" + " }\n" + + " pre function expectErrors:: bool {\n" + " case (error) {true}\n" + " case (success) {false}\n" + " }\n" + + " }\n" + + " test1 = pre function {\n" + " context:: expectNoErrors." + " ad hoc success\n" + " }\n" + + " test2 = pre function {\n" + " context:: expectErrors." + " ad hoc success\n" + " }" + + "main = function::bool;entry {\n" + " test1() != test2()\n" + "}"); + + bool (*main)() = (bool (*)()) man->run(); + bool result = main(); + ASSERT_EQ(true, result); } +//TODO adhoc type. FDecl sets wrong type in prefunc case(invalid type)) TEST(Adhoc, full_contextExpectNoErrrors){ - PassManager* man = PassManager::prepareForCode ( - "import raw (\"core/control-context.lp\")\n" - - "interface(extern-c){\n" - " xml2 = library:: pkgconfig(\"libxml-2.0\").\n" - " \n" - " include {\n" - " xml2 = [\"stdlib.h\"]\n" - " }.\n" - "}" - - "interface(adhoc){\n" - " pre function expectNoErrors:: bool {\n" - " case Error {0}\n" - " case Success {1}\n" - " }\n" - "}\n" - - "expectErrorCode = pre function(x::int){\n" - " if (x==0)::bool {ad hoc \"Success\"}\n" - " else {ad hoc \"Error\"}\n" - "}\n" - - "main = function::bool; entry {\n" - " context:: expectNoErrors." - " expectErrorCode(system(\"ls -la\"))\n" - "}" ); - - int (*main)() = (int (*)()) man->run(); - ASSERT_EQ(1, main()); + PassManager* man = PassManager::prepareForCode ( + "import raw (\"core/control-context.lp\")\n" + + "interface(extern-c){\n" + " xml2 = library:: pkgconfig(\"libxml-2.0\").\n" + " \n" + " include {\n" + " xml2 = [\"stdlib.h\"]\n" + " }.\n" + "}" + + "interface(adhoc){\n" + " pre function expectNoErrors:: bool {\n" + " case (error) {false}\n" + " case (success) {true}\n" + " }\n" + "}\n" + + "expectErrorCode = pre function(x::int){\n" + " if (x==0)::undef {ad hoc success}\n" + " else {ad hoc error}\n" + "}\n" + + "main = function::bool; entry {\n" + " context:: expectNoErrors." + " expectErrorCode(system(\"ls -la\"))\n" + "}" ); + + int (*main)() = (int (*)()) man->run(); + ASSERT_EQ(1, main()); } TEST(Adhoc, ast_switchAdhoc1){ - PassManager* man = PassManager::prepareForCode ( - "test1 = function:: bool {\n" - " switch ad hoc (x:: errors)\n" - " case ERROR {0}\n" - " case SUCCESS {1}\n" - " \n" - " }" - ); - - Expression eSwitch = man->root->findFunction("test1")->getEntryScope()->getBody(); - EXPECT_EQ(Operator::SWITCH_ADHOC, eSwitch.op); - EXPECT_EQ(3, eSwitch.operands.size()); - - EXPECT_EQ(1, eSwitch.tags.size()); - EXPECT_EQ("errors", eSwitch.tags.begin()->first); - - Expression eCondition = eSwitch.getOperands()[0]; - EXPECT_EQ("x", eCondition.getValueString()); + PassManager* man = PassManager::prepareForCode ( + "test1 = function:: bool {\n" + " x = 0. \n" + " switch ad hoc (x:: errors)\n" + " case (error) {0}\n" + " case (success) {1}\n" + "\n" + "}" + ); + + Expression eSwitch = man->root->findFunction("test1")->getEntryScope()->getBody(); + EXPECT_EQ(Operator::SWITCH_ADHOC, eSwitch.op); + EXPECT_EQ(3, eSwitch.operands.size()); + + EXPECT_EQ(1, eSwitch.tags.size()); + EXPECT_EQ("errors", eSwitch.tags.begin()->first); + + Expression eCondition = eSwitch.getOperands()[0]; + EXPECT_EQ("x", eCondition.getValueString()); } diff --git a/cpp/tests/ast.cpp b/cpp/tests/ast.cpp index 46c637d..144a1f6 100644 --- a/cpp/tests/ast.cpp +++ b/cpp/tests/ast.cpp @@ -1,48 +1,68 @@ /* * 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"); 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, syntax_recognizeIdentifiers){ + PassManager* man = PassManager::prepareForCode(R"Code( + test= function(a:: num):: num; entry { + a = b:: int. + b = 8:: int. + + a + } + )Code"); +} + +TEST(AST, syntax_operatorIndex){ + PassManager* man = PassManager::prepareForCode(R"Code( + test= function(a:: num):: num; entry { + b = a[1]. + b + } + )Code"); +} + TEST(AST, DISABLED_InterfacesDataDFA){ } TEST(AST, DISABLED_InterfacesDataExtern){ } //TODO xreate.atg: replace all Type<> as ExprAnnotations<> diff --git a/cpp/tests/attachments.cpp b/cpp/tests/attachments.cpp new file mode 100644 index 0000000..54b8bba --- /dev/null +++ b/cpp/tests/attachments.cpp @@ -0,0 +1,26 @@ +/* + * attachments.cpp + * + * Author: pgess + * Created on January 22, 2017, 12:16 PM + */ + + + +#include "attachments.h" +#include "ast.h" + +#include "gtest/gtest.h" + +using namespace xreate; + +TEST(Attachments, basic1){ + AttachmentsContainerDefault* c = new AttachmentsContainerDefault(); + + Expression expTest(Atom(10)); + c->put(expTest, true); + + Expression expTest2(Atom(11)); + + ASSERT_FALSE(c->exists(expTest2)); +} \ No newline at end of file diff --git a/cpp/tests/basic.cpp b/cpp/tests/basic.cpp deleted file mode 100644 index 0deb63b..0000000 --- a/cpp/tests/basic.cpp +++ /dev/null @@ -1,26 +0,0 @@ - -#include "gtest/gtest.h" -#include "passmanager.h" -#include "Scanner.h" -#include "Parser.h" -#include -#include - -using namespace std; -using namespace xreate; - -TEST(Basic, functionEntry1){ - std::unique_ptr program(PassManager::prepareForCode( - "func1 = function(a:: int):: int {a+8} \ - func2 = function::int; entry {12 + func1(4)} \ - ")); - - void* entryPtr = program->run(); - int (*entry)() = (int (*)())(intptr_t)entryPtr; - - int answer = entry(); - ASSERT_EQ(24, answer); -} - - - diff --git a/cpp/tests/cfa.cpp b/cpp/tests/cfa.cpp index f01028c..42f7c4f 100644 --- a/cpp/tests/cfa.cpp +++ b/cpp/tests/cfa.cpp @@ -1,119 +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(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(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(); 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(); + const Expression& exprSum = scopeEntry->getDeclaration(scopeEntry->getSymbol("sum")); + CodeScope* scopeExpected = exprSum.blocks.front(); ScopePacked scopeIdExpected = man->clasp->pack(scopeExpected); ASSERT_EQ(scopeIdExpected, scopeIdActual); } TEST(CFA, CFGRoots){ std::string program = R"CODE( main = function::int{a()+ b()} a= function::int {c1() + c2()} b= function::int {c2()} c1=function::int{0} c2=function::int{0} )CODE"; 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 e5371df..95b96b6 100644 --- a/cpp/tests/compilation.cpp +++ b/cpp/tests/compilation.cpp @@ -1,80 +1,37 @@ #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){ } -TEST(Compilation, Sequence1){ - PassManager* man = PassManager::prepareForCode( - "interface(extern-c){\n" - " libFake = library:: pkgconfig(\"libxml-2.0\").\n" - " \n" - " include {\n" - " libFake = [\"stdio.h\", \"stdlib.h\"]\n" - " }.\n" - "}" - - "main = function:: int; entry {\n" - " sequence [" - " printf(\"FIRST-\"),\n" - " printf(\">SECOND\")\n" - " ]" - "}" - ); - - int (*main)() = (int (*)()) man->run(); - - testing::internal::CaptureStdout(); - main(); - std::string output = testing::internal::GetCapturedStdout(); - - ASSERT_STREQ("FIRST->SECOND", output.c_str()); -} - -TEST(Compilation, 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" - "}" +TEST(Compilation, functionEntry1){ + std::unique_ptr program(PassManager::prepareForCode( + "func1 = function(a:: int):: int {a+8} \ + func2 = function::int; entry {12 + func1(4)} \ + ")); - "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" - "]" - "}" - ); + void* entryPtr = program->run(); + int (*entry)() = (int (*)())(intptr_t)entryPtr; - int (*main)() = (int (*)()) man->run(); - main(); + int answer = entry(); + ASSERT_EQ(24, answer); } - TEST(Compilation, full_IFStatementWithVariantType){ PassManager* man = PassManager::prepareForCode( - "COLORS = type variant (RED, BLUE, GREEN).\n" + "Color = 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" + " main = function(x::int):: bool; entry {\n" + " color = if (x == 0 )::Color {RED} else {BLUE}.\n" + " if (color == BLUE)::bool {true} else {false}\n" " }" ); - int (*main)(int) = (int (*)(int)) man->run(); - ASSERT_EQ(0, main(0)); - ASSERT_EQ(1, main(1)); + bool (*main)(int) = (bool (*)(int)) man->run(); + ASSERT_FALSE(main(0)); + ASSERT_TRUE(main(1)); } - diff --git a/cpp/tests/containers.cpp b/cpp/tests/containers.cpp index 731da87..ba9d06c 100644 --- a/cpp/tests/containers.cpp +++ b/cpp/tests/containers.cpp @@ -1,96 +1,96 @@ /* * 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, ListAsArray){ PassManager* man = PassManager::prepareForCode( R"Code( main = function(x:: int):: int;entry { a = [1, 2, 3]:: [int]. a[x] } )Code" ); void* mainPtr = man->run(); int (*main)(int) = (int (*)(int))mainPtr; ASSERT_EQ(2, main(1)); delete man; } TEST(Containers, ListAsArray2){ PassManager* man = PassManager::prepareForCode( R"Code( main = function:: int;entry { a= [1, 2, 3]:: [int]. b= loop map(a->el:: int):: [int]{ 2 * el }. sum = loop fold(b->el:: int, 0->acc):: int { acc + el }. sum } )Code" ); void* mainPtr = man->run(); int (*main)() = (int (*)())mainPtr; ASSERT_EQ(0, main()); delete man; } 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"); + const Symbol symb_chilrenRaw{body->getSymbol("childrenRaw"), body}; containers::ImplementationLinkedList iLL(symb_chilrenRaw); ASSERT_EQ(true, static_cast(iLL)); ASSERT_EQ("next", iLL.fieldPointer); Implementation impl = Implementation::create(symb_chilrenRaw); ASSERT_NO_FATAL_FAILURE(impl.extract()); ImplementationRec recOnthefly = impl.extract(); ASSERT_EQ(symb_chilrenRaw, recOnthefly.source); } TEST(Containers, Implementation_LinkedListFull){ FILE* input = fopen("scripts/testspass/Containers_Implementation_LinkedList1.xreate","r"); 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(17, answer); fclose(input); } diff --git a/cpp/tests/context.cpp b/cpp/tests/context.cpp index 847dab1..796fee1 100644 --- a/cpp/tests/context.cpp +++ b/cpp/tests/context.cpp @@ -1,495 +1,496 @@ /* * frame-context.cpp * * Created on: Dec 3, 2015 * Author: pgess */ #include "passmanager.h" #include "query/context.h" #include "gtest/gtest.h" #include #include using namespace xreate; TEST(Context, frame_Context1){ PassManager* man = PassManager::prepareForCode( " import raw (\"core/control-context.lp\")\n" " compute = function::int {\n" " 0\n" " }\n" " computeFast = function:: int {\n" " context:: computation(fast).\n" " compute()\n" " }\n" " computePrecisely = function:: int {\n" " context:: computation(precise). \n" " compute()\n" " }\n" "test = function(cmnd:: int):: int; entry {\n" " context:: arithmetic(iee754). \n" " if (cmnd > 0)::int {computePrecisely()} else {computeFast()} \n" "}\n" ); ContextQuery* query = (ContextQuery*) man->clasp->registerQuery(new ContextQuery(), QueryId::ContextQuery); man->runWithoutCompilation(); CodeScope* scopeTestC = man->root->findFunction("compute")->getEntryScope(); const Domain& context = query->getContext(man->clasp->pack(scopeTestC)); int contextSize = context.size(); EXPECT_EQ(1, contextSize); //arithmetic(iee754) } TEST(Context, contextAsRequirementSuccessful1){ PassManager* man = PassManager::prepareForCode( " import raw (\"core/control-context.lp\")\n" " case context::safe {\n" " funcSensitive = function::int {\n" " 0\n" " }}\n" " test = function:: int; entry {\n" " context:: safe; test.\n" " funcSensitive()\n" " }\n" ); int (*main)() = (int (*)()) man->run(); ASSERT_EQ(0, main()); } TEST(Context, contextAsRequirementFailed){ PassManager* man = PassManager::prepareForCode( " import raw (\"core/control-context.lp\")\n" " case context::safe {\n" " funcSensitive = function::int {\n" " 0\n" " }}\n" " test = function:: int; entry {\n" " context:: non_safe; test.\n" " funcSensitive()\n" " }\n" ); ASSERT_DEATH(man->run(), "findFunction"); } TEST(Context, ContextPropagationNested){ PassManager* man = PassManager::prepareForCode( " import raw (\"core/control-context.lp\")\n" " case context::safe {\n" " square = function(x:: int) ::int {\n" " x * x\n" " }}\n" " test = function:: int; entry {\n" " context:: safe; test.\n" " range = [1..10]:: [int]. \n" " loop fold(range->x::int, 0->acc):: int { \n" " acc + square(x) \n" " } \n" " }\n" ); int (*main)() = (int (*)()) man->run(); ASSERT_EQ(385, main()); } TEST(Context, ContextPropagationNestedInterfunction){ PassManager* man = PassManager::prepareForCode( " import raw (\"core/control-context.lp\")\n" " case context::toMillimeters {\n" " convertConcrete = function(source:: num)::num {\n" " 10 * source \n" " }\n" " }\n" " case context::toInches {\n" " convertConcrete = function(source:: num)::num {\n" " 2 * source \n" " }\n" " }\n" "convert= function(source:: num):: num { \n" "convertConcrete(source) \n" "} \n" "test = function(source:: num):: num; entry {\n" " context:: toMillimeters.\n" " convert(1)\n" "}\n" ); int (*main)(int) = (int (*)(int)) man->run(); ASSERT_EQ(10, main(1)); } TEST(Context, full_ContextBasedFunctionSpecialization){ PassManager* man = PassManager::prepareForCode( " import raw (\"core/control-context.lp\")\n" " case context::toMillimeters {\n" " convert = function(source:: num)::num {\n" " 10 * source \n" " }\n" " }\n" " case context::toInches {\n" " convert = function(source:: num)::num {\n" " 2 * source \n" " }\n" " }\n" "test = function(vrnt:: int)::int; entry {\n" " switch(vrnt):: int\n" - " case 0 {\n" + " case (0) {\n" " context:: toMillimeters.\n" " convert(1)\n" " }\n" "\n" - " case 1 {\n" + " case (1) {\n" " context:: toInches.\n" " convert(1)\n" " }\n" " case default {0}\n" " }" ); int (*main)(int) = (int (*)(int)) man->run(); ASSERT_EQ(10, main(0)); ASSERT_EQ(2, main(1)); } -//TOODO recover context loop and enable the test -TEST(Context, full_LoopContext){ - - PassManager* man = PassManager::prepareForCode( - " import raw (\"core/control-context.lp\")\n" - " case context:: a {\n" - " print = function:: string {\n" - " \"a\"\n" - " }}\n" - "\n" - " case context:: b {\n" - " print = function:: string {\n" - " \"b\"\n" - " }}\n" - "\n" - " case context:: c {\n" - " print = function:: string {\n" - " \"c\"\n" - " }}\n" - "\n" - " case context:: d {\n" - " print = function:: string {\n" - " \"d\"\n" - " }}\n" - "\n" - " start = function(command::int)::string; entry {\n" - " switch (command) :: string \n" - " case 0 {\n" - " context:: print(a); print(b); print(d).\n" - "\n" - " loop context (\"print\") {\n" - " print()\n" - " }\n" - " }\n" - "\n" - " case default {\n" - " context:: print(c).\n" - " loop context (\"print\") {\n" - " print()\n" - " }\n" - " }\n" - " }"); - - - char* (*main)(int) =(char* (*)(int)) man->run(); - ASSERT_STREQ("c", main(1)); - ASSERT_STREQ("a", main(0)); -} - TEST(Context, full_RuleContext){ /* "rule context:: childs(Child)\n" " case artefact(Item)\n" " {\n" " artefact_depends(Item, Child)\n" " }"; */ PassManager* man = PassManager::prepareForCode( " import raw (\"core/control-context.lp\")\n" " case context:: toMilli {\n" " convert = function(length::int)::int{\n" " 10 * length\n" " }\n" " }\n" "\n" " case context:: toCenti {\n" " convert = function(length::int)::int{\n" " length\n" " }\n" " }\n" "\n" " main=function::int; entry {\n" " context:: output(milli).\n" "\n" " rule context::toMilli\n" - " case output(milli) {true}\n" + " case (output(milli)) {truth}\n" "\n" " convert(1)\n" " }" ); - man->clasp->addRawScript("true."); + man->clasp->addRawScript("truth."); 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" +" rule context::X case (output(X)) {truth}\n" "\n" " switch (comm)::num \n" -" case 0 {\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."); + man->clasp->addRawScript("truth."); 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" + " case (0) {\n" " context:: milli.\n" " calculate(1)\n" " }\n" "\n" " case default{\n" " context:: centi. \n" " calculate(1)\n" " }\n" "}"); man->runWithoutCompilation(); ContextQuery* queryContext = reinterpret_cast(man->clasp->getQuery(QueryId::ContextQuery)); Expression exprSwitch = man->root->findFunction("main")->__entry->getBody(); CodeScope* blockDefault = man->root->findFunction("main")->__entry->getBody().operands[1].blocks.front(); ScopePacked blockDefaultId = man->clasp->pack(blockDefault); const Domain& domDefault = queryContext->getContext(blockDefaultId); ASSERT_EQ(1, domDefault.count(Expression(Atom("centi")))); std::list variants = man->root->getFunctionVariants("convert"); for (ManagedFnPtr f: variants){ const Expression guard = f->guardContext; bool result = (guard.getValueString() == "centi" || guard.getValueString() == "milli" || !guard.isValid()); ASSERT_TRUE(result); } const FunctionDemand& demMain = queryContext->getFunctionDemand("main"); ASSERT_EQ(0, demMain.size()); const FunctionDemand& demCalculate = queryContext->getFunctionDemand("calculate"); ASSERT_EQ(1, demCalculate.size()); int (*entry)(int) = (int (*)(int)) man->run(); ASSERT_EQ(1000, entry(0)); ASSERT_EQ(100, entry(1)); } TEST(Context, loopContextExists){ PassManager* man = PassManager::prepareForCode ( "import raw (\"core/control-context.lp\")\n" "interface(cfa){\n" " operator fold:: annotation1.\n" "}\n" "\n" "main = function:: int; entry {\n" " x = [1..10]:: [int].\n" " sum = loop fold (x->el:: int, 0->sum):: int {\n" " el + sum + f1()\n" " }. \n" " sum\n" "}" "case context:: annotation1 {" " f1 = function::int {\n" " x = 0:: int. " " x\n" " }" "}" ); man->run(); } TEST(Context, pathDependentContext){ std::string program = R"CODE( import raw("core/control-context.lp") convert = function(length:: num) :: num { 0 } case context:: convert(milli, meters) { convert = function(length:: num) :: num { 1000 * length } } case context:: convert(centi, meters) { convert = function(length:: num) :: num { 100 * length } } case context:: convert(centi, kilo) { convert = function(length:: num) :: num { 100000 * length } } case context:: convert(milli, kilo) { convert = function(length:: num) :: num { 1000000 * length } } main = function(value::num, unitsInput::num, unitsOutput::num)::num; entry{ switch (unitsInput)::num - case 0 { + case (0) { test_fromMilli(value, unitsOutput) } - case 1 { + case (1) { test_fromCenti(value, unitsOutput) } case default {0} } test_fromCenti = function(value::num, output::num)::num{ context:: input(centi). switch(output):: num - case 0 { + case (0) { toMeters(value) } - case 1 { + case (1) { toKilo(value) } case default {0} } test_fromMilli = function(value::num, output::num)::num{ context:: input(milli). switch(output):: num - case 0 { + case (0) { toMeters(value) } - case 1 { + case (1) { toKilo(value) } case default {0} } toMeters = function(value::num)::num { - rule context:: convert(X, meters) case input(X) {true} + rule context:: convert(X, meters) case (input(X)) {truth} doConvert(value) } toKilo = function(value::num)::num { - rule context:: convert(X, kilo) case input(X) {true} + rule context:: convert(X, kilo) case (input(X)) {truth} doConvert(value) } doConvert = function(value::num)::num{ convert(value) })CODE"; boost::scoped_ptr man(PassManager::prepareForCode(move(program))); + man->clasp->addRawScript("truth."); 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)); } +//TODO 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)); +} + diff --git a/cpp/tests/effects-versions.cpp b/cpp/tests/effects-versions.cpp index 0a5b4ba..3ca9fb4 100644 --- a/cpp/tests/effects-versions.cpp +++ b/cpp/tests/effects-versions.cpp @@ -1,75 +1,276 @@ /* * Created on: Dec 16, 2016 * Author: pgess */ +#include "pass/versionspass.h" #include "passmanager.h" #include "gtest/gtest.h" using namespace xreate; -TEST(Effects, syntax_recognizeIdentifiers){ +TEST(Effects, syntax_versions_1){ PassManager* man = PassManager::prepareForCode(R"Code( test= function(a:: num):: num; entry { - a = b:: int. - b = 8:: int. + x= b[8]. + b = 5:: num. + x{1} = a:: num. - a + x{1} + a } )Code"); } -TEST(Effects, syntax_operatorIndex){ - PassManager* man = PassManager::prepareForCode(R"Code( - test= function(a:: num):: num; entry { - b = a[1]. - b +TEST(Effects, analysis_versions_1){ + PassManager* man = PassManager::prepareForCode( + R"Code( + test= function:: num; entry { + x{0}= 3:: int. + x{1} = x{0} + 1. + + x{1} } )Code"); + + VersionsPass* pass = new VersionsPass(man); + pass->run(); + + VersionsGraph graph = pass->getResultGraph(); + ASSERT_TRUE(graph.validate()); } -TEST(Effects, syntax_versions_1){ - PassManager* man = PassManager::prepareForCode(R"Code( +TEST(Effects, analysis_versions_2){ + PassManager* man = PassManager::prepareForCode( + R"Code( test= function(a:: num):: num; entry { - x= b[8]. - b = 5:: num. - x{1} = a:: num. + x{0}= 3:: int. + b = [1, 2, x{0}]. + x{1} = b[2]. x{1} + a } )Code"); + + VersionsPass* pass = new VersionsPass(man); + pass->run(); + + VersionsGraph graph = pass->getResultGraph(); + ASSERT_TRUE(graph.validate()); } -TEST(Effects, analysis_versions_1){ - PassManager* man = PassManager::prepareForCode(R"Code( +TEST(Effects, analysis_versions_2_1_fail){ + PassManager* man = PassManager::prepareForCode( + R"Code( test= function(a:: num):: num; entry { - x= b[8]. - b = 5. - x{1} = a. + x{0}= 5:: int. + b = x{0}. + x{1} = 2. - x{1} + a + b + x{1} } )Code"); + VersionsPass* pass = new VersionsPass(man); + pass->run(); + + VersionsGraph graph = pass->getResultGraph(); + graph.__debug_print(std::cout); + ASSERT_FALSE(graph.validate()); +} - VersionsPass* pass = new VersionsPass(); +TEST(Effects, analysis_versions_2_2){ + PassManager* man = PassManager::prepareForCode( + R"Code( + test= function(a:: num):: num; entry { + x{0}= 5:: int. + b = intrinsic copy(x{0}). + x{1} = 2. + + b + x{1} + } + )Code"); + + VersionsPass* pass = new VersionsPass(man); pass->run(); - pass->finish(); + + VersionsGraph graph = pass->getResultGraph(); + graph.__debug_print(std::cout); + ASSERT_TRUE(graph.validate()); } +TEST(Effects, analysis_versions_3){ + PassManager* man = PassManager::prepareForCode( + R"Code( + test= function:: num; entry { + x{0}= 3:: int. + a = x{0}:: int. + b = a :: int. + x{1} = b. + + x{1} + } + )Code"); + + VersionsPass* pass = new VersionsPass(man); + pass->run(); + + VersionsGraph graph = pass->getResultGraph(); + graph.__debug_print(std::cout); + ASSERT_TRUE(graph.validate()); + std::cout << "========================\n"; + graph.__debug_print(std::cout); + AttachmentsContainerDefault>* attachmentsDependency = graph.representAsAttachments(); + + CodeScope* scope = man->root->findFunction("test")->getEntryScope(); + const std::list& dependenciesX1 = attachmentsDependency->get(Symbol{ScopedSymbol{1, 1}, scope}); + ASSERT_EQ(3, dependenciesX1.size()); +} + +TEST(Effects, compilation_versions_1){ + PassManager* man = PassManager::prepareForCode( + R"Code( + test= function:: num; entry { + x{1} = b. + b = a :: int. + a = x{0}:: int. + x{0}= 3:: int. + + x{1} + } + )Code"); + + man->runWithoutCompilation(); + if (!man->isPassRegistered(PassId::VersionsPass)){ + VersionsPass* pass = new VersionsPass(man); + pass->run(); + pass->finish(); + } + + int (*body)() = (int (*)())man->run(); + int answer = body(); + + ASSERT_EQ(3, answer); +} + +TEST(Effects, compilation_versions_versionInit1){ + PassManager* man = PassManager::prepareForCode( + R"Code( + test= function:: num; entry { + x{0} = 3. + + x{0} + } + )Code"); + + man->runWithoutCompilation(); + if (!man->isPassRegistered(PassId::VersionsPass)){ + VersionsPass* pass = new VersionsPass(man); + pass->run(); + pass->finish(); + } + + int (*body)() = (int (*)())man->run(); + int answer = body(); + + ASSERT_EQ(3, answer); +} + +TEST(Effects, compilation_versions_versionNext1){ + PassManager* man = PassManager::prepareForCode( + R"Code( + test= function:: num; entry { + x{0} = 5. + x{1} = x{0} - 2. + + x{1} + } + )Code"); + + man->runWithoutCompilation(); + if (!man->isPassRegistered(PassId::VersionsPass)){ + VersionsPass* pass = new VersionsPass(man); + pass->run(); + pass->finish(); + } + + int (*body)() = (int (*)())man->run(); + int answer = body(); + + ASSERT_EQ(3, answer); +} + +TEST(Effects, compilation_versions_IntrinsicCopy1){ + PassManager* man = PassManager::prepareForCode( + R"Code( + test= function:: num; entry { + x{0} = 5. + b = intrinsic copy (x{0}). + x{1} = 2. + + b - x{1} + } + )Code"); + + man->runWithoutCompilation(); + if (!man->isPassRegistered(PassId::VersionsPass)){ + VersionsPass* pass = new VersionsPass(man); + pass->run(); + pass->finish(); + } + + int (*body)() = (int (*)())man->run(); + int answer = body(); + + ASSERT_EQ(3, answer); +} + +TEST(Effects, compilation_versions_varexchange){ + PassManager* man = PassManager::prepareForCode( + R"Code( + test= function:: num; entry { + a{0} = 3. + b{0} = 5. + tmp = intrinsic copy (a{0}). + a{1} = b{0}. + b{1} = tmp. + + b{1} + } + )Code"); + + man->runWithoutCompilation(); + if (!man->isPassRegistered(PassId::VersionsPass)){ + VersionsPass* pass = new VersionsPass(man); + pass->run(); + pass->finish(); + } + + int (*body)() = (int (*)())man->run(); + int answer = body(); + + ASSERT_EQ(3, answer); +} + + + + + +/* TEST(Effects, analysis_versions_copy){ } TEST(Effects, syntax_references1){ } TEST(Effects, syntax_scope_versions1){ } TEST(Effects, DynamicVersions_analysis){ -} \ No newline at end of file +} + */ + diff --git a/cpp/tests/externc.cpp b/cpp/tests/externc.cpp index 2542a4e..b8f9536 100644 --- a/cpp/tests/externc.cpp +++ b/cpp/tests/externc.cpp @@ -1,108 +1,106 @@ #include "gtest/gtest.h" #include "passmanager.h" #include "Scanner.h" #include "Parser.h" #include #include using namespace std; TEST(InterfaceExternC, testAST) { std::string code = " \ interface(extern-c){ \ xml2 = library:: pkgconfig(\"libxml-2.0\"). \ \ include { \ xml2 = [\"libxml/tree.h\"] \ }. \ } \ "; Scanner scanner(reinterpret_cast (code.c_str()), code.size()); Parser parser(&scanner); parser.Parse(); ASSERT_EQ(1, parser.root.__externdata.size()); for (const ExternEntry& lib : parser.root.__externdata) { ASSERT_EQ("libxml-2.0", lib.package); ASSERT_EQ(1, lib.headers.size()); ASSERT_EQ("libxml/tree.h", lib.headers.at(0)); } } TEST(InterfaceExternC, testfetchPackageHeaders) { ExternEntry entry{"libxml-2.0", {}}; vector args = ExternLayer::fetchPackageFlags(entry); ASSERT_EQ(1, args.size()); ASSERT_EQ("-I/usr/include/libxml2", args.at(0)); } TEST(InterfaceExternC, testfetchPackageLibs) { ExternEntry entry{"libxml-2.0", {}}; vector args = ExternLayer::fetchPackageLibs(entry); ASSERT_EQ(1, args.size()); ASSERT_EQ("xml2", args.at(0)); } TEST(InterfaceExternC, testLoadLib) { std::string msgErr; if (!llvm::sys::DynamicLibrary::LoadLibraryPermanently("-lpcre -lxml2", &msgErr)) { cout << msgErr; ASSERT_EQ("", msgErr); } ASSERT_TRUE(true); } TEST(InterfaceExternC, testBSD1) { std::string code = " \n\ interface(extern-c){ \n\ libbsd = library:: pkgconfig(\"libbsd\"). \n\ \n\ include { \n\ libbsd = [\"bsd/stdlib.h\"] \n\ }. \n\ } \n" "main= function:: int; entry{arc4random_uniform(24) }"; std::unique_ptr program(PassManager::prepareForCode(move(code))); 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); Scanner scanner(input); Parser parser(&scanner); parser.Parse(); AST& ast = parser.root; CodeScope* body = ast.findFunction("test")->getEntryScope(); - Symbol symbTree = body->findSymbol("tree"); - - const TypeAnnotation& tTree = CodeScope::findDeclaration(symbTree).type; + const TypeAnnotation& tTree = body->getDeclaration(body->getSymbol("tree")).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/interpretation.cpp b/cpp/tests/interpretation.cpp index cfff9d1..8d0ade4 100644 --- a/cpp/tests/interpretation.cpp +++ b/cpp/tests/interpretation.cpp @@ -1,340 +1,369 @@ #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 { + main = function::bool { x = "a":: string. - y = if (x=="b"):: string; interpretation(force) { - 1 + y = if (x=="b"):: bool; interpretation(force) { + true } else { - 0 + false }. y } )Code" ); - InterpretationPass* pass; - if (man->isPassRegistered(PassId::InterpretationPass)){ - pass = (InterpretationPass*) man->getPassById(PassId::InterpretationPass); - } else { - pass = new InterpretationPass(man); - pass->run(); - } - Symbol symbolY = man->root->findFunction("main")->__entry->findSymbol("y"); + InterpretationPass* pass = new InterpretationPass(man); + pass->run(); + + CodeScope* scopeEntry = man->root->findFunction("main")->getEntryScope(); + Symbol symbolY{scopeEntry->getSymbol("y"), scopeEntry}; InterpretationData& dataSymbolY = Attachments::get(symbolY); ASSERT_EQ(INTR_ONLY, dataSymbolY.resolution); } TEST(Interpretation, Compilation_StatementIF_1){ PassManager* man = PassManager::prepareForCode( 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(x:: int):: int { - comm= "inc":: string. + comm= "inc":: string; interpretation(force). - y = if (comm == "inc") {x+1} else {x}. - y + y = if (comm == "inc")::int {x+1} else {x}. + y } -)Code" ); +)Code" ); - InterpretationPass* pass; - if (man->isPassRegistered(PassId::InterpretationPass)){ - pass = (InterpretationPass*) man->getPassById(PassId::InterpretationPass); - } else { - pass = new InterpretationPass(man); - pass->run(); - } + InterpretationPass* pass = new InterpretationPass(man); + pass->run(); - Symbol symbolY = man->root->findFunction("main")->__entry->findSymbol("y"); + CodeScope* scopeEntry = man->root->findFunction("main")->getEntryScope(); + Symbol symbolY{scopeEntry->getSymbol("y"), scopeEntry}; InterpretationData& dataSymbolY = Attachments::get(symbolY); - ASSERT_EQ(ANY, dataSymbolY.resolution); + ASSERT_EQ(CMPL_ONLY, dataSymbolY.resolution); ASSERT_EQ(IF_INTERPRET_CONDITION, dataSymbolY.op); } TEST(Interpretation, Compilation_StatementIF_InterpretCondition_1){ PassManager* man = PassManager::prepareForCode( R"Code( main = function(x:: int):: int; entry { comm= "inc":: string; interpretation(force). - y = if (comm == "inc") {x+1} else {x}. + y = if (comm == "inc")::int {x+1} else {x}. y } )Code" ); man->runWithoutCompilation(); InterpretationPass* pass; if (man->isPassRegistered(PassId::InterpretationPass)){ pass = (InterpretationPass*) man->getPassById(PassId::InterpretationPass); } else { pass = new InterpretationPass(man); pass->run(); } int (*main)(int) = (int (*)(int))man->run(); int result = main(1); ASSERT_EQ(2, result); } TEST(Interpretation, Compilation_StatementFOLD_INTERPRET_INPUT_1){ PassManager* man = PassManager::prepareForCode( R"Code( main = function(x:: int):: int; entry { commands = ["inc", "double", "dec"]:: [string]; interpretation(force). loop fold(commands->comm::string, x->operand):: int{ switch(comm)::int case ("inc"){ operand + 1 } case ("dec"){ operand - 1 } case ("double"){ operand * 2 } } } )Code" ); man->runWithoutCompilation(); InterpretationPass* pass; if (man->isPassRegistered(PassId::InterpretationPass)){ pass = (InterpretationPass*) man->getPassById(PassId::InterpretationPass); } else { pass = new InterpretationPass(man); pass->run(); } + const ManagedFnPtr& funcMain = man->root->findFunction("main"); + InterpretationData& dataBody = Attachments::get(funcMain); + ASSERT_EQ(FOLD_INTERPRET_INPUT, dataBody.op); + int (*main)(int) = (int (*)(int))man->run(); int result = main(10); ASSERT_EQ(21, result); } TEST(Interpretation, StatementCall_RecursionNo_1){ PassManager* man = PassManager::prepareForCode( 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(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()}; + Symbol symbCallEv{{0, VERSION_NONE}, exprLoop.blocks.front()}; InterpretationData dataCallEv = Attachments::get(symbCallEv); ASSERT_EQ(CMPL_ONLY, dataCallEv.resolution); ASSERT_EQ(CALL_INTERPRET_PARTIAL, dataCallEv.op); } -TEST(Interpretation, PartialIntr_2){ +TEST(Interpretation, Compilation_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} + case ("inc") {argument + 1} + case ("dec") {argument - 1} + case ("double") {argument * 2} + case default {argument} } main = function::int; entry { commands= ["inc", "double", "dec"]:: [string]; interpretation(force). loop fold(commands->comm::string, 10->operand):: int{ evaluate(operand, comm) } } )Code" ); - InterpretationPass* pass = new InterpretationPass(man); - pass->run(); + man->runWithoutCompilation(); + if (!man->isPassRegistered(PassId::InterpretationPass)){ + InterpretationPass* pass = new InterpretationPass(man); + pass->run(); + } int (*main)() = (int (*)())man->run(); int result = main(); ASSERT_EQ(21, result); } -//TOTEST call indirect recursion(w/o tags) -//TASK implement and test Loop Inf (fix acc types in coco grammar) +TEST(Interpretation, PartialIntr_3){ + PassManager* man = PassManager::prepareForCode( +R"Code( + Command= type variant (INC, DEC, DOUBLE). + evaluate= function(argument:: num, code:: Command; 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]:: [Command]; interpretation(force). + loop fold(commands->comm::Command, 10->operand):: int{ + evaluate(operand, comm) + } + } +)Code" ); + man->runWithoutCompilation(); + if (!man->isPassRegistered(PassId::InterpretationPass)){ + InterpretationPass* pass = new InterpretationPass(man); + pass->run(); + } + int (*main)() = (int (*)())man->run(); + int result = main(); + + ASSERT_EQ(21, result); +} + +//TOTEST call indirect recursion(w/o tags) +//TASK implement and test Loop Inf (fix acc types in coco grammar) \ No newline at end of file diff --git a/cpp/tests/main.cpp b/cpp/tests/main.cpp index 66078a2..2385205 100644 --- a/cpp/tests/main.cpp +++ b/cpp/tests/main.cpp @@ -1,136 +1,15 @@ #include "utils.h" #include using namespace std; using namespace xreate; int main(int argc, char **argv) { testing::GTEST_FLAG(color) = "yes"; string testsTemplate = Config::get("tests.template"); string testsFilter = Config::get(string("tests.templates.") + testsTemplate); testing::GTEST_FLAG(filter) = testsFilter; testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); } - -//TODO adopt useful tests - -//void testParser_1() -//{ -// shared_ptr scanner(new Scanner(L"scripts/input.xreate")); -// shared_ptr parser(new Parser(scanner.get())); -// parser->Parse(); -// flush(cout); - -// AST& root = parser->root; -// LLVMLayer l(&root); - -// root.compile(l); -// root.run(l); -//} - -//void testClasp2() -//{ -// shared_ptr scanner(new Scanner(L"scripts/input.xreate")); -// shared_ptr parser(new Parser(scanner.get())); -// parser->Parse(); -// flush(cout); - -// if (parser->errors->count) -// { -// cout << "Found " << parser->errors->count << " errors. Stop" << endl; -// exit(1); -// } - -// AST& root = parser->root; -// ClaspLayer clasp; - -// /* -// FunctionTagsPass(root).run(clasp); -// RulesPass(root).run(clasp); - -// CFGPass(&clasp).run(); - -// clasp.1 -// run(); -// */ -//} - -//void testUnsafeCode1() -//{ -// shared_ptr scanner(new Scanner(L"scripts/cases/bugs-code.xreate")); -// shared_ptr parser(new Parser(scanner.get())); -// parser->Parse(); -// flush(cout); - -// if (parser->errors->count) -// { -// cout << "Found " << parser->errors->count << " errors. Stop" << endl; -// exit(1); -// } - -// AST& root = parser->root; -// ClaspLayer clasp; - -// /* -// FunctionTagsPass(root).run(clasp); -// RulesPass(root).run(clasp); - -// CFGPass(&clasp).run(); -// //clasp.addRule(":- call(X, Y), tag(Y, unsafe), not tag(X, unsafe), function(X), function(Y)."); - -// clasp.run(); -// */ -//} - -//void test_DFG_1() -//{ -// shared_ptr scanner(new Scanner(L"scripts/input.xreate")); -// shared_ptr parser(new Parser(scanner.get())); -// parser->Parse(); -// flush(cout); - -// if (parser->errors->count) -// { -// cout << "Found " << parser->errors->count << " errors. Stop" << endl; -// exit(1); -// } - -// PassManager m; -// m.clasp = new ClaspLayer(); - -// m.llvm = new LLVMLayer(&parser->root); -// m.root = & parser->root; -// m.clasp->ast = m.root; - -// m.registerPass(new DFAPass(&m)); -// m.run(); - -// m.clasp->run(); -// m.root->compile(*m.llvm); -// m.root->run(*m.llvm); -//} - -//void test_Xml_1() -//{ -// shared_ptr scanner(new Scanner(L"scripts/input.xreate")); -// shared_ptr parser(new Parser(scanner.get())); -// parser->Parse(); -// flush(cout); - -// if (parser->errors->count) -// { -// cout << "Found " << parser->errors->count << " errors. Stop" << endl; -// exit(1); -// } - -// PassManager m; -// m.root = & parser->root; -// m.clasp = new ClaspLayer(); -// m.clasp->ast = m.root; -// m.llvm = new LLVMLayer(&parser->root); - -// m.registerPass(new DFAPass(&m)); -// m.run(); -//} diff --git a/cpp/tests/supplemental/versions-algorithm-data_dependency.cpp b/cpp/tests/supplemental/versions-algorithm-data_dependency.cpp index 59ae20f..7a4612d 100644 --- a/cpp/tests/supplemental/versions-algorithm-data_dependency.cpp +++ b/cpp/tests/supplemental/versions-algorithm-data_dependency.cpp @@ -1,260 +1,296 @@ /* * File: algorithm-data_dependency * Date: Dec 23, 2016 * Author: pgess */ #include #include #include #include #include "gtest/gtest.h" #include #include const int V_NOVERSION = -2; const int V_ENDOFLIFE = -1; struct Symbol { std::string name; int version; Symbol getNextVersion() const{ return Symbol{name, version+1}; } }; namespace std { template<> struct hash { typedef Symbol argument_type; typedef std::size_t result_type; result_type operator()(argument_type const& s) const { result_type const h1 ( std::hash()(s.name) ); return h1 ^ (s.version << 1); // or use boost::hash_combine } }; template<> struct equal_to { typedef Symbol argument_type; bool operator()(const argument_type& __x, const argument_type& __y) const { return __x.name == __y.name && __x.version == __y.version; } }; } //Ограничения: // - точно знаем следующую версию на этапе декл. (C.NV.1) class DDSolver{ public: void l1_applyLowerBound(const Symbol& left, const std::initializer_list& dependencies){ for (Symbol right: dependencies){ //lower bound: __infs.emplace(left, right); __sups.emplace(right, left); } } void l1_applyOwnUpperBound(const Symbol& left){ //own upper bound: //C.NV.1 __infs.emplace(left.getNextVersion(), left); __sups.emplace(left, left.getNextVersion()); } void l1_applyDependentUpperBound(const Symbol& left, const std::initializer_list& dependencies){ // additionally apply dependent upper bound for (Symbol right: dependencies){ auto right2 = right.getNextVersion(); __infs.emplace(right2, left); __sups.emplace(left, right2); } } void addVariable(const Symbol& left, const std::initializer_list& dependencies){ l1_applyLowerBound(left, dependencies); l1_applyOwnUpperBound(left); //initialization upper bound l1_applyDependentUpperBound(left, dependencies); } //TODO assert: only aliases allowed void addAlias(const Symbol& left, const std::initializer_list& dependencies){ l1_applyLowerBound(left, dependencies); l1_applyOwnUpperBound(left); //lifetime upper bound l1_applyDependentUpperBound(left.getNextVersion(), dependencies); } bool checkCyclicComponent(const Symbol& s, std::unordered_set& symbolsVisited, std::unordered_set& symbolsSups){ if (symbolsVisited.count(s)) return false; symbolsVisited.insert(s); symbolsSups.insert(s); auto rangeInf = __infs.equal_range(s); if (__infs.count(s)) for (auto sInf = rangeInf.first; sInf != rangeInf.second; ++sInf){ if (symbolsSups.count(sInf->second)) { __flagCycle = std::make_pair(sInf->second, s); return true; } if(checkCyclicComponent(sInf->second, symbolsVisited, symbolsSups)) return true; } symbolsSups.erase(s); return false; } bool checkCyclicFull(){ std::unordered_set symbolsVisited, symbolsSups; std::unordered_multimap::iterator s; for (s = __infs.begin(); s != __infs.end(); ++s){ if(checkCyclicComponent(s->first, symbolsVisited, symbolsSups)) return true; } return false; } bool validate(){ return !checkCyclicFull(); } void solve(){ std::unordered_set binEnabled, binFrontier; //seed for (auto edge: __sups){ if (! __infs.count(edge.first)){ binEnabled.insert(edge.first); binFrontier.insert(edge.first); } } while (binFrontier.size()){ const Symbol& node= *binFrontier.begin(); //print node: std:: printf("put (%s, %d)\n", node.name.c_str(), node.version); auto rangeSups = __sups.equal_range(node); for(auto sup=rangeSups.first; sup != rangeSups.second; ++sup){ bool flagEnabled = true; auto rangeInfs = __infs.equal_range(sup->second); for (auto inf=rangeInfs.first; inf != rangeInfs.second; ++inf){ if (!binEnabled.count(inf->second)){ flagEnabled = false; break; } } if (flagEnabled){ binEnabled.insert(sup->second); binFrontier.insert(sup->second); } } binFrontier.erase(node); } } void solve2(Symbol nodeEntry, std::unordered_set& binPreviousNodes, std::unordered_set& binEnabledNodes){ binPreviousNodes.insert(nodeEntry); auto rangeChilds = __infs.equal_range(nodeEntry); for(auto node=rangeChilds.first; node != rangeChilds.second; ++node){ if (binEnabledNodes.count(node->second)) continue; auto nodeError = binPreviousNodes.find(node->second); if (nodeError != binPreviousNodes.end()){ std:: printf("(%s, %d) - (%s, %d)", nodeError->name.c_str(), nodeError->version, node->second.name.c_str(), node->second.version); - assert(true); + assert(false); } solve2(node->second, binPreviousNodes, binEnabledNodes); } std:: printf("put (%s, %d)\n", nodeEntry.name.c_str(), nodeEntry.version); binEnabledNodes.insert(nodeEntry); binPreviousNodes.erase(nodeEntry); // auto rangeParents = __sups.equal_range(nodeEntry); // for(auto node=rangeParents.first; node != rangeParents.second; ++node){ // std::unordered_set binEmpty; // solve2(node->second, binEmpty, binEnabledNodes); // } } void __debug_printGraph(){ for (auto edge: __infs){ std:: printf("(%s, %d) <- (%s, %d) \n", edge.second.name.c_str(), edge.second.version, edge.first.name.c_str(), edge.first.version); } } private: std::unordered_multimap __sups; std::unordered_multimap __infs; public: std::pair __flagCycle; }; -//TEST(Datadependency, test1){ -// DDSolver solver; -// -// solver.addAlias(Symbol{"c", V_NOVERSION}, {Symbol{"a", 0}}); -// solver.addVariable(Symbol{"a", 1}, {Symbol{"b", 0}}); -// solver.addVariable(Symbol{"b", 1}, {Symbol{"c", V_NOVERSION}}); -// -// solver.__debug_printGraph(); -// -// ASSERT_FALSE(solver.validate()); -// -// std:: printf("(%s, %d) - (%s, %d)", -// solver.__flagCycle.first.name.c_str(), solver.__flagCycle.first.version, -// solver.__flagCycle.second.name.c_str(), solver.__flagCycle.second.version); -//} - -//TEST(Datadependency, test2){ -// DDSolver solver; -// -// solver.addVariable(Symbol{"c", V_NOVERSION}, {Symbol{"a", 0}}); -// solver.addVariable(Symbol{"a", 1}, {Symbol{"b", 0}}); -// solver.addVariable(Symbol{"b", 1}, {Symbol{"c", V_NOVERSION}}); -// -// ASSERT_TRUE(solver.validate()); -// -// solver.solve(); -//} +TEST(Datadependency, test1){ + DDSolver solver; + + solver.addAlias(Symbol{"c", V_NOVERSION}, {Symbol{"a", 0}}); + solver.addVariable(Symbol{"a", 1}, {Symbol{"b", 0}}); + solver.addVariable(Symbol{"b", 1}, {Symbol{"c", V_NOVERSION}}); + + solver.__debug_printGraph(); + + ASSERT_FALSE(solver.validate()); + + std:: printf("(%s, %d) - (%s, %d)", + solver.__flagCycle.first.name.c_str(), solver.__flagCycle.first.version, + solver.__flagCycle.second.name.c_str(), solver.__flagCycle.second.version); +} + +TEST(Datadependency, test2){ + DDSolver solver; + + solver.addVariable(Symbol{"c", V_NOVERSION}, {Symbol{"a", 0}}); + solver.addVariable(Symbol{"a", 1}, {Symbol{"b", 0}}); + solver.addVariable(Symbol{"b", 1}, {Symbol{"c", V_NOVERSION}}); + + ASSERT_TRUE(solver.validate()); + + solver.solve(); +} TEST(Datadependency, test3){ DDSolver solver; solver.addVariable(Symbol{"c", V_NOVERSION}, {Symbol{"a", 0}}); solver.addVariable(Symbol{"a", 1}, {Symbol{"b", 0}}); solver.addVariable(Symbol{"b", 1}, {Symbol{"c", V_NOVERSION}}); std::unordered_set binPreviousNodes, binEnabledNodes; solver.solve2(Symbol{"b", 1}, binPreviousNodes, binEnabledNodes); ASSERT_TRUE(true); +} + +TEST(Datadependency, test4){ + DDSolver solver; + + solver.addVariable(Symbol{"c", V_NOVERSION}, {Symbol{"a", 0}}); + solver.addVariable(Symbol{"a", 1}, {Symbol{"b", 0}}); + solver.addVariable(Symbol{"b", 1}, {Symbol{"c", V_NOVERSION}}); + + std::unordered_set binPreviousNodes, binEnabledNodes; + solver.solve2(Symbol{"b", 1}, binPreviousNodes, binEnabledNodes); + ASSERT_TRUE(true); +} + +TEST(Datadependency, test5){ + DDSolver solver; + + solver.addAlias(Symbol{"b", V_NOVERSION}, {Symbol{"a", 0}}); + solver.addVariable(Symbol{"a", 1}, {Symbol{"b", V_NOVERSION}}); + + std:: printf("(%s, %d) - (%s, %d)", + solver.__flagCycle.first.name.c_str(), solver.__flagCycle.first.version, + solver.__flagCycle.second.name.c_str(), solver.__flagCycle.second.version); + + ASSERT_TRUE(solver.validate()); +} + +TEST(Datadependency, test6){ + DDSolver solver; + + solver.addVariable(Symbol{"a", 1}, {Symbol{"a", 0}}); + + std::unordered_set binPreviousNodes, binEnabledNodes; + solver.solve2(Symbol{"a", 1}, binPreviousNodes, binEnabledNodes); + + ASSERT_TRUE(solver.validate()); } \ No newline at end of file diff --git a/cpp/tests/testClangAPI.h b/cpp/tests/testClangAPI.h deleted file mode 100644 index aab7ee5..0000000 --- a/cpp/tests/testClangAPI.h +++ /dev/null @@ -1,9 +0,0 @@ -// -// Created by pgess on 4/16/15. -// - -#ifndef XREATE_TESTCLANGAPI_H -#define XREATE_TESTCLANGAPI_H - -void testClang1(); -#endif //XREATE_TESTCLANGAPI_H diff --git a/cpp/tests/types.cpp b/cpp/tests/types.cpp index d90a673..b9d3e96 100644 --- a/cpp/tests/types.cpp +++ b/cpp/tests/types.cpp @@ -1,167 +1,163 @@ /* * 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); + 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 symb = body->findSymbol("childrenRaw"); - - const TypeAnnotation& t = CodeScope::findDeclaration(symb).type; + const TypeAnnotation& t = body->getDeclaration(body->getSymbol("childrenRaw")).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 TypeAnnotation& t = body->getDeclaration(body->getSymbol("tree")).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()->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 {GREEN} \n" "main = function:: int; entry { \n" " switch(test()):: int \n" - " case GREEN {0} \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/scripts/dsl/regexps.xreate b/scripts/dsl/regexps.xreate index b02d3e1..684c99b 100644 --- a/scripts/dsl/regexps.xreate +++ b/scripts/dsl/regexps.xreate @@ -1,81 +1,76 @@ =========================== DATA -patternAB = { - sequence: [ - {zeroOrMore: 'a'}, - {text: 'b'}, - ] -} - -mod sequence{ -[ - mod zeroOrMore (text("a")), - matcher text("b") -] -) - + +patternAB = [Sequence, + [[ZeroOrMore, "a"], + [Text, "b"]]]. ========================== HANDLERS - case matcher:: mod sequence -match = function(text, matcher) { - loop fold(node-> matcher, 0->pos){ - n = match(matcher, mid(text, pos, length(text))).// <-- every time length? +Matcher = type variant (Sequence, ZeroOrMore, Text) + +matchSequence = function(text::string, sequence::undef):: int{ + textLength = length(text):: int. + + loop fold(sequence-> matcher:: undef, 0->pos){ + n = match(mid(text, pos, textLength), matcher). - if (pos == pos_FAIL || n == pos_FAIL){ - pos_FAIL:: break + if (n == pos_FAIL:: break){ + pos + } else { pos+n } } } - case matcher:: mod zeroOrMore (Dereferenced) -match= function(text, matcher){ - matcherChild = matcher:: Dereferenced. //<--- extract child(unification) +matchZeroOrMore= function(text::string, matcher::string):: int{ + textLength = length(text):: int. loop fold inf(0->pos, n==pos_FAIL){ //<--- infinite loop? - n = match(matcherChild, mid(text, pos, length(text))). + n = match(matcherChild, mid(text, pos, textLength)). if (n == pos_FAIL:: break){ pos } else { pos+n } } } - case matcher:: matcher text -match = function(text, matcher) { - pattern = matcher:: string. +matchText = function(text::string, matcher::string):: int { + textLength = length(text):: int. - if (length(text)>0 && - length(pattern) <= length(text) && - mid(text, 0, length(pattern)) == pattern) + if (length(matcher) <= textLength, mid(text, 0, length(matcher)) == matcher) { - length(pattern); + textLength; } else { pos_FAIL; } } -match = function(text::string, pattern::string)::string{ - n= match(pattern, text). - - if (n != pos_FAIL) +match = function(text::string, pattern::undef)::string{ + + n = switch (pattern[0]) :: int + case (Sequence) {matchSequence(text, pattern[1])} + case (ZeroOrMore) {matchZeroOrMore(text, pattern[1])} + case (Text) {matchText(text, pattern[1])} + case default {pos_FAIL} + + if (n != pos_FAIL) {mid(text, 0, n)} else {text_FAIL} } ================================= CLIENT test = function(){ match(patternAB, "aaaaab"). match(patternAB, "baaaaa"). } diff --git a/scripts/testspass/Containers_Implementation_LinkedList1.xreate b/scripts/testspass/Containers_Implementation_LinkedList1.xreate index 2966ef4..7a7a039 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 = "scripts/testspass/Containers_Implementation_LinkedList1-data.xml" :: string. docRaw = xmlParseFile(filename) :: xmlDocPtr. tree= xmlDocGetRootElement(docRaw) :: xmlNodePtr. - childrenRaw = tree["children"]:: [xmlNodePtr]; containers:linkedlist(next, null). + childrenRaw = tree["children"]:: [xmlNodePtr]; linkedlist(next, null). size = loop fold(childrenRaw->child:: xmlNodePtr, 0->count):: int { count +1::int }. size }